404

我在 C 中工作,我必须连接一些东西。

现在我有这个:

message = strcat("TEXT ", var);

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

现在,如果您有 C 方面的经验,我相信您会意识到,当您尝试运行它时,这会给您带来分段错误。那么我该如何解决呢?

4

17 回答 17

450

在 C 中,“字符串”只是普通char数组。因此,您不能直接将它们与其他“字符串”连接起来。

您可以使用该strcat函数,它将指向的字符串附加到指向的字符串src的末尾dest

char *strcat(char *dest, const char *src);

这是来自 cplusplus.com 的示例

char str[80];
strcpy(str, "these ");
strcat(str, "strings ");
strcat(str, "are ");
strcat(str, "concatenated.");

对于第一个参数,您需要提供目标缓冲区本身。目标缓冲区必须是 char 数组缓冲区。例如:char buffer[1024];

确保第一个参数有足够的空间来存储您要复制的内容。如果您可以使用,使用以下函数会更安全:strcpy_s并且strcat_s您必须明确指定目标缓冲区的大小。

注意:字符串文字不能用作缓冲区,因为它是一个常量。因此,您总是必须为缓冲区分配一个字符数组。

的返回值strcat可以简单地忽略,它只返回与作为第一个参数传入的指针相同的指针。它是为了方便起见,并允许您将调用链接到一行代码中:

strcat(strcat(str, foo), bar);

所以你的问题可以解决如下:

char *foo = "foo";
char *bar = "bar";
char str[80];
strcpy(str, "TEXT ");
strcat(str, foo);
strcat(str, bar);
于 2008-11-21T13:13:29.470 回答
271

避免strcat在 C 代码中使用。最干净,最重要的是,最安全的方法是使用snprintf

char buf[256];
snprintf(buf, sizeof(buf), "%s%s%s%s", str1, str2, str3, str4);

一些评论者提出了一个问题,即参数的数量可能与格式字符串不匹配,代码仍然可以编译,但如果是这种情况,大多数编译器已经发出警告。

于 2008-11-21T13:21:28.737 回答
42

字符串也可以在编译时连接。

#define SCHEMA "test"
#define TABLE  "data"

const char *table = SCHEMA "." TABLE ; // note no + or . or anything
const char *qry =               // include comments in a string
    " SELECT * "                // get all fields
    " FROM " SCHEMA "." TABLE   /* the table */
    " WHERE x = 1 "             /* the filter */ 
                ;
于 2015-09-19T08:22:13.147 回答
27

伙计们,使用 str n cpy()、str n cat() 或 s n printf()。
超出缓冲区空间将丢弃内存中的任何其他内容!
(请记住为结尾的 null '\0' 字符留出空间!)

于 2008-11-21T13:33:04.673 回答
16

如果您事先不知道要连接多少个字符串,那么 malloc 和 realloc 也很有用。

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

void example(const char *header, const char **words, size_t num_words)
{
    size_t message_len = strlen(header) + 1; /* + 1 for terminating NULL */
    char *message = (char*) malloc(message_len);
    strncat(message, header, message_len);

    for(int i = 0; i < num_words; ++i)
    {
       message_len += 1 + strlen(words[i]); /* 1 + for separator ';' */
       message = (char*) realloc(message, message_len);
       strncat(strncat(message, ";", message_len), words[i], message_len);
    }

    puts(message);

    free(message);
}
于 2008-11-21T15:29:06.450 回答
6

没有限制缓冲区大小的最佳方法是使用 asprintf()

char* concat(const char* str1, const char* str2)
{
    char* result;
    asprintf(&result, "%s%s", str1, str2);
    return result;
}
于 2013-04-08T02:23:41.777 回答
5

尝试修改字符串文字是未定义的行为,类似于:

strcat ("Hello, ", name);

会尝试做。它将尝试将字符串附加到未明确定义name的字符串字面量的末尾。"Hello, "

试试这个。它实现了您似乎想要做的事情:

char message[1000];
strcpy (message, "TEXT ");
strcat (message, var);

这将创建一个允许修改的缓冲区,然后将字符串文字和其他文本复制到其中。请注意缓冲区溢出。如果您控制输入数据(或事先检查),则可以像我一样使用固定长度的缓冲区。

否则,您应该使用缓解策略,例如从堆中分配足够的内存以确保您可以处理它。换句话说,类似:

