如何在C语言中连接常量/字面字符串?

425

我正在使用C语言编程,需要将一些东西拼接起来。

目前我有以下代码:

message = strcat("TEXT ", var);

message2 = strcat(strcat("TEXT ", foo), strcat(" TEXT ", bar));

如果你有C语言的经验,你肯定知道当你运行这段代码时会产生分段错误。那么我该如何解决这个问题?


9
建议您使用 strlcat 而不是 strcat!http://www.gratisoft.us/todd/papers/strlcpy.html - activout.se
7
我想重申一下那个建议。Strcat会导致缓冲区溢出漏洞,有人可能给你的程序提供数据,导致它执行任意代码。 - Brian
17个回答

3

strcat()函数的第一个参数需要能够容纳足够空间以存储连接后的字符串。因此,需要分配具有足够空间来接收结果的缓冲区。

char bigEnough[64] = "";

strcat(bigEnough, "TEXT");
strcat(bigEnough, foo);

/* and so on */

strcat()函数将第二个参数连接到第一个参数上,并将结果存储在第一个参数中。返回的char*只是第一个参数本身,仅供参考。

你不能得到一个新分配的字符串,其中包含第一个和第二个参数连接在一起的内容,这可能与你的代码预期不符。


2

您可以编写自己的函数来完成与strcat()相同的操作,但不会改变任何内容:

#define MAX_STRING_LENGTH 1000
char *strcat_const(const char *str1,const char *str2){
    static char buffer[MAX_STRING_LENGTH];
    strncpy(buffer,str1,MAX_STRING_LENGTH);
    if(strlen(str1) < MAX_STRING_LENGTH){
        strncat(buffer,str2,MAX_STRING_LENGTH - strlen(buffer));
    }
    buffer[MAX_STRING_LENGTH - 1] = '\0';
    return buffer;
}

int main(int argc,char *argv[]){
    printf("%s",strcat_const("Hello ","world"));    //Prints "Hello world"
    return 0;
}

如果两个字符串加起来的长度超过1000个字符,它将在1000个字符处截断字符串。您可以更改MAX_STRING_LENGTH的值以适应您的需求。

哇!你从来没有释放内存,太糟糕了! return buffer; free(buffer); - Liviu
@Duck,你需要在函数退出后释放内存...这样你就不需要手动释放它了。 - Liviu
char* mycat = strcat_const("Hello ","world"); free(mycat);有区别,不是吗? - Liviu
1
return buffer;之后执行free(buffer);,如果没有执行,请在调试器中查看;我现在明白了:是的,在main函数中必须释放内存。 - Liviu
@Liviu 我已经编辑过了,现在没有内存泄漏的问题,但是它只支持有限数量的字符。 - Donald Duck
显示剩余10条评论

2
您正在尝试将一个字符串复制到静态分配的地址中。您需要将其拼接到缓冲区。

具体而言:

...剪辑...

目标地

Pointer to the destination array, which should contain a C string, and be large enough to contain the concatenated resulting string.

这里还有一个示例。

http://www.cplusplus.com/reference/clibrary/cstring/strcat.html

此外,这里也有相关内容。


1
尝试类似于这个的东西:
#include <stdio.h>
#include <string.h>

int main(int argc, const char * argv[])
{
  // Insert code here...
  char firstname[100], secondname[100];
  printf("Enter First Name: ");
  fgets(firstname, 100, stdin);
  printf("Enter Second Name: ");
  fgets(secondname,100,stdin);
  firstname[strlen(firstname)-1]= '\0';
  printf("fullname is %s %s", firstname, secondname);

  return 0;
}

1
假设您有一个char[fixed_size]而不是char*,您可以使用一个创意宏来完成所有操作,采用类似于<<cout<<like的顺序(“rather %s the disjointed %s\n”,“than”,“printf style format”)。如果您正在处理嵌入式系统,则此方法还将允许您省略malloc以及大型的*printf函数系列,例如snprintf()(这可避免dietlibc对*printf的抱怨)。
#include <unistd.h> //for the write example
//note: you should check if offset==sizeof(buf) after use
#define strcpyALL(buf, offset, ...) do{ \
    char *bp=(char*)(buf+offset); /*so we can add to the end of a string*/ \
    const char *s, \
    *a[] = { __VA_ARGS__,NULL}, \
    **ss=a; \
    while((s=*ss++)) \
         while((*s)&&(++offset<(int)sizeof(buf))) \
            *bp++=*s++; \
    if (offset!=sizeof(buf))*bp=0; \
}while(0)

char buf[256];
int len=0;

strcpyALL(buf,len,
    "The config file is in:\n\t",getenv("HOME"),"/.config/",argv[0],"/config.rc\n"
);
if (len<sizeof(buf))
    write(1,buf,len); //outputs our message to stdout
else
    write(2,"error\n",6);

//but we can keep adding on because we kept track of the length
//this allows printf-like buffering to minimize number of syscalls to write
//set len back to 0 if you don't want this behavior
strcpyALL(buf,len,"Thanks for using ",argv[0],"!\n");
if (len<sizeof(buf))
    write(1,buf,len); //outputs both messages
else
    write(2,"error\n",6);
  • 注意1,通常情况下不会像这样使用argv [0] - 只是一个例子
  • 注意2,您可以使用任何输出char *的函数,包括非标准函数(例如itoa()将整数转换为字符串类型)。
  • 注意3,如果您已经在程序中使用printf,则没有理由不使用snprintf(),因为编译后的代码会更大(但内联且速度显着更快)

1
这是我的解决方案。
#include <stdlib.h>
#include <stdarg.h>

char *strconcat(int num_args, ...) {
    int strsize = 0;
    va_list ap;
    va_start(ap, num_args);
    for (int i = 0; i < num_args; i++) 
        strsize += strlen(va_arg(ap, char*));

    char *res = malloc(strsize+1);
    strsize = 0;
    va_start(ap, num_args);
    for (int i = 0; i < num_args; i++) {
        char *s = va_arg(ap, char*);
        strcpy(res+strsize, s);
        strsize += strlen(s);
    }
    va_end(ap);
    res[strsize] = '\0';

    return res;
}

但是你需要指定要连接多少个字符串

char *str = strconcat(3, "testing ", "this ", "thing");

1
int main()
{
    char input[100];
    gets(input);

    char str[101];
    strcpy(str, " ");
    strcat(str, input);

    char *p = str;

    while(*p) {
       if(*p == ' ' && isalpha(*(p+1)) != 0)
           printf("%c",*(p+1));
       p++;
    }

    return 0;
}

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