当用作strcat()的目标数组时,C中的指针算术



在研究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结尾的字符串的地址,调用会将第二个(源)参数附加到该字符串。将第二个参数的内容附加到stringstring + 1string + 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 + 1string都无关紧要,因为在任何一种情况下,strcat都将查找null终止符,而不查找其他内容。

最新更新