在研究C中的字符串操作时,我遇到了一个与strcat()
不太一样的效果。采用以下小程序:
#include <stdio.h>
#include <string.h>
int main()
{
char string[20] = "abcde";
strcat(string + 1, "fghij");
printf("%s", string);
return 0;
}
我希望这个程序能打印出bcdefghij
。我的想法是,在C中,字符串是字符数组,数组的名称是指向其第一个元素的指针,即索引为零的元素。因此,变量string
是指向a
的指针。但是,如果我计算string + 1
,并将其用作与strcat()
级联的目标数组,我会得到一个指向一个数组元素(在本例中为1 * sizeof(char)
)之外的内存地址的指针,从而得到指向b
的指针。所以我的想法是,目标目的地是以b
开始(以不可见的null字符结束)的数组,然后连接fghij
,得到bcdefghij
。
但这不是我得到的——程序的输出是abcdefghij
。这与我在strcat(string, "fghij");
中得到的输出完全相同——忽略了1与string
的相加。我还得到了相同的输出,添加了另一个数字,例如strcat(string + 4, "fghij");
。
有人能向我解释一下为什么会这样吗?我的最佳猜测是,它与+
运算符的绑定优先级有关,但我对此不确定。
编辑:我用char string[20]
增加了原始数组的大小,这样它在任何情况下都足够大,可以容纳连接的字符串。输出仍然是一样的,我认为这意味着数组溢出不是我问题的关键。
您将得到abcdefghij
的输出,因为您对strcat
的调用没有更改string
的地址(您也不能更改它——它在声明它的块的持续时间内是固定的,就像任何其他变量的地址一样)。传递给strcat
的是string
数组的第二个元素的地址:但它仍然被解释为以nul
结尾的字符串的地址,调用会将第二个(源)参数附加到该字符串。将第二个参数的内容附加到string
、string + 1
或string + n
将在string
数组中产生相同的结果,只要在n
索引处或之后有nul
终止符即可。
要打印实际传递给strcat
调用的字符串值(即从'b'
字符开始),可以保存调用的返回值并打印:
#include <stdio.h>
#include <string.h>
int main()
{
char string[20] = "abcde";
char* result = strcat(string + 1, "fghij"); // strcat will return the "string + 1" pointer
printf("%s", result); // bcdefghij
return 0;
}
char string[] = "abcde";
strcat(string + 1, "fghij");
将五个字符附加到一个完整的字符串数组中。Booom。未定义的行为。
将某些内容添加到字符串数组是一种性能优化,它告诉运行时已知字符串至少有那么多个字符长。
您似乎相信字符串是它自己的东西,而不是数组,strcat
正在对它的第一个参数做一些事情。这不是怎么回事。字符串是数组*;strcat正在修改数组内容。
*有人会过来声称堆分配的字符串不是数组。OP还没有处理堆
数组是不可修改的lvalue。例如,您可能不写
char string[20] = "abcde";
char string2[] = ""fghij"";
string = string2;
在表达式中使用的数组会隐式转换为指向其第一个元素的指针。
例如,如果要写入string + 1
,则不会更改数组的地址。
在这次通话中
strcat(string + 1, "fghij");
从数组的第二个元素开始重写数组字符串的元素。
在本声明中,
printf("%s", string);
从其第一个字符开始输出整个数组(再次将用作自变量的数组指示符转换为指向其第一个元素的指针)。
你可以写例如
printf("%s", string + 1);
在这种情况下,数组从其第二个元素开始输出。
这只是指向同一数组中同一内存不同部分的两个指针。您的代码中没有创建第二个数组的内容"数组的名称是指向其第一个元素"的指针;实际上,无论何时在表达式中使用,它都会衰减为指向其第一个元素的指针。所以在string + 1
的情况下,这种衰减首先发生在string
操作数上,然后得到指针算术。实际上,您永远不能对数组类型执行指针运算,只能对衰退的指针执行指针运算。这里的详细信息:Do pointers support"数组式索引";?
对于strcat
,它基本上做两件事:对原始字符串调用strlen
以找到它的结束位置,然后调用strcpy
将新字符串附加到存储null终止符的位置。这与键入strcpy(&src[strlen(src)], dst);
完全相同
因此,传递string + 1
或string
都无关紧要,因为在任何一种情况下,strcat
都将查找null终止符,而不查找其他内容。