如何在C语言中连接两个字符串?

176

我该如何将两个字符串相加?

我尝试了name = "derp" + "herp";,但出现了错误:

表达式必须具有整数或枚举类型

12个回答

221

C语言不像其他一些编程语言那样提供对字符串的全面支持。在C中,字符串只是指向以第一个空字符结尾的char数组的指针。C中没有字符串拼接运算符。

使用strcat函数来连接两个字符串。您可以使用以下函数来实现:

#include <stdlib.h>
#include <string.h>

char* concat(const char *s1, const char *s2)
{
    char *result = malloc(strlen(s1) + strlen(s2) + 1); // +1 for the null-terminator
    // in real code you would check for errors in malloc here
    strcpy(result, s1);
    strcat(result, s2);
    return result;
}

这不是最快的方式,但你现在不应该担心那个。请注意,该函数向调用者返回一个堆分配的内存块,并传递该内存块的所有权。当不再需要该内存块时,调用者有责任使用 free 函数释放内存。

像这样调用函数:

char* s = concat("derp", "herp");
// do things with s
free(s); // deallocate the string
如果您确实关注性能问题,那么您会希望避免反复扫描输入缓冲区以查找空终止符。
char* concat(const char *s1, const char *s2)
{
    const size_t len1 = strlen(s1);
    const size_t len2 = strlen(s2);
    char *result = malloc(len1 + len2 + 1); // +1 for the null-terminator
    // in real code you would check for errors in malloc here
    memcpy(result, s1, len1);
    memcpy(result + len1, s2, len2 + 1); // +1 to copy the null-terminator
    return result;
}

如果你打算大量使用字符串,那么最好使用一种具有对字符串的一流支持的不同语言。


1
小技巧:代码可以复制字符串的第一部分到最后,然后使用return memcpy(result, s1, len1);。虽然这只是微小的优化或者说是一点点的代码压缩,但是对于基本字符串操作的潜在改进可以提高其价值,因为这些操作被广泛使用。 - chux - Reinstate Monica
6
使用 stpcpy 的第一个版本可以轻微提高性能,它会返回指向第一个字符串末尾的指针:strcpy(stpcpy(result, s1), s2); - Daniel
@Daniel 你是指 strcat(stpcpy(result, s1), s2); 吗? - YoussefDir
@YoussefDir 不,他没有。 - David Heffernan
1
@YoussefDir 我拒绝了你的建议修改。你看到的编译器错误是因为你正在使用 C++ 编译器,但这是一个 C 语言问题。 - David Heffernan

24
#include <stdio.h>

int main(){
    char name[] =  "derp" "herp";
    printf("\"%s\"\n", name);//"derpherp"
    return 0;
}

1
它也适用于C语言中的宏,这值得注意。 - Abe Fehr

21

David Heffernan在他的回答中解释了这个问题,我写了改进后的代码。请看下面。

一个通用函数

我们可以编写一个有用的可变参数函数来连接任意数量的字符串:

#include <stdlib.h>       // calloc
#include <stdarg.h>       // va_*
#include <string.h>       // strlen, strcpy

char* concat(int count, ...)
{
    va_list ap;
    int i;

    // Find required length to store merged string
    int len = 1; // room for NULL
    va_start(ap, count);
    for(i=0 ; i<count ; i++)
        len += strlen(va_arg(ap, char*));
    va_end(ap);

    // Allocate memory to concat strings
    char *merged = calloc(sizeof(char),len);
    int null_pos = 0;

    // Actually concatenate strings
    va_start(ap, count);
    for(i=0 ; i<count ; i++)
    {
        char *s = va_arg(ap, char*);
        strcpy(merged+null_pos, s);
        null_pos += strlen(s);
    }
    va_end(ap);

    return merged;
}

使用方法

#include <stdio.h>        // printf

void println(char *line)
{
    printf("%s\n", line);
}

int main(int argc, char* argv[])
{
    char *str;

    str = concat(0);             println(str); free(str);
    str = concat(1,"a");         println(str); free(str);
    str = concat(2,"a","b");     println(str); free(str);
    str = concat(3,"a","b","c"); println(str); free(str);

    return 0;
}

输出:

  // Empty line
a
ab
abc

清理

请注意,当不再需要分配的内存时,应该释放它以避免内存泄漏:

char *str = concat(2,"a","b");
println(str);
free(str);

4
calloc的参数顺序是错误的,应该先是count再是size。由于sizeof(char)被定义为1,因此在这里可以通过乘法恒等式来避免问题。 - Andy
int len --> size_t len 视为 "size" 代码的正确类型,因为 size_t 是正确的类型。同时,将 // room for NULL --> // room for null character,因为 NULL 意味着空指针。 - chux - Reinstate Monica

20

我假设你只需要它用于一次性的事情。我假设你是一名PC开发者。

使用Stack,Luke。无论何时何地都要使用它。永远不要为小型分配使用malloc/free。

#include <string.h>
#include <stdio.h>

#define STR_SIZE 10000

