char *s[]和char (*s)[]之间有什么区别?

11

当我阅读有关C语言的书籍时,双重指针让我很困惑。

char s[5][5];
char *s[5];
char (*s)[5];

那么它们之间有什么区别呢?


6
可以访问http://cdecl.org/,或安装`cdecl`程序。 - Keith Thompson
第二个例子更清晰地写作char * s [5]; - aroth
4个回答

17

在C语言中,最好对声明进行清晰的表达,以使其更加直观。为此,您需要遵循右左阅读的约定。以下是其方法:

char *s[5];

你如何说出它?首先从变量名s的右侧开始,然后向左移动。所以你从说"s是一个/一"开始。在右边,你看到了一个[],然后说"s是一个数组..."。然后你再向左移动,看到了*,并说"s是一个指针数组。"这就是它的含义。它是一个由5个指针组成的数组。你可以在这个数组中存储不同的指针。

现在是另一个:

char (*s)[5];
你可以按照同样的逻辑开始。先说“s是一个”,然后看 () 中的内容,括号内的任何内容都比括号外的内容更接近 s。因此,*[] 更接近 s。现在你可以说,“s 是一个指针……” 然后走出括号看 []。接着继续说,“s是指向数组的指针”。这正是它的含义。这是一个指针,将指向数组的第一个元素。
现在按照同样的逻辑来猜测下一步会是什么:
int (*callme)(int a, int b)
int (*callme[10])(int a, int b)

提示:最后一个可以用来创建函数的查找表。

编辑:

正如评论中提到的,开头也有一个 char。我从来没有找到一种简单的方法来说明这个,但通常从上下文中很清楚。例如,在第一个示例中,char 定义了数组的类型,而在第二个示例中,它定义了指针。在我发布的练习中,int 定义了函数返回值的类型。通常,对于这样的定义,将恰好有一个未定义类型的项。这就是我找出类型所在的位置的方式。


你忘记了包含 charchar *s[5] 不是任何类型的 5 个“不同指针”的数组,它具体是一个指向 char 的 5 个指针的数组。 - Dour High Arch
那是真的。我应该提到那个。 - ssm
值得指出的是,声明中既不需要 a 也不需要 b(int, int) 就足够了。 - David C. Rankin
我收回之前的说法。在优先级和结合性方面如何解析(复杂)声明?表明这里确实适用优先级。 - user3920237
优先级和结合性确实是我们考虑规则的方式,但结果仍然取决于绑定发生的方式。我实际上非常喜欢这个词。 - ssm
显示剩余6条评论

8
  • 第一个是二维字符数组
  • 第二个是指向字符指针的数组
  • 第三个是指向字符数组的指针

值得一提的是,二维数组只是一个数组中包含了多个数组。 - Keith Thompson
1
或者是一个包含5个长度为5的字符数组的数组。 - David C. Rankin

3

虽然已经介绍了declaration,但也应该指出用法上的差异:

char s[5][5]; --

  • s 指向分配的内存区域(如果是全局的则在堆中,如果是局部的则在栈中),
  • 你可以安全地在 s[0][0].. s[4][4](或者在 s[0].. s[24])处写入高达25个字符值,
  • sizeof(s) == 25。

char *s[5]; --

  • s 指向分配的内存区域(如果是全局的则在堆中,如果是局部的则在栈中),
  • 你可以安全地在 s[0].. s[4] 处写入高达5个指针值,
  • sizeof(s) == 40 (*)。

char (*s)[5]; --

  • s并没有指向任何分配的内存——在这一点上,它只是一个未初始化的指针。
  • 您可以安全地在&s写入一个指针值。
  • sizeof(s) == 8 (*)。

(*) 注意:假设是64位架构。


3
1. char s[5][5]; 这里s是一个二维数组,有5行5列。在这5行5列中,您将保存字符类型的元素。
2. char *s[5]; s是一个一维数组,有5个元素,每个元素都是指向字符的指针。
3. char (*s)[5]; s在这里是一个指针而不是数组。s指向一组字符数组。例如:
char arr[5][5]; char(*s)[5]; s = arr;
s[0][0]将与arr[0][0]数组相同。

char(*s)[5]只是一个指针吗?char *schar (*s)[5]char (*s)[10]之间有什么区别吗? - storen
@storen 是的,char (*s)[5] 只是一个指针。但它是一个指向字符数组的指针。例如:1. char (*s)[5]; char arr[2][5]; s = arr; 这里 s 指向的是 arr 的第一行,长度为 5 的数组。如果你执行 s++,那么 s 就会指向 arr 的第二行。2. char *s; char arr[5]; s = arr; 这里 s 指向的是数组的首个元素,就是一个字符。如果你执行 s++,它就会指向下一个字符。 - dido
但我想知道编译器如何知道这个指针的类型是int,而另一个是char?当我们定义一个int * a类型时,编译器不仅存储值a,还存储a的类型,因此可能会有一些额外的内存开销。 - storen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接