当我想通过引用一个函数来传递一个数组时,我不知道该选择什么。
void myFunction(int* data);
这两种情况之间是否存在差异或最佳编码方式:
myFunction(&data[0]);
或者
myFunction(data);
当我想通过引用一个函数来传递一个数组时,我不知道该选择什么。
void myFunction(int* data);
这两种情况之间是否存在差异或最佳编码方式:
myFunction(&data[0]);
或者
myFunction(data);
没有区别。数组(“正确的”数组)会自动衰减为指向其第一个元素的指针。
例如,假设您有
int my_array[10];
然后使用 plainmy_array
将自动衰减为指向其第一个元素的指针,即&my_array[0]
.
正是这种数组到指针的衰减允许您对数组和指针同时使用指针算术和数组索引。因为上面的数组my_array[i]
正好等于*(my_array + i)
。指针也存在这种等价性:
int *my_pointer = my_array; // Make my_pointer point to the first element of my_array
那么my_pointer[i]
也正好等于*(my_pointer + i)
。
出于好奇(以及在实际程序中你不应该做的事情),由于加法的交换性质,表达式如*(my_array + i)
也将等于*(i + my_array)
,然后等于i[my_array]
。
数组作为参数传递给函数时,会自动衰减为指向其第一个元素的指针。所以传递或者传递data
给&data[0]
函数是完全等价的。
从可读性的角度来看,我会选择前者。它使读者清楚地知道该函数可能对整个数组进行操作,而不仅仅是对一个元素进行操作。
除了明显的(data
比 短&data[0]
;因此更容易编写和阅读)之外,没有区别。
想想什么&data[0]
意思:
data[0]
.data[0]
只是意味着*(data+0)
,即*data
。*data
简单的指针data
。没有不同。当强制转换为指针时,数组 ( data
) 衰减为指向其第一个元素 ( &data[0]
) 的指针。
请记住,这data[0]
只是意味着*(data+0)
, so&data[0]
等价于&*(data+0)
,它简化为data
(因为&*
取消了)。
演示:
#include <stdio.h>
int main(void) {
int data[2];
printf("%p\n", (void*)data);
printf("%p\n", (void*)&*(data+0));
printf("%p\n", (void*)&data[0]);
return 0;
}
输出:
$ gcc -Wall -Wextra -pedantic a.c -o a && a
0x3c2180f4fa0
0x3c2180f4fa0
0x3c2180f4fa0
data 是指向数组开头的指针。&data[0] 是数组第一个元素的地址。
在阅读代码时,对于大多数人来说,第一个选项是更具可读性,我想这是大多数程序员会并且应该选择的方式
没有任何区别,因为两者都指向数组的相同起始位置,即 a[0]。
我总是建议使用通用方法。
只考虑函数
void myFunction( char* data);
其中参数具有类型char *
而不是int *
.
现在让我们假设您想将字符串文字传递给函数。
它可以像
myFunction( "Hello" );
或喜欢
myFunction( &"Hello"[0] );
很明显,第一种方法更清晰易读。
所以我更喜欢使用第一种方法。:)
其实这样的表达
&data[i];
在语法上是多余的..事实上它看起来像
&( *( data + i ) )
这相当于只是
data + i
当i
等于 0 那么你有
data + 0
在表达式中是等价的(我不考虑例如 sizeof 操作符)
data
所以使用data
而不是&data[0]
.
我会使用my_function(data)
,因为为什么让它比它必须的更混乱?
如果由于某种原因您需要在数据中间某处找到单个元素的内存地址,那么my_function(&data[17])
可能是有保证的,但也可能有更好的方法来处理这种情况。
通常,如果您必须手动且专门地手动挑选出类似的单个数据,那么您可能做得不是很好。
在极少数情况下它是有意义的(例如,如果您正在解析来自其他来源的数据,并且您总是 100% 的时间只关心第 17 个字节)......但通常情况并非如此。
考虑以下几点:随着代码的发展和您的更改,您可能还会稍微更改数据结构。Data[17] 可能不再是您需要的神奇字节。现在它可能是数据[18]。如果您在代码中的 100 或 1000 个不同位置手动硬编码数据 [17],您现在必须手动更改它们并希望它不会导致任何新错误。还有……便携性问题。
相反,设计函数可以从数据结构中找到并返回您需要的任何数据,而无需任何硬编码地址。随着代码的发展,它们仍然可以工作(如果设计得当),并且可移植性提高 1000 倍。