单个变量中允许多少指针(*
)?
让我们考虑以下示例。
int a = 10;
int *p = &a;
同样我们可以
int **q = &p;
int ***r = &q;
等等。
例如,
int ****************zz;
答案 0 :(得分:394)
C
标准指定下限:
5.2.4.1 Translation limits
276实施应能够翻译和执行至少一个包含以下每个限制的至少一个实例的程序:[...]
279 - 12个指针,数组和函数声明符(以任意组合)修改 声明中的算术,结构,联合或void类型
上限是特定于实现的。
答案 1 :(得分:149)
实际上,C程序通常使用无限指针间接。一个或两个静态级别很常见。三重间接是罕见的。但无限是非常普遍的。
无限指针间接是在结构的帮助下实现的,当然,不是直接声明器,这是不可能的。并且需要一个结构,以便您可以在此结构中包含可以终止的不同级别的其他数据。
struct list { struct list *next; ... };
现在你可以拥有list->next->next->next->...->next
。这实际上只是多个指针间接:*(*(..(*(*(*list).next).next).next...).next).next
。当.next
是结构的第一个成员时,它基本上是一个noop,因此我们可以将其想象为***..***ptr
。
对此没有任何限制,因为链接可以用循环遍历而不是像这样的巨型表达式,而且,结构可以很容易地变成圆形。
因此,换句话说,链接列表可能是添加另一个间接级别来解决问题的最终示例,因为您在每次推送操作时都会动态地执行此操作。 :)
答案 2 :(得分:80)
<强>理论上:强>
你可以拥有任意级别的间接。
<强>实际上:强>
当然,任何消耗内存的东西都是无限期的,由于主机环境上可用的资源会有限制。实际上,实现可以支持的最大限制是,实现应该适当地记录它。因此,在所有此类工件中,标准未指定最大限制,但它确实指定了下限。
以下是参考资料:
C99标准5.2.4.1翻译限制:
- 12个指针,数组和函数声明符(以任意组合)修改 声明中的算术,结构,联合或void类型。
这指定了每个实施必须支持的下限。请注意,在标准中,标准进一步说:
18)实施应尽可能避免强加固定的翻译限制。
答案 3 :(得分:74)
正如人们所言,“在理论上”没有限制。然而,出于兴趣,我使用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;
}
答案 4 :(得分:61)
检查听起来很有趣。
Visual Studio 2010(在Windows 7上),在获得此错误之前,您可以拥有1011个级别:
致命错误C1026:解析器堆栈溢出,程序太复杂
gcc(Ubuntu),100k + *
没有崩溃!我猜硬件是这里的限制。
(仅使用变量声明进行测试)
答案 5 :(得分:27)
没有限制,请查看示例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 */
如果你的意思是“在程序难以阅读之前你可以使用多少级别的指针”,这是一个品味问题,但是有一个限制。具有两个间接级别(指向某事物的指针)是常见的。除此之外,更容易思考;除非替代方案会更糟,否则不要这样做。
如果您的意思是“在运行时可以有多少级别的指针间接”,则没有限制。这一点对于循环列表尤为重要,其中每个节点都指向下一个节点。你的程序可以永远遵循指针。
答案 6 :(得分:23)
指向函数实际上更有趣。
#include <cstdio>
typedef void (*FuncType)();
static void Print() { std::printf("%s", "Hello, World!\n"); }
int main() {
FuncType const ft = &Print;
ft();
(*ft)();
(**ft)();
/* ... */
}
如图所示here,这给出了:
你好,世界!
你好,世界!
你好,世界!
并且它不涉及任何运行时开销,因此您可以根据需要堆叠它们......直到您的编译器对文件进行阻塞。
答案 7 :(得分:19)
无限制。指针是一块内存,其内容是一个地址。
如你所说
int a = 10;
int *p = &a;
指向指针的指针也是一个包含另一个指针地址的变量。
int **q = &p;
此处q
是指向保存p
地址的a
地址的指针。
指向指针的指针没有什么特别之处。
因此,持有另一个指针地址的poniters链没有限制
即
int **************************************************************************z;
是允许的。
答案 8 :(得分:13)
请注意,这里有两个可能的问题:我们可以在C类型中实现指针间接的多少级别,以及我们可以将多少级别的指针间接填充到单个声明器中。
C标准允许对前者施加最大值(并给出最小值)。但这可以通过多个typedef声明来规避:
typedef int *type0;
typedef type0 *type1;
typedef type1 *type2; /* etc */
所以最终,这是一个实现问题,它与C程序在被拒绝之前的大小/复杂程度有关,这是一个非常特定于编译器的程序。
答案 9 :(得分:13)
每个C ++开发人员都应该听说过(in)着名的Three star programmer
而且似乎确实存在一些必须伪装的魔法“指针障碍”
从C2引用:
三星级程序员
C程序员的评级系统。你的指针越间接(即你的变量之前的“*”越多),你的声誉就越高。没有明星的C程序员几乎不存在,因为几乎所有非平凡的程序都需要使用指针。大多数是一星级程序员。在过去(好吧,我很年轻,所以这些看起来至少对我而言),偶尔会找到一个由三星级程序员完成的代码并且敬畏地颤抖。 有些人甚至声称他们在不止一个间接层面上看到了涉及函数指针的三星代码。听起来像UFO一样真实。
答案 10 :(得分:3)
我想指出,生成一个具有任意数量*的类型是模板元编程可能发生的事情。我忘记了我在做什么,但有人建议我可以使用递归 T *类型生成新的不同类型,在它们之间进行某种元操作。
模板元编程是一种疯狂的缓慢下降,所以在生成具有几千级间接的类型时没有必要找借口。例如,将peano整数映射到模板扩展作为函数式语言,这只是一种方便的方法。
答案 11 :(得分:2)
2004 MISRA C标准的规则17.5 禁止超过2级指针间接。
答案 12 :(得分:1)
没有真实限制之类的东西,但存在限制。所有指针都是通常存储在堆栈 not heap 中的变量。堆栈通常很小(在某些链接期间可以更改其大小)。所以假设你有4MB堆栈,这是非常正常的大小。并且假设我们有4字节大小的指针(指针大小不同,具体取决于架构,目标和编译器设置)。
在这种情况下4 MB / 4 b = 1024
所以可能的最大数量是1048576,但是我们不应该忽略其他一些东西在堆栈中的事实。
但是有些编译器可能有最大数量的指针链,但限制是堆栈大小。因此,如果您在使用无穷大链接时增加堆栈大小并使机器具有无限内存,该内存运行操作系统以处理该内存,那么您将拥有无限的指针链。
如果使用int *ptr = new int;
并将指针放入堆中,那么通常的方式限制将是堆大小,而不是堆栈。
编辑只是意识到infinity / 2 = infinity
。如果机器有更多内存,那么指针大小会增加。因此,如果内存是无穷大而指针的大小是无穷大,那么这是坏消息... :)
答案 13 :(得分:0)
这取决于存储指针的位置。如果它们处于堆叠状态,则相当低限制。如果将它存储在堆中,则限制要高得多。
看看这个节目:
#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;
}
它会创建1M指针,并在显示中指出链接到第一个变量number
的内容很容易。
顺便说一句。它使用92K
的RAM,所以想象一下你可以走多远。