我们可以拥有多少级指针?

问题描述 投票:438回答:14

单个变量中允许有多少个指针(*?]

让我们考虑以下示例。

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

类似地我们可以拥有

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

依此类推。

例如,

int ****************zz;
c++ c pointers language-lawyer limit
14个回答
397
投票

C标准指定下限:

5.2.4.1 Translation limits

276该实现应能够翻译和执行至少一个程序,该程序包含以下每个限制的至少一个实例:[...]

279 — 12个指针,数组和函数声明符(以任何组合)修改一个声明中的算术,结构,联合或无效类型

上限是特定于实现的。


13
投票

请注意,这里有两个可能的问题:在C类型中可以实现多少级指针间接寻址,以及可以在单个声明符中填充多少级指针间接寻址。


4
投票

我想指出的是,使用模板元编程可以产生带有任意数量*的类型。我忘记了我到底在做什么,但是有人建议我可以使用recursive


3
投票

[Rule 17.5]的2004 MISRA C标准”禁止超过2级的指针间接寻址。


1
投票

没有像[[真实限制

这样的东西,但存在限制。所有指针都是通常存储在堆栈非堆

0
投票
相当低。如果将其存储在堆中,则限制要高得多。

查看此程序:


153
投票

实际上,C程序通常使用无限指针间接寻址。一两个静态级别很常见。三重间接寻址很少见。但是无限是非常普遍的。

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

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

现在您可以拥有list->next->next->next->...->next。这实际上只是多个指针的间接寻址:*(*(..(*(*(*list).next).next).next...).next).next。当.next是结构的第一个成员时,基本上是noop,因此我们可以将其想象为***..***ptr

对此实际上没有限制,因为可以使用循环而不是像这样的巨大表达式来遍历链接,此外,可以轻松地使结构成为圆形。

因此,换句话说,链表可能是添加另一种间接寻址级别来解决问题的最终示例,因为您在每次推送操作中都会动态地执行此操作。 :)


82
投票

理论上:

您可以根据需要具有任意数量的间接级别。

实际上:

当然,不会消耗内存的任何事物都是无限的,由于主机环境上的可用资源会受到限制。因此,实际上对实现可以支持的内容有最大的限制,并且实现应适当记录它。因此,在所有此类工件中,标准均未指定最大限制,但确实指定了下限制。

这里是参考:

C99标准5.2.4.1翻译限制:

— 12个指针,数组和函数声明符(以任何组合)修改一个声明中的算术,结构,联合或无效类型。

这指定每个实现必须支持的下限。请注意,该脚注中的标准还说:

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


76
投票

正如人们所说的,“理论上没有限制。但是,出于兴趣,我在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;
}

63
投票

听起来很有趣。

  • Visual Studio 2010(在Windows 7上,在出现此错误之前,您可以具有1011个级别:

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

  • gcc(Ubuntu),100k + *不会崩溃!我想硬件是这里的极限。

(仅通过变量声明进行测试)


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 */

如果您的意思是“在程序难以阅读之前可以使用多少级指针,”这是个问题,但是有一个限制。通常有两个间接级别(一个指向某物的指针)。除此之外,更难考虑。除非替代方案会更糟,否则不要这样做。

如果您的意思是“在运行时可以有多少个级别的指针间接,”没有限制。这一点对于循环列表尤其重要,在循环列表中,每个节点都指向下一个节点。您的程序可以永远跟随指针。


24
投票

实际上,指向函数的指针甚至更有趣。

#include <cstdio>

typedef void (*FuncType)();

static void Print() { std::printf("%s", "Hello, World!\n"); }

int main() {
  FuncType const ft = &Print;
  ft();
  (*ft)();
  (**ft)();
  /* ... */
}

如图here所示:

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

而且它不涉及任何运行时开销,因此您可能可以将它们尽可能多地堆叠起来,直到编译器在文件上阻塞为止。


20
投票

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

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

指向指针的指针也是一个变量,其中包含另一个指针的地址。

int **q = &p;

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

关于指针的指针没有什么特别的特殊之处。因此,拥有另一个指针地址的编织链没有限制。即

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

被允许。


16
投票

每个C ++开发人员都应该听说过(著名的Three star programmer] >>

而且似乎确实确实存在一些不可思议的“指针障碍”

C2语录:

三星级程序员

C程序员的评分系统。指针的间接性越强(即变量前的“ *”越多),您的声誉就越高。没有明星的C程序员实际上是不存在的,因为实际上所有非平凡的程序都需要使用指针。大多数是一星级程序员。在过去(嗯,我还很年轻,所以至少对我来说这些看起来像过去),偶尔会发现由三星级程序员编写的一段代码,并敬畏地颤抖。甚至有人声称,他们在不止一层的间接访问中看到了包含函数指针的三星级代码。对我来说,听起来像不明飞行物一样真实。

© www.soinside.com 2019 - 2024. All rights reserved.