这段代码有几个问题,但首先我们需要退后一步,谈谈如何在 C 中处理数组。
除非它是 sizeof 或一元 & 运算符的操作数,或者是用于在声明中初始化另一个数组的字符串字面量,否则“T 的 N 元素数组”类型的表达式将被转换(“decay”)为“pointer to T”类型的表达式,表达式的值将是数组第一个元素的地址。
在声明中
char a[] = "hello";
"hello" 是一个字符串文字,其类型为“char 的 6 元素数组”(5 个字符加上 0 终止符)。因为它被用来在声明中初始化数组a,所以上面的规则不适用;相反,a 的大小设置为与字面量 (6) 的大小相同,并将字符串字面量的内容复制到数组中。
当您从main 呼叫change 时
change(a);
表达式 a 的类型为“char 的 6 元素数组”。由于它既不是字符串文字,也不是sizeof 或一元& 运算符的操作数,因此该表达式将转换为“指向char”的类型,表达式的值将是第一个地址元素。因此change 函数被声明为
void change(char *a);
在这种情况下,a 只是一个指针。当你写
a = "goodbye";
字符串文字"goodbye" 没有在初始化程序中使用,它不是sizeof 或一元& 运算符的操作数,因此表达式被转换为类型“指向char”的指针,并且表达式的值是第一个字符的地址。所以这里发生的情况是,您将字符串文字"goodbye" 的地址 复制到a。这将覆盖a 中的值,但此a 与main 中的array a 不是同一个内存对象,因此对它的任何更改都不会反映在@987654352 中@。
如果您想更新数组的内容,您将需要使用库函数strcpy/strncpy(用于以0 结尾的字符串)或memcpy(用于其他所有内容),或者显式更新每个元素(a[0]='g'; a[1]='o'; a[2]='o'; 等)。
要更新a 的内容,您可以使用
strcpy( a, "goodbye" );
除了...
a 只能容纳 5 个字符和一个 0 终止符; "goodbye" 是 7 个字符加上 0 终止符;它比a 能够存储的字符大两个字符。 C 将很乐意让您执行操作并立即丢弃a 之后的字节,这可能会导致任何数量的问题(像这样的缓冲区溢出是典型的恶意软件利用)。此时您有两个选择:
首先,您可以声明 a 大到足以处理任一字符串:
#define MAX_LEN 10
...
char a[MAX_LEN] = "hello";
其次,可以限制复制到a的字符串大小:
void change( char *a, size_t size )
{
strncpy( a, "goodbye", size - 1 );
a[size - 1] = 0;
}
请注意,当您调用change 时,您需要传递a 可以存储为单独参数的元素数量;没有办法从指针告诉它指向的数组有多大:
change( a, sizeof a / sizeof *a ); // although in this case, sizeof a would be
// sufficient.