C语言拼接字符串

字符串拼接涉及两个字符串的合并。strcat函数经常用来执行这种操作,这个函数接受两个字符串指针作为参数,然后把两者拼接起来并返回拼接结果的指针。这个函数的原型如下:

char *strcat(char *s1, const char *s2);

此函数把第二个字符串拼接到第一个的结尾,第二个字符串是以常量char指针的形式传递的。函数不会分配内存,这意味着第一个字符串必须足够长,能容纳拼接后的结果,否则函数可能会越界写入,导致不可预期的行为。函数的返回值的地址跟第一个参数的地址一样。这在某些情况下比较方便,比如这个函数作为printf函数的参数时。

为了说明这个函数的用法,我们会组合两个错误消息字符串。第一个是前缀,第二个是具体的错误消息。如下所示,我们首先在缓冲区中为两个字符串分配足够的内存,然后把第一个字符串复制到缓冲区,最后将第二个字符串和缓冲区拼接:

char* error = "ERROR: ";
char* errorMessage = "Not enough memory";

char* buffer = (char*)malloc(strlen(error)+strlen(errorMessage)+1);
strcpy(buffer,error);
strcat(buffer, errorMessage);

printf("%s\n", buffer);
printf("%s\n", error);
printf("%s\n", errorMessage);

我们给malloc函数的参数加1是为了容纳NUL字符。假设第一个字面量在内存中的位置就在第二个字面量前面,这段代码的输出会像下面这样。下图说明了内存分配情况。

ERROR: Not enough memory
ERROR:
Not enough memory

正确的拼接操作

如果我们没有为拼接后的字符串分配独立的内存,就可能会覆写第二个字符串,下面这个没有用到缓冲区的例子会说明这一点。我们仍然假设第一个字面量在内存中的位置就在第二个字面量前面:

char* error = "ERROR: ";
char* errorMessage = "Not enough memory";

strcat(error, errorMessage);
printf("%s\n", error);
printf("%s\n", errorMessage);

这段代码的输出如下:

ERROR: Not enough memory
ot enough memory

errorMessage字符串会左移一个字符,原因是拼接后的结果覆写了errorMessage。字面量"Not enough memory"紧跟在第一个字面量之后,因此覆写了第二个字面量。下图解释了这一点,字面量池的状态显示在左边,右边是复制操作后的状态。

不正确的字符串拼接操作

如果我们像下面这样用char数组而不是用指针来存储字符串,就不一定能工作了:

char error[] = "ERROR: ";
char errorMessage[] = "Not enough memory";

如果用下面这个strcpy调用会得到一个语法错误,这是因为我们试图把函数返回的指针赋给数组名字,这类操作不合法:

error = strcat(error, errorMessage);

如果像下面这样去掉赋值,就可能会有内存访问的漏洞,因为复制操作会覆写栈帧的一部分。这里假设在函数内部声明数组,如图5-11所示。无论源字符串是存储在字符串字面量池中还是栈帧中,都不应该用来直接存放拼接后的结果,一定要专门为拼接结果分配内存:

strcat(error, errorMessage);

覆写栈帧

拼接字符串时容易犯错的另一个地方是使用字符字面量而不是字符串字面量。在下例中,我们将一个字符串拼接到一个路径字符串后,这样是能如期工作的:

char* path = "C:";
char* currentPath = (char*) malloc(strlen(path)+2);
currentPath = strcat(currentPath,"\\");

因为额外的字符和NUL字符需要空间,我们在malloc调用中给字符串长度加了2。因为在字符串字面量中用了转义序列,所以这里拼接的是一个反斜杠字符。

不过,如果使用字符字面量,如下所示,那么就会得到一个运行时错误,原因是第二个参数被错误地解释为char类型变量的地址1:

currentPath = strcat(path,'\\');

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程