单个变量中允许有多少个指针(*
?]
让我们考虑以下示例。
int a = 10;
int *p = &a;
类似地我们可以拥有
int **q = &p;
int ***r = &q;
依此类推。
例如,
int ****************zz;
C
标准指定下限:
5.2.4.1 Translation limits
276该实现应能够翻译和执行至少一个程序,该程序包含以下每个限制的至少一个实例:[...]
279 — 12个指针,数组和函数声明符(以任何组合)修改一个声明中的算术,结构,联合或无效类型
上限是特定于实现的。
请注意,这里有两个可能的问题:在C类型中可以实现多少级指针间接寻址,以及可以在单个声明符中填充多少级指针间接寻址。
我想指出的是,使用模板元编程可以产生带有任意数量*的类型。我忘记了我到底在做什么,但是有人建议我可以使用recursive
[Rule 17.5]的2004 MISRA C标准”禁止超过2级的指针间接寻址。
没有像[[真实限制
这样的东西,但存在限制。所有指针都是通常存储在堆栈非堆查看此程序:
实际上,C程序通常使用无限指针间接寻址。一两个静态级别很常见。三重间接寻址很少见。但是无限是非常普遍的。
无限指针间接是借助结构来实现的,当然,不是借助直接声明符实现的,这是不可能的。并且需要一个结构,以便您可以在此结构可以终止的不同级别上包含其他数据。
struct list { struct list *next; ... };
现在您可以拥有list->next->next->next->...->next
。这实际上只是多个指针的间接寻址:*(*(..(*(*(*list).next).next).next...).next).next
。当.next
是结构的第一个成员时,基本上是noop,因此我们可以将其想象为***..***ptr
。
对此实际上没有限制,因为可以使用循环而不是像这样的巨大表达式来遍历链接,此外,可以轻松地使结构成为圆形。
因此,换句话说,链表可能是添加另一种间接寻址级别来解决问题的最终示例,因为您在每次推送操作中都会动态地执行此操作。 :)
理论上:
您可以根据需要具有任意数量的间接级别。
实际上:
当然,不会消耗内存的任何事物都是无限的,由于主机环境上的可用资源会受到限制。因此,实际上对实现可以支持的内容有最大的限制,并且实现应适当记录它。因此,在所有此类工件中,标准均未指定最大限制,但确实指定了下限制。
这里是参考:
C99标准5.2.4.1翻译限制:
— 12个指针,数组和函数声明符(以任何组合)修改一个声明中的算术,结构,联合或无效类型。
这指定每个实现必须支持的下限。请注意,该脚注中的标准还说:
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:解析器堆栈溢出,程序太复杂
gcc(Ubuntu),100k + *
不会崩溃!我想硬件是这里的极限。
(仅通过变量声明进行测试)
没有限制,请参见示例here。
答案取决于您所指的“指针级别”。如果您的意思是“一个声明中可以有多少个间接级别?”答案是“至少12”。
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 */
如果您的意思是“在程序难以阅读之前可以使用多少级指针,”这是个问题,但是有一个限制。通常有两个间接级别(一个指向某物的指针)。除此之外,更难考虑。除非替代方案会更糟,否则不要这样做。
如果您的意思是“在运行时可以有多少个级别的指针间接,”没有限制。这一点对于循环列表尤其重要,在循环列表中,每个节点都指向下一个节点。您的程序可以永远跟随指针。
实际上,指向函数的指针甚至更有趣。
#include <cstdio>
typedef void (*FuncType)();
static void Print() { std::printf("%s", "Hello, World!\n"); }
int main() {
FuncType const ft = &Print;
ft();
(*ft)();
(**ft)();
/* ... */
}
如图here所示:
你好,世界!你好,世界!你好,世界!
而且它不涉及任何运行时开销,因此您可能可以将它们尽可能多地堆叠起来,直到编译器在文件上阻塞为止。
没有无限制。指针是一块内存,其内容是一个地址。如您所说
int a = 10;
int *p = &a;
指向指针的指针也是一个变量,其中包含另一个指针的地址。
int **q = &p;
这里q
是指向保存p
地址的指针,该地址已经保存a
的地址。
关于指针的指针没有什么特别的特殊之处。因此,拥有另一个指针地址的编织链没有限制。即
int **************************************************************************z;
被允许。
每个C ++开发人员都应该听说过(著名的Three star programmer] >>
而且似乎确实确实存在一些不可思议的“指针障碍”
C2语录:
三星级程序员
C程序员的评分系统。指针的间接性越强(即变量前的“ *”越多),您的声誉就越高。没有明星的C程序员实际上是不存在的,因为实际上所有非平凡的程序都需要使用指针。大多数是一星级程序员。在过去(嗯,我还很年轻,所以至少对我来说这些看起来像过去),偶尔会发现由三星级程序员编写的一段代码,并敬畏地颤抖。甚至有人声称,他们在不止一层的间接访问中看到了包含函数指针的三星级代码。对我来说,听起来像不明飞行物一样真实。