C字符串追加

56

我想要连接两个字符串。我使用了以下命令:

new_str = strcat(str1, str2);

这个命令改变了str1的值。我想让new_strstr1str2连接起来的结果,同时str1的值不会被改变。


5
没错,它就是这样做的。 - Charlie Martin
2
由于各种原因,您可能希望跟踪str1str2new_str的大小,并使用strncat而不仅仅是strcat。这将有助于避免一些缓冲区溢出错误。 - Brendan Long
10个回答

79

你需要分配新的空间。考虑以下代码片段:

char * new_str ;
if((new_str = malloc(strlen(str1)+strlen(str2)+1)) != NULL){
    new_str[0] = '\0';   // ensures the memory is an empty string
    strcat(new_str,str1);
    strcat(new_str,str2);
} else {
    fprintf(STDERR,"malloc failed!\n");
    // exit?
}

你可能想考虑使用稍微安全一点的strnlen(3)

更新,请见上文。在某些C运行时版本中,malloc返回的内存没有被初始化为0。将new_str的第一个字节设置为零可以确保它看起来像一个空字符串,以便于strcat使用。


14
malloc 可能会返回垃圾值,即使在现代系统上也是如此。calloc 则提供了经过清零的内存空间。 - Kornel
2
而calloc通常也需要花费sizeof(space)的时间来完成。如果您正在处理大量字符串并且对指针进行仔细的管理,那么您可以节省大量冗余指令。 - Charlie Martin
2
请删除不正确的猜测:“我相信新的C规范实际上要求malloc这样做”。此外,通过将第一个字节设置为零,根据定义,它就成为了零长度字符串(而不是看起来像)。 - Michael Labbé
使内存看起来像一个空字符串。由malloc返回的内存,由void *引用,本质上什么也不是--根据定义。 - Charlie Martin

13

请执行以下操作:

strcat(new_str,str1);
strcat(new_str,str2);

7
有一个前提条件,即 new_str 必须初始化为空字符串。 - indiv
2
当new_str无法容纳空间或(*new_str) != 0时,程序会崩溃。 - Michael Labbé
2
这一直给我“分段错误”。 - Sarah

7
考虑使用优秀但不为人知的open_memstream()函数。 FILE *open_memstream(char **ptr, size_t *sizeloc); 使用示例:
// open the stream
FILE *stream;
char *buf;
size_t len;
stream = open_memstream(&buf, &len);

// write what you want with fprintf() into the stream
fprintf(stream, "Hello");
fprintf(stream, " ");
fprintf(stream, "%s\n", "world");

// close the stream, the buffer is allocated and the size is set !
fclose(stream);
printf ("the result is '%s' (%d characters)\n", buf, len);
free(buf);

如果你事先不知道要添加的内容长度,使用这种方式比自己管理缓冲区更加方便和安全。

2
值得注意的是,open_memstream 是 POSIX 的一部分,而不是 ISO C 标准。因此,在非 Unix 系统(如 Windows)上不可用,甚至在所有 Unix 系统上也不可用。strcat 是一个更具可移植性的解决方案。 - Denis Washington

1
你需要先使用 strncpystr1 复制到 new_string 中。

0
你可以使用asprintf将它们连接成一个新的字符串:
char *new_str;
asprintf(&new_str,"%s%s",str1,str2);

1
这在特定平台上是固有的,其中asnprintf可用。它不是“标准”的。 - László Papp

0
我编写了一个支持动态变量字符串追加的函数,类似于 PHP 的字符串追加:str + str + ... 等等。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

int str_append(char **json, const char *format, ...)
{
    char *str = NULL;
    char *old_json = NULL, *new_json = NULL;

    va_list arg_ptr;
    va_start(arg_ptr, format);
    vasprintf(&str, format, arg_ptr);

    // save old json
    asprintf(&old_json, "%s", (*json == NULL ? "" : *json));

    // calloc new json memory
    new_json = (char *)calloc(strlen(old_json) + strlen(str) + 1, sizeof(char));

    strcat(new_json, old_json);
    strcat(new_json, str);

    if (*json) free(*json);
    *json = new_json;

    free(old_json);
    free(str);

    return 0;
}

int main(int argc, char *argv[])
{
    char *json = NULL;

    str_append(&json, "name: %d, %d, %d", 1, 2, 3);
    str_append(&json, "sex: %s", "male");
    str_append(&json, "end");
    str_append(&json, "");
    str_append(&json, "{\"ret\":true}");

    int i;
    for (i = 0; i < 10; i++) {
        str_append(&json, "id-%d", i);
    }

    printf("%s\n", json);

    if (json) free(json);

    return 0;
}

这将是一个非常低效的、非常快速的解决方案。 - lukassos

-1

我需要添加子字符串来创建一个ssh命令,我用(Visual Studio 2013)解决了这个问题。

char gStrSshCommand[SSH_COMMAND_MAX_LEN]; // declare ssh command string

strcpy(gStrSshCommand, ""); // empty string

void appendSshCommand(const char *substring) // append substring
{
  sprintf(gStrSshCommand, "%s %s", gStrSshCommand, substring);
}

-1
strcpy(str1+strlen(str1), str2);

1
这个失败是因为 str1 必须保持不变(根据问题要求)。 - Michael Labbé
4
请问你能否说明一下你的回答如何解决问题?仅包含代码的回答并不是很有用,尤其对于后来遇到这篇文章的读者来说。谢谢! - Cristik

-3

strcat的man页面说明arg1和arg2被附加到arg1中,并返回s1的指针。如果您不想干扰str1、str2,则必须编写自己的函数。

char * my_strcat(const char * str1, const char * str2)
{
   char * ret = malloc(strlen(str1)+strlen(str2));

   if(ret!=NULL)
   {
     sprintf(ret, "%s%s", str1, str2);
     return ret;
   }
   return NULL;    
}

希望这能解决你的问题


2
我不喜欢使用printf进行字符串拼接。可以使用strcpy、strcat甚至memcpy轻松完成。 - eyalm
是的,你说得对。但我想给你一个单一的语句。你可以使用strcpy(ret,str1),然后再使用strcat(ret,str2)。或者像你说的那样,使用memcpy会更快。 - maheshgupta024
3
你需要为复制的字符串分配多少空间?提示:不是strlen(str)。 - Bo Persson
1
我对在函数内部进行malloc操作的任何代码都感到不满! - Ulterior
2
这段代码崩溃是因为malloc的长度没有考虑到空终止符。此外,多个返回语句是冗余的。 - Michael Labbé

-4

2
这真是糟糕透了,在这里使用strlen(str1)和使用strncpy()没有任何意义,普通的strcpy()也能实现同样的功能。如果你使用sizeof new_str,那就有意义了。 - unwind
2
我不知道这是一个打字错误还是对strncpy函数的n参数的严重误解,但你需要提供new_str的缓冲区大小,而不是str1的长度。如果new_str只能容纳5个字符,但str1却有1000个字符,那么会发生什么呢? - indiv
@indiv 不要误解。strncpy 参考 - num - 将源的前 num 个字符复制到目标中。当然,在进行此操作之前应检查源缓冲区的长度。 - Ulterior

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接