方括号如何在 C 中工作?
Posted
技术标签:
【中文标题】方括号如何在 C 中工作?【英文标题】:How do square brackets work in C? 【发布时间】:2015-04-14 01:27:09 【问题描述】:我刚开始学习 C,我正在尝试了解基础知识。大量的教程会告诉你事情并让你相信它而没有任何真正的解释,而且我找不到人类可读的答案。
如下:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
int *a;
a = malloc(5 * sizeof(int));
a[2] = 4;
printf("%d\n", a[0]); // Prints 0
printf("%d\n", a[2]); // Prints 4
return 0;
我没有将int *a
明确声明为指向数组的指针,但如果我为其分配一些内存,我可以像我已经 将其声明为数组一样使用a
。用方括号声明一个指针只是我在下面所做的事情的快捷方式吗?方括号实际上是在做一些指针运算吗?
厚颜无耻的第二个问题
为什么内存地址分配给a
而不是*a
?
【问题讨论】:
声明带有方括号的指针只是我在下面所做的事情的快捷方式吗?方括号实际上是在做一些指针运算吗? 分别是可能和是。 为什么内存地址分配给a
而不是*a
?因为你写的是a = malloc(...)
,而不是*a = malloc(...)
。
从书中学习。 Here 是一些很棒的建议。
普通的书籍/教程通常会使这比需要的更难。 int *a;
声明了 int
类型的指针 a
目前没有指向任何地方(它本身有一个地址,但它不包含任何其他地址 - 即它是一个空指针)。 malloc
保留一块内存并将起始地址返回给该块。 a
现在包含新块的起始地址。 a[2]
与 *(a + 2)
相同,只是表示获取 at address a + 2
的值。 a
被声明为类型 int
知道 int
是 4-bytes
,因此它为内存中的第三个 int
提供了正确的地址。
感谢您的及时回复。我有一些这样的书。我想我应该多加注意。
说真的,问题是在你达到一定程度的理解之前,真正的答案是没有意义的,所以试图在曲折的细节中“理解基础”并不是很刚开始时很有效率。这就是为什么它们对你来说不是“人类可读的”。最好只是通过并接受一段时间的浅层理解,直到足够的练习使一切都开始点击。
【参考方案1】:
我没有将
int *a
明确声明为指向数组的指针,但如果我为它分配一些内存,我就可以使用a
,就像我已经 将它声明为一个数组一样。用方括号声明一个指针只是我在下面所做的事情的快捷方式吗?
类似,但不是。 int *a
将 a
声明为指向 int
的指针。 int b[5]
为 5 个 int
s 分配空间,将 b
声明为 constant pointer to 一个 array-of-int
int
引用(在大多数情况下可以被视为常量指向int
) 的指针,并将b
定义为指向已分配空间的指针。因此,int b[5]
比int *a
做得更多,这也意味着int *a
比int b[5]
更灵活。例如,您可以增加a
,但不能增加b
。
malloc
在堆上分配内存。 int b[5]
,如果是全局变量,将位于程序的数据段中(即,它实际上被编译成可执行文件)。如果是本地的,它将在堆栈上分配。同样,相似,但不同。
方括号实际上是在做一些指针运算吗?
在声明中,没有。当您使用指针变量时,是的:x[y]
与*(x + y)
相同。所以a[1]
和*(a + 1)
一样,和*(1 + a)
一样,又和1[a]
一样(但请不要使用最后一个)。
为什么内存地址分配给
a
而不是*a
?
厚脸皮问题的厚脸皮回答:因为你写的是a = ...
而不是*a = ...
。
编辑:John Bode 给出了一个有用的指针(呵呵):常量指针和数组引用不是一回事,尽管它们非常相似。一方面,sizeof(...)
会给出不同的结果。
【讨论】:
很好的解释。现在我看到了重要的一点,记住星号表示一种类型。int *
在声明中表示类型。 *a
in *a = ...
表示引用,意思是“写入a
指向的位置”,而不是“写入a
”,即a = ...
。
Nit - b
不是指针。它是一个数组表达式,在大多数情况下被转换为一个指针表达式。它不存储指针值。
@Amadan,1[x]
和a[1]
有什么区别?即使您的意思是1[a]
而不是1[x]
,我仍然会有同样的问题。
@ma11hew28 对,有一个错字。为了清楚起见,我将添加我所说的内容并更正它:“a[1]
与*(a + 1)
相同,与*(1 + a)
相同,又与1[a]
相同”。
【参考方案2】:
方括号实际上是在做一些指针运算吗?
是的。括号可以应用于任何指针,而不仅仅是数组。它们提供指针算术和指针解引用的简写。您的代码本质上是这样做的:
int *a = malloc(5 * sizeof(int));
*(a+2) = 4;
printf("%d\n", *(a+0));
printf("%d\n", *(a+2));
实际上与此等效:
int *a = malloc(5 * sizeof(int));
*((int*)(((unsigned long)a)+(2*sizeof(int)))) = 4;
printf("%d\n", *((int*)(((unsigned long)a)+(0*sizeof(int)))));
printf("%d\n", *((int*)(((unsigned long)a)+(2*sizeof(int)))));
【讨论】:
【参考方案3】:方括号实际上是在做一些指针运算吗?
a[b]
等价于*(a + b)
。所以是的,它是指针算术。它首先将指针偏移b
,然后访问该内存位置,就像一个数组一样。
为什么内存地址分配给
a
而不是*a
?
内存地址存储在a
,因为a
是指针,指针存储内存地址。 *a
是那个内存地址的数据。
【讨论】:
【参考方案4】:用方括号声明指针只是我在下面所做的事情的快捷方式吗?
当然不是!数组和指针是两个完全不同的东西。 int a[5];
,这里a
的类型是int[5]
,而int *b;
b
的类型是int*
。在许多情况下,前者衰变为后者。这称为阵列衰减。阅读更多关于它的信息here。
方括号实际上是在做一些指针运算吗?
是的,当您执行a[3]
时,真正发生的是*(a + 3)
,即a
衰减为int*
,其余的只是指针运算,即指向a
、3 * sizeof(int)
的第一个元素的地址已添加。
为什么内存地址分配给a而不是*a?
我认为您在标识符和应用于变量的运算符之间感到困惑。指针只是另一个变量;所有变量名都应遵循标识符的规则,即来自标准:
标识符是任意长的字母和数字序列。
虽然运算符*
取消引用它所应用的指针并根据指针类型返回结果。所以内存地址总是分配给变量a
。 a
指向的内存地址处的值将始终由*a
引用。
【讨论】:
【参考方案5】:为什么分配给a而不是*a的内存地址?
因为malloc()
返回一个address
,您使用=
运算符将其分配给(存储)指针变量a
。
通常我们将malloc()
返回的这些address
存储在指针变量中,就像您对语句a = malloc(5 * sizeof(int));
所做的那样。
如果您尝试将malloc()
返回的地址存储在非指针变量中,那么您将遇到问题。
【讨论】:
以上是关于方括号如何在 C 中工作?的主要内容,如果未能解决你的问题,请参考以下文章