const static char TEXT[] = "TEXT ";

// Make *sure* you have enough space.

char *message = malloc (sizeof(TEXT) + strlen(var) + 1);
if (message == NULL)
     handleOutOfMemoryIntelligently();
strcpy (message, TEXT);
strcat (message, var);

// Need to free message at some point after you're done with it.
于 2008-11-21T13:14:49.310 回答
5

如果您有 C 经验,您会注意到字符串只是最后一个字符为空字符的字符数组。

现在这很不方便,因为您必须找到最后一个字符才能附加一些东西。strcat会为你做的。

因此 strcat 在第一个参数中搜索空字符。然后它将用第二个参数的内容替换它(直到以 null 结尾)。

现在让我们来看看你的代码:

message = strcat("TEXT " + var);

在这里,您正在向指向文本“TEXT”的指针添加一些内容(“TEXT”的类型是 const char*。一个指针。)。

这通常是行不通的。修改“TEXT”数组也不起作用,因为它通常放置在一个常量段中。

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

这可能会更好,除非您再次尝试修改静态文本。strcat 没有为结果分配新内存。

我建议改为这样做:

sprintf(message2, "TEXT %s TEXT %s", foo, bar);

阅读文档sprintf以检查它的选项。

现在很重要的一点:

确保缓冲区有足够的空间来容纳文本和空字符。有几个函数可以帮助您,例如 strncat 和 printf 的特殊版本,它们为您分配缓冲区。不确保缓冲区大小将导致内存损坏和可远程利用的错误。

于 2008-11-21T13:31:50.197 回答
5

不要忘记初始化输出缓冲区。strcat 的第一个参数必须是一个以空结尾的字符串,并为结果字符串分配足够的额外空间:

char out[1024] = ""; // must be initialized
strcat( out, null_terminated_string ); 
// null_terminated_string has less than 1023 chars
于 2008-11-21T13:41:10.537 回答
5

正如人们指出的那样,字符串处理得到了很大改善。因此,您可能想学习如何使用 C++ 字符串库而不是 C 样式的字符串。但是,这是纯 C 的解决方案

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

void appendToHello(const char *s) {
    const char *const hello = "hello ";

    const size_t sLength     = strlen(s);
    const size_t helloLength = strlen(hello);
    const size_t totalLength = sLength + helloLength;

    char *const strBuf = malloc(totalLength + 1);
    if (strBuf == NULL) {
        fprintf(stderr, "malloc failed\n");
        exit(EXIT_FAILURE);
    }

    strcpy(strBuf, hello);
    strcpy(strBuf + helloLength, s);

    puts(strBuf);

    free(strBuf);

}

int main (void) {
    appendToHello("blah blah");
    return 0;
}

我不确定它是否正确/安全,但现在我找不到在 ANSI C 中执行此操作的更好方法。

于 2011-12-07T20:04:42.090 回答
3

strcat() 的第一个参数需要能够为连接的字符串保留足够的空间。所以分配一个有足够空间的缓冲区来接收结果。

char bigEnough[64] = "";

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

/* and so on */

strcat() 会将第二个参数与第一个参数连接起来,并将结果存储在第一个参数中,返回的 char* 就是第一个参数,只是为了您的方便。

您没有得到连接第一个和第二个参数的新分配的字符串,我猜您根据您的代码预期。

于 2008-11-21T13:14:58.080 回答
2

您正在尝试将字符串复制到静态分配的地址中。您需要 cat 进入缓冲区。

具体来说:

……剪……

目的地

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

这里也有一个例子。

于 2008-11-21T13:17:54.080 回答
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以满足您的需要。

于 2016-07-29T12:39:36.287 回答
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;
}
于 2014-04-10T12:41:55.440 回答
1

假设你有一个 char[fixed_size] 而不是一个 char*,你可以使用一个单一的、创造性的宏来一次完成所有的<<cout<<like排序(“而不是 %s 脱节的 %s\n”、“than”、“printf样式格式”)。如果您正在使用嵌入式系统,此方法还允许您省略 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(),因为编译后的代码会更大(但内联且速度明显更快)
于 2014-12-14T06:54:32.390 回答
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;
}
于 2016-11-04T21:10:35.723 回答
0

这是我的解决方案

#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");
于 2016-12-31T16:41:21.173 回答