【问题标题】:Reconciling declaration and usage syntax of arrays in C协调 C 中数组的声明和使用语法
【发布时间】:2014-11-22 23:02:41
【问题描述】:

在 C 中,“数组语法”只是指针语法的语法糖。那是 a[4] 转换为 *(a+4)

但这并不总是正确的。

下面肯定是荒谬的,

int a[4] = {1,2,3,4};
int *(a+4) = {1,2,3,4};

这不会编译。

无论如何,我想知道是否有人对这种差异有任何见解。对我来说,拥有两种不同类别的语法似乎很奇怪。一份声明,一份实际使用。

这是怎么回事?

【问题讨论】:

  • 你的第二行应该更像:int *a = malloc(sizeof(int) * 4); a[1] = 1; a[2] = 2;...etc...
  • 除了 SnakeDoc 的正确注释之外,您还有其他实例,其中不止一种语法是正确的。 V.g.,(*myPointerToStruct).myMembermyPointerToStruct->myMember 相同。或者,数组a[0]*a 相同(第一种形式更好)

标签: c arrays pointers syntax declaration


【解决方案1】:

C 的(诚然令人困惑的)声明语法背后的一般灵感是“声明遵循使用”。所以,例如:

int *ptr;

碰巧将ptr 声明为int* 类型的对象(这就是为什么有些人更喜欢写int* ptr;),但是如果您遵循语法,它真正 的意思是*ptr 的类型为 int

但不要太从字面上理解“声明遵循使用”的想法。这不是一个实际的语言规则,它并不适用于所有情况。这是理解 C 的声明语法的良好开端,但绝不是全部。

对于简单的数组定义:

int arr[10];

你可以说arr[10]int 类型。而表达式arr[10]的类型为int,当然它指的是一个不存在的数组元素。

数组和指针是不等价的。数组索引运算符是涉及指针运算的操作的“语法糖”:x[y] 表示 *(x+y)。但这仅适用于数组索引运算符[]。它不适用于数组声明语法。

通过将声明视为表达式,可以理解许多(但不是全部)形式的声明,类型名称告诉您该表达式具有什么类型。但并非所有表达式都可以转换为声明。没有对应于表达式x+y 或表达式*(x+y) 的声明。

关于数组和指针,最重要的是要记住它们是不同的东西。索引运算符[] 被定义为对指针值进行操作(该指针必须指向数组对象的元素)。在大多数但不是所有上下文中,数组类型的表达式隐式转换为指向数组第一个元素的指针;例外情况是它是一元 &、一元 sizeof 的操作数,或者是用于初始化数组的初始化程序中的字符串文字。

C 声明的含义由语言语法决定。 “声明遵循使用”不是该语法的一部分。

【讨论】:

  • 但是为什么同一种语言中有这两个语法?为什么不只是一克!
  • @captaincurrie:一个语法;您可以在C standard 中看到它。声明和表达式有单独的部分,因为两者的单一语法都行不通。你是说C在所有情况下都应该严格遵循“声明遵循使用”的原则吗?随意展示如何使它发挥作用。说真的,这会很有趣。但它必须是一种新的语言;此时从根本上改变 C 的语法会破坏现有代码,这是行不通的。
  • @captaincurrie: C 不是 100% 一致的,因为它进化了;它具有许多早期 C 或其祖先语言 B 中不存在的特性,并且必须在不破坏现有代码的情况下添加它们。一些 Lisp 方言在语法上可能接近 100% 一致——但 C 绝对不是 Lisp。
  • 谢谢。我想我需要好好研究一下程序语言的实现/设计才能感到满意。
【解决方案2】:

您提到的“语法糖”适用于 后缀表达式 [...]。您在示例中拥有的是声明。两者都使用相同的字符,但是这两个结构属于语法树的完全不同的分支。

【讨论】:

  • 感谢您的回答。我只是觉得'为什么你会在同一种语言中有两种不同的语法'。感觉像是一些不应该存在的杂质。我想要一致性!
【解决方案3】:

引用C-faq:

说数组和指针是“等价的”并不意味着 它们是相同的,甚至不能互换。它的意思是 数组和指针算术被定义为使得指针可以 方便地用于访问数组或模拟数组。其他 用 Wayne Throop 的话来说,它是“指针算术和数组” 索引 [that] 在 C 中是等价的,指针和数组是 不同。'')

除此之外,引用 C-faq 中的this 问题:

数组是一个单独的、预先分配的连续元素块(所有 同类型),大小和位置固定。指针是一个 在任何地方引用任何数据元素(特定类型)。一种 必须将指针分配为指向在别处分配的空间,但它 可以重新分配(并且空间,如果从 malloc 派生,可以 调整大小)随时。指针可以指向一个数组,并且可以 模拟(与 malloc 一起)动态分配的数组,但 指针是一种更通用的数据结构。

所以数组不仅仅是指针的语法糖

【讨论】:

  • 我会比常见问题解答更进一步。说数组和指针是“等价的”是完全错误的。他们不是。
  • 数组是一个概念,是我们可以操作的数学对象。指针是一个实际的东西。
  • @captaincurrie:好吧,矩阵是您所指的数学对象。数组和指针都是“实际的东西”:P 但它不是同一事物的不同表示法。它们根本不同。
【解决方案4】:

指针语法之所以有效,是因为这就是 C 在幕后的工作方式,并且不会阻止您滥用它。

int a[4] 告诉编译器你想在堆栈中创建一个给定大小的变量(4 x sizeof(int)),所以如果你想使用指针语法来做,你必须找到另一个告诉它这样做的方法,或者使用malloc,或者通过分配double b[2](或任何其他相同大小的东西)并投射它。

【讨论】:

  • 你怎么知道double b[2]int a[4]大小一样?不一定。并且定义double 的数组并将其视为int 的数组是不安全的;一方面,对齐方式可能不匹配。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-20
  • 1970-01-01
  • 2018-09-18
  • 2021-11-17
  • 1970-01-01
  • 2011-02-02
  • 2015-11-01
相关资源
最近更新 更多