我们可以有多less级别的指针?

在一个variables中允许多less个指针( * )?

我们来看下面的例子。

 int a = 10; int *p = &a; 

同样我们可以有

 int **q = &p; int ***r = &q; 

等等。

例如,

 int ****************zz; 

C标准规定了下限:

5.2.4.1翻译限制

276实施应能够翻译和执行至less一个包含以下每个限制的至less一个实例的程序:

指针,数组和函数声明符(以任何组合方式)修改声明中的算术,结构,联合或无效types

上限是具体实现。

实际上,C程序通常使用无限指针间接。 一个或两个静态水平是常见的。 三重间接是罕见的。 但无限是非常普遍的。

无限的指针间接是通过struct的帮助来实现的,当然不是直接声明的,这是不可能的。 并且需要一个结构体,以便可以在可以终止的不同级别上包含此结构体中的其他数据。

 struct list { struct list *next; ... }; 

现在你可以有list->next->next->next->...->next 。 这只是多指针间接指针: *(*(..(*(*(*list).next).next).next...).next).next 。 而.next基本上是noop,因为它是结构的第一个成员,所以我们可以把它想象成***..***ptr

对此没有限制,因为链接可以循环遍历,而不是像这样的巨大expression式,而且结构可以很容易地制成圆形。

因此,换句话说,链表可能是增加另一个间接级来解决问题的最终例子,因为每个推动操作都是dynamic的。 🙂

从理论上讲:

你可以拥有任意数量的间接指针。

几乎:

当然,没有任何消耗内存的东西可以是不确定的,由于主机环境上可用的资源,会有限制。 所以实际上对于实现能够支持什么是最大的限制,并且实现应该适当地logging它。 所以在所有这些工件中,标准没有指定最大限制,但是它确定了下限。

这里是参考:

C99标准5.2.4.1翻译限制:

– 12个指针,数组和函数声明符(以任何组合方式)修改声明中的算术,结构,联合或无效types。

这指定了每个实现必须支持的下限。 请注意,在标准脚本中进一步说:

18)实施应尽可能避免强加固定的翻译限制。

正如人们所说,“理论上”没有限制。 但是,出于兴趣,我用g ++ 4.1.2来运行它,它的大小达到了20,000。 编译虽然很慢,所以我没有尝试更高。 所以我猜g ++也没有任何限制。 (尝试设置size = 10并查看ptr.cpp,如果它不是很明显。)

g++ create.cpp -o create ; ./create > ptr.cpp ; g++ ptr.cpp -o ptr ; ./ptr

create.cpp

 #include <iostream> int main() { const int size = 200; std::cout << "#include <iostream>\n\n"; std::cout << "int main()\n{\n"; std::cout << " int i0 = " << size << ";"; for (int i = 1; i < size; ++i) { std::cout << " int "; for (int j = 0; j < i; ++j) std::cout << "*"; std::cout << " i" << i << " = &i" << i-1 << ";\n"; } std::cout << " std::cout << "; for (int i = 1; i < size; ++i) std::cout << "*"; std::cout << "i" << size-1 << " << \"\\n\";\n"; std::cout << " return 0;\n}\n"; return 0; } 

听起来很有趣。

  • Visual Studio 2010(在Windows 7上),你可以有1011级别之前得到这个错误:

    致命错误C1026:parsing器堆栈溢出,程序太复杂

  • gcc(Ubuntu),100k + *没有崩溃! 我猜硬件是这里的限制。

(只用variables声明进行testing)

没有限制, 在这里查看示例。

答案取决于你所指的“指针级别”。 如果你的意思是“你可以在一个声明中有多less层次的间接性?” 答案是“至less12”。

 int i = 0; int *ip01 = & i; int **ip02 = & ip01; int ***ip03 = & ip02; int ****ip04 = & ip03; int *****ip05 = & ip04; int ******ip06 = & ip05; int *******ip07 = & ip06; int ********ip08 = & ip07; int *********ip09 = & ip08; int **********ip10 = & ip09; int ***********ip11 = & ip10; int ************ip12 = & ip11; ************ip12 = 1; /* i = 1 */ 

如果你的意思是“程序难读之前可以使用多less级别的指针”,这是一个有趣的问题,但是有一个限制。 有两个间接级别(指向某个指针的指针)是常见的。 除此之外,有一点难以轻易思考; 不要这样做,除非替代品会更糟。

如果你的意思是“你可以在运行时有多less级别的指针间接寻址”,那么没有限制。 这一点对于循环列表来说尤为重要,其中每个节点指向下一个节点。 你的程序可以永远遵循指针。

