无法通过这种方式来计算数字的平方

Ema*_*uel 135 c arrays pointers c99 variable-length-array

我找到了一个计算数字平方的函数:

int p(int n) {
    int a[n]; //works on C99 and above
    return (&a)[n] - a;
}
Run Code Online (Sandbox Code Playgroud)

它返回n 2的值.问题是,它是如何做到的?经过一点点测试后,我发现之间是(&a)[k]和/ .这是为什么?(&a)[k+1]sizeof(a)sizeof(int)

Mar*_*ata 117

显然是一个黑客...但是一种在不使用*运算符的情况下对数字进行平方的方法(这是编码竞赛要求).

(&a)[n] 
Run Code Online (Sandbox Code Playgroud)

相当于指向int位置的指针

(a + sizeof(a[n])*n)
Run Code Online (Sandbox Code Playgroud)

因此整个表达是

  (&a)[n] -a 

= (a + sizeof(a[n])*n -a) /sizeof(int)

= sizeof(a[n])*n / sizeof(int)
= sizeof(int) * n * n / sizeof(int)
= n * n
Run Code Online (Sandbox Code Playgroud)

  • 作为一个古老的编码器,当编译时不知道`n`时,编译器可以将`(&a)`视为指向`n*sizeof(int)`对象的指针,这让我感到吃惊.C曾经是_simple_语言...... (33认同)
  • 顺便说一句,它也是UB,因为它增加了一个指针,既不指向底层数组的元素,也不指向过去. (14认同)
  • 正如你明确暗示但我觉得有必要明确表示,这是一种语法黑客.乘法运算仍然在那里; 它只是被避免的运营商. (11认同)

hac*_*cks 86

要理解这个hack,首先你需要理解指针差异,即当两个指向同一数组元素的指针相减时会发生什么?

当从另一个指针中减去一个指针时,结果是指针之间的距离(在数组元素中测量).所以,如果p指向a[i]q指向a[j],则p - q等于i - j.

C11:6.5.6加法运算符(p9):

当减去两个指针时,两个指针都指向同一个数组对象的元素,或者指向数组对象的最后一个元素的元素; 结果是两个数组元素的下标的差异.[...].
换句话说,如果表达式PQ指向,分别为i和第j一个数组对象的个元素,表达(P)-(Q)具有值i?j所提供的值在适合类型的对象ptrdiff_t.

现在我希望你知道数组名转换为指针,a转换为指向数组第一个元素的指针a.&a是整个存储块的地址,即它是数组的地址a.下图将帮助您理解(阅读此答案以获得详细说明):

在此输入图像描述

这将帮助您了解为什么a&a具有相同的地址以及(&a)[i] i 数组的地址(与其大小相同a)的地址.

所以,声明

return (&a)[n] - a; 
Run Code Online (Sandbox Code Playgroud)

相当于

return (&a)[n] - (&a)[0];  
Run Code Online (Sandbox Code Playgroud)

这种差异将会给指针之间的元素数(&a)[n](&a)[0],其是n各阵列n int元素.因此,总数组元素n*n= n2.


注意:

C11:6.5.6加法运算符(p9):

当减去两个指针时,两个指针都指向同一个数组对象的元素,或者指向数组对象的最后一个元素的元素 ; 结果是两个数组元素的下标的差异.结果的大小是实现定义的,其类型(有符号整数类型)ptrdiff_t<stddef.h>头文件中定义.如果结果在该类型的对象中无法表示,则行为未定义.

由于(&a)[n]既不指向同一数组对象的元素也不指向数组对象的最后一个元素,因此(&a)[n] - a将调用未定义的行为.

另请注意,最好将函数的返回类型更改pptrdiff_t.


oua*_*uah 35

a是一个(变量)数组n int.

&a是指向(变量)数组的指针n int.

(&a)[1]int一个int超过最后一个数组元素的指针.这个指针是n int后面的元素&a[0].

(&a)[2]int一个int超过两个数组的最后一个数组元素的指针.这个指针是2 * n int后面的元素&a[0].

(&a)[n]int一个int超过数组的最后一个数组元素的指针n.这个指针是n * n int后面的元素&a[0].只是减去&a[0]a你有n.

当然,这在技术上是未定义的行为,即使它在您的机器上工作,因为(&a)[n]它不指向数组内部或超过最后一个数组元素(如指针算术的C规则所要求的).


Vla*_*cow 12

如果你有两个指针指向同一个数组的两个元素,那么它的差异将产生这些指针之间的元素数量.例如,此代码段将输出2.

int a[10];

int *p1 = &a[1];
int *p2 = &a[3];

printf( "%d\n", p2 - p1 ); 
Run Code Online (Sandbox Code Playgroud)

现在让我们考虑表达

(&a)[n] - a;
Run Code Online (Sandbox Code Playgroud)

在这个表达式中a有type int *并指向它的第一个元素.

表达式&a具有类型int ( * )[n]并指向成像二维数组的第一行.它的值匹配a虽然类型的值不同.

( &a )[n]
Run Code Online (Sandbox Code Playgroud)

是这个成像的二维数组的第n个元素,并且具有类型,int[n]即它是成像数组的第n行.在表达式中,(&a)[n] - a它被转换为第一个元素的地址,并且类型为"int*".

所以在n (&a)[n]an行之间 有n行.所以差异将等于n * n.

  • @Emanuel - 这个矩阵只是对这种情况下指针算法如何工作的解释.此矩阵未分配,您无法使用它.就像它已经说过几次一样,1)这段代码片段是一个没有实际用途的hack; 2)你需要学习指针算法是如何工作的,以便理解这个hack. (2认同)