方括号如何在 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 知道 int4-bytes,因此它为内存中的第三个 int 提供了正确的地址。 感谢您的及时回复。我有一些这样的书。我想我应该多加注意。 说真的,问题是在你达到一定程度的理解之前,真正的答案是没有意义的,所以试图在曲折的细节中“理解基础”并不是很刚开始时很有效率。这就是为什么它们对你来说不是“人类可读的”。最好只是通过并接受一段时间的浅层理解,直到足够的练习使一切都开始点击。 【参考方案1】:

我没有将int *a 明确声明为指向数组的指针,但如果我为它分配一些内存,我就可以使用a,就像我已经 将它声明为一个数组一样。用方括号声明一个指针只是我在下面所做的事情的快捷方式吗?

类似,但不是。 int *aa 声明为指向 int 的指针。 int b[5] 为 5 个 ints 分配空间,将 b 声明为 constant pointer to int 一个 array-of-int 引用(在大多数情况下可以被视为常量指向int) 的指针,并将b 定义为指向已分配空间的指针。因此,int b[5]int *a 做得更多,这也意味着int *aint 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*,其余的只是指针运算,即指向a3 * sizeof(int) 的第一个元素的地址已添加。

为什么内存地址分配给a而不是*a?

我认为您在标识符和应用于变量的运算符之间感到困惑。指针只是另一个变量;所有变量名都应遵循标识符的规则,即来自标准:

标识符是任意长的字母和数字序列。

虽然运算符* 取消引用它所应用的指针并根据指针类型返回结果。所以内存地址总是分配给变量aa 指向的内存地址处的值将始终由*a 引用。

【讨论】:

【参考方案5】:

为什么分配给a而不是*a的内存地址?

因为malloc() 返回一个address,您使用= 运算符将其分配给(存储)指针变量a

通常我们将malloc() 返回的这些address 存储在指针变量中,就像您对语句a = malloc(5 * sizeof(int)); 所做的那样。

如果您尝试将malloc() 返回的地址存储在非指针变量中,那么您将遇到问题。

【讨论】:

以上是关于方括号如何在 C 中工作?的主要内容,如果未能解决你的问题,请参考以下文章

FROM中的子查询不在Oracle SQL中工作

ORA-00907: SQL 中的自然连接缺少右括号

shell括号操作符

&符号(&)符号如何在c ++中工作? [复制]

如何让 tcsetpgrp() 在 C 中工作?

char* argv[] 如何在 c/c++ 中工作? [复制]