指针函数实际上更有趣。

 #include <cstdio> typedef void (*FuncType)(); static void Print() { std::printf("%s", "Hello, World!\n"); } int main() { FuncType const ft = &Print; ft(); (*ft)(); (**ft)(); /* ... */ } 

如这里所示,这给出:

你好,世界!
你好,世界!
你好,世界!

它不涉及任何运行时间的开销,所以你可以尽可能多地堆叠它们,直到你的编译器扼杀文件。

没有限制 。 指针是一块内存,其内容是一个地址。
如你所说

 int a = 10; int *p = &a; 

指向指针的指针也是一个包含另一个指针地址的variables。

 int **q = &p; 

这里q是指向保存p的地址的指针, p已经保存了a的地址。

指针指针没有特别的特殊之处。
所以对持有另一个指针的地址的连锁群没有限制。
即。

  int **************************************************************************z; 

被允许。

请注意,这里有两个可能的问题:我们可以在Ctypes中实现多less级别的指针间接寻址,以及我们可以将多less级别的指针间接寻址到一个单独的声明器中。

C标准允许对前者施加最大值(并给出最小值)。 但是这可以通过多个typedef声明来绕过:

 typedef int *type0; typedef type0 *type1; typedef type1 *type2; /* etc */ 

所以最终,这是一个实现问题,它涉及到C程序被拒绝之前可以有多大/多么复杂的想法,这是非常特定的编译器。

每个C ++开发者都应该听说(着名) 三星程序员

而且似乎真的有一些魔法“指针障碍”,必须被伪装

引用C2:

三星程序员

C程序员的评分系统。 你的指针越是间接的(即你的variables之前的“*”越多),你的声望就越高。 几乎没有明星的C程序员几乎不存在,因为几乎所有非平凡的程序都需要使用指针。 大多数是一星级程序员。 在旧时代(当然,我还年轻,所以这些对我来说至less看起来是旧时代的),偶尔会发现一个由三星级程序员完成的代码,并且惊愕起来。 有些人甚至声称他们已经看到三星级代码与涉及函数指针,在不止一个层面的间接。 听起来和UFO一样真实。

2004年MISRA C标准规则17.5禁止超过2级的指针间接。

没有像真正的限制这样的事情,但存在限制。 所有的指针都是variables,通常是堆栈而不是堆 。 堆栈通常很小(在一些链接过程中可以改变它的大小)。 所以可以说,你有4MB的堆栈,这是相当正常的大小。 让我们说我们有4个字节大小的指针(指针大小不一样,取决于架构,目标和编译器设置)。

在这种情况下, 4 MB / 4 b = 1024这样可能的最大数量将是1048576,但我们不应该忽略其他一些东西在堆栈中的事实。

然而,一些编译器可能有最大数量的指针链,但是限制是堆栈大小。 所以如果你在连接无穷大的时候增加堆栈的大小,并且让无限内存的机器运行操作系统来处理内存,那么你将拥有无限的指针链。

如果你使用int *ptr = new int; 并把你的指针放入堆中,这是不是很平常的方式限制将堆大小,而不是堆栈。

编辑只要意识到infinity / 2 = infinity 。 如果机器有更多的内存,所以指针大小增加。 所以如果记忆是无限的,指针的大小是无限的,那么这是坏消息… 🙂

我想指出的是,生成一个具有任意数量*的types是模板元编程可能发生的事情。 我完全忘记了自己在做什么,但是有人build议我可以通过recursion T *types来产生新的独特types,它们之间有一些元操作。

模板元编程是一个缓慢的陷入疯狂,所以没有必要为生成一个具有几千级间接types的借口。 例如,将peano整数映射到作为function语言的模板扩展上是一种方便的方法。

这取决于你存储指针的地方。 如果他们在堆栈,你有相当低的限制。 如果你把它存储在堆中,你的限制要高得多。

看这个节目:

 #include <iostream> const int CBlockSize = 1048576; int main() { int number = 0; int** ptr = new int*[CBlockSize]; ptr[0] = &number; for (int i = 1; i < CBlockSize; ++i) ptr[i] = reinterpret_cast<int *> (&ptr[i - 1]); for (int i = CBlockSize-1; i >= 0; --i) std::cout << i << " " << (int)ptr[i] << "->" << *ptr[i] << std::endl; return 0; } 

它创build了1M个指针,并在显示什么点容易注意到什么链到第一个可变number

BTW。 它使用92K的RAM,所以想象你可以走多远。