【问题标题】:Why 'c[&i]' compiles while 'c[i]' doesn't? [duplicate]为什么 'c[&i]' 编译而 'c[i]' 不编译? [复制]
【发布时间】:2016-10-18 21:39:19
【问题描述】:

此示例编译时没有警告/错误(gcc 4.8.2 -Wall):

#include <stdio.h>
int main() 
{ 
    char c;
    int i;    
    printf("%p %02x\n",&i,c[&i]);
    printf("%p %02x\n",&c,c[&c]);

    // important to note that this line DOESN'T compile:
    //printf("%p %02x\n",&i,c[i]);
    //  which makes sense as c is NOT an array, it is a char.

    return 1;
}

为什么语法 c[&i] 可以编译?是故意的还是意外的? 语法 c[&i] 在语义上是否有效? (有什么有用的意思吗?)

我的输出示例:(指针每次都会改变)

0xbfb2577c b7718cea
0xbfb2577b 08

这个问题源于这里有问题的一段奇怪的代码“ch2[&i]”: C duplicate character,character by character

NOTE#0(经过反思更新)关于重复/类似问题: 这个问题不是 c 数组引用上的链接问题的重复。它是相关的,因此参考它们很有用。相关问题讨论了有效的 a[b] 和 b[a] 情况,其中 a 或 b 之一是指针,另一个是 int。这个问题处理更奇怪的情况,也许应该是无效的情况,其中 a 或 b 之一是字符。 对于C数组,为什么a[5] == 5[a]? 14 个答案 With arrays, why is it the case that a[5] == 5[a]? 字符串作为数组索引 3 个答案 String as an array index

注意 #1:编译器会发生这种情况,因为变量 c 的类型是 char,当与指针结合使用时,它可以用作数组的索引。

注意 #2:由于某种原因,c[&lt;ptr&gt;] 的类型计算为 &lt;ptr&gt; 的类型。

例如:c[&amp;pi]c[&amp;pc] 的结果类型导致以下代码中的警告:

int *pi; char *pc; pi=&i; pc=&c;
printf("%p %02x\n",&pi,c[&pi]);
printf("%p %02x\n",&pc,c[&pc]);

关于类型“int *”或“char *”而不是“unsigned int”的警告:

c/so_cweirdchar2.c: In function ‘main’:
c/so_cweirdchar2.c:13:5: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘int *’ [-Wformat=]
     printf("pi %p %02x\n",&pi,c[&pi]);
     ^
c/so_cweirdchar2.c:14:5: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘char *’ [-Wformat=]
     printf("pc %p %02x\n",&pc,c[&pc]);
     ^

【问题讨论】:

  • 注意&amp;i一个指针。

标签: c arrays pointers syntax


【解决方案1】:

在 C 中,[] 后缀指针置换运算符是可交换的。如果a[i] 是一个有效的表达式,那么i[a] 也是一个有效的表达式,并且意思相同。尽管我们必须观察运算符的关联性和优先级,以确保我们正确地执行此反转操作。您的c[&amp;i](&amp;i)[c] 的含义相同:指针&amp;i 被整数c 取代。

[] 的可交换性的基础是索引与指针位移和解引用的组合之间的等价性,其中+ 运算符是可交换的:

E1[E2]  <-->  *(E1 + E2)
  ^               ^
  |               |
  v               v
E2[E1]  <-->  *(E2 + E1)

这里我们将E1 理解为完全带括号的表达式,因此我们不关心优先级。实际上,我们正在操作抽象语法树,其中E1E2 是节点。

【讨论】:

  • 酷。好的。很好的解释。我现在部分明白了。如果 [] 内的值是整数,它会起作用。奇怪的是,如果 c 是一个普通变量,像 c[i] 这样的表达式将无法编译,例如字符 c;但是使用指针作为引用似乎会诱使编译器允许您为普通变量下标。
  • 另一件值得注意的事情是,我看到 a[&b] 的类型以 b 类型出现。这是当 'a' 是 char(不是 char*)时。并不完全符合人们的预期。
  • c[i] 要求操作数之一是指针,一个是整数。这是因为它基本上是*(c + i)c + i 部分,如果我们这样看,理论上会采用任何算术类型,例如 intfloat;但结果不会与一元 * 取消引用;这需要一个指针。产生指针的唯一加法表达式是 pointer + some integer type 或反之亦然。
  • 有趣的是,编译器在c[i] 中标记(作为警告我假设)c 不是数组,但在c[&amp;i](或(&amp;i+c))中没有标记这不是一个数组。在第一个中,程序员被告知他索引不是数组的东西(c),但在第二个中,他没有被告知他索引其他不是数组的东西(i),
  • 我看到编译器将 c[i] 作为错误抛出。正确的是:0) 谁想要索引到单个字符 c。 c[&i] 上没有错误或警告。
【解决方案2】:

编译没有错误。完全有效的 C:

int main (int argc, char** argv)
{
    int n=5;
    char *a="abcdefghijk";

    printf("%c\n", a[n]);
    printf("%c\n", n[a]);
    return 0;
}

【讨论】:

  • 但是'char c; c[n];'不编译。 “错误:下标值既不是数组也不是指针也不是向量”
  • 正确。你需要一个整数和一个指针,OP 有。请注意,如果我将 int n=5; 更改为 char n=5; 我的示例仍然可以编译并运行良好。
  • “一个整数和一个指针”有助于记住 a[b]。谢谢。添加注意,c 可以愉快地转换 char 或任何指向/来自 int 的指针。我可以看到您的示例并自行理解它,但没有完全理解您试图用它解释的内容。
猜你喜欢
  • 2019-12-12
  • 2012-02-01
  • 1970-01-01
  • 2011-06-28
  • 1970-01-01
  • 1970-01-01
  • 2023-03-22
  • 2020-05-10
  • 2010-12-18
相关资源
最近更新 更多