int main()
{
  char s1[] = "oppa";
  char s2[] = "gangnam";
  char s3[] = "style";

  {
    char result[STR_SIZE] = {0};
    snprintf(result, sizeof(result), "%s %s %s", s1, s2, s3);
    printf("%s\n", result);
  }
}

如果每个字符串的大小不够10 KB,那就把它的大小加一个零,不必担心——它们会在作用域结束时释放它们的堆栈内存。

1
这段代码可以更清晰地表达为 snprintf(result, sizeof result, "%s %s %s", s1, s2, s3); - M.M
因为江南Style而点赞 - Sathesh

9
你应该使用strcat,或者更好的是strncat。搜索一下(关键词是“连接字符串”)。

8
警告:strncat() 是一个极难正确使用的函数。不看手册,你会指定什么长度给 strncat() 吗?如果你说“缓冲区的长度”,那么你刚好证明了我的观点。它的接口让人很难理解,而当你有足够的数据安全使用它时,你根本不需要使用该函数——有其他更快、更高效的替代方案(如 strcpy()memmove())。几乎无论问到“我应该使用什么”,strncat() 都不是答案。 - Jonathan Leffler

7
在C语言中,你不能像那样添加字符串字面值。你需要创建一个缓冲区,大小为字符串字面值一加上字符串字面值二再加上一个字节用于空字符终止,并将相应的字面值复制到该缓冲区,并确保它以空字符结尾。或者你可以使用库函数,比如strcat

4

字符串连接

在C语言中,将任意两个字符串连接起来至少有3种方法:

1) 将字符串2复制到字符串1的末尾

#include <stdio.h>
#include <string.h>
#define MAX 100
int main()
{
  char str1[MAX],str2[MAX];
  int i,j=0;
  printf("Input string 1: ");
  gets(str1);
  printf("\nInput string 2: ");
  gets(str2);
  for(i=strlen(str1);str2[j]!='\0';i++)  //Copying string 2 to the end of string 1
  {
     str1[i]=str2[j];
     j++;
  }
  str1[i]='\0';
  printf("\nConcatenated string: ");
  puts(str1);
  return 0;
}

2) 通过将字符串1和字符串2复制到字符串3中

#include <stdio.h>
#include <string.h>
#define MAX 100
int main()
{
  char str1[MAX],str2[MAX],str3[MAX];
  int i,j=0,count=0;
  printf("Input string 1: ");
  gets(str1);
  printf("\nInput string 2: ");
  gets(str2);
  for(i=0;str1[i]!='\0';i++)          //Copying string 1 to string 3
  {
    str3[i]=str1[i];
    count++;
  }
  for(i=count;str2[j]!='\0';i++)     //Copying string 2 to the end of string 3
  {
    str3[i]=str2[j];
    j++;
  }
  str3[i]='\0';
  printf("\nConcatenated string : ");
  puts(str3);
  return 0;
}

3) 通过使用strcat()函数

#include <stdio.h>
#include <string.h>
#define MAX 100
int main()
{
  char str1[MAX],str2[MAX];
  printf("Input string 1: ");
  gets(str1);
  printf("\nInput string 2: ");
  gets(str2);
  strcat(str1,str2);                    //strcat() function
  printf("\nConcatenated string : ");
  puts(str1);
  return 0;
}

4

没有 GNU 扩展:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    const char str1[] = "First";
    const char str2[] = "Second";
    char *res;

    res = malloc(strlen(str1) + strlen(str2) + 1);
    if (!res) {
        fprintf(stderr, "malloc() failed: insufficient memory!\n");
        return EXIT_FAILURE;
    }

    strcpy(res, str1);
    strcat(res, str2);

    printf("Result: '%s'\n", res);
    free(res);
    return EXIT_SUCCESS;
}

或者使用GNU扩展方式:

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    const char str1[] = "First";
    const char str2[] = "Second";
    char *res;

    if (-1 == asprintf(&res, "%s%s", str1, str2)) {
        fprintf(stderr, "asprintf() failed: insufficient memory!\n");
        return EXIT_FAILURE;
    }

    printf("Result: '%s'\n", res);
    free(res);
    return EXIT_SUCCESS;
}

查看更多详情,请参考mallocfreeasprintf


3
#include <string.h>
#include <stdio.h>
int main()
{
   int a,l;
   char str[50],str1[50],str3[100];
   printf("\nEnter a string: ");
   scanf("%s",str);
   str3[0]='\0';
   printf("\nEnter the string which you want to concat with string one: ");
   scanf("%s",str1);
   strcat(str3,str);
   strcat(str3,str1);
   printf("\nThe string is %s\n",str3);
}

1

我这里使用了asprintf

样例代码:

char* fileTypeToStr(mode_t mode) {
    char * fileStrBuf = NULL;
    asprintf(&fileStrBuf, "%s", "");

    bool isFifo = (bool)S_ISFIFO(mode);
    if (isFifo){
        asprintf(&fileStrBuf, "%s %s,", fileStrBuf, "FIFO");
    }

...

    bool isSocket = (bool)S_ISSOCK(mode);
    if (isSocket){
        asprintf(&fileStrBuf, "%s %s,", fileStrBuf, "Socket");
    }

    return fileStrBuf;
}

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