如何在C中连接const / literalstring?

我在C工作,我必须连接几件事情。

现在我有这个:

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

现在,如果你有C的经验,我相信你会意识到,当你尝试运行它时,会给你一个分段错误。 那么我该如何解决这个问题呢?

在C中,“strings”只是简单的char数组。 因此,你不能直接连接他们与其他“string”。

您可以使用strcat函数,它将src指向的string附加到dest指向的string的末尾:

 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 ,使用像strcpy_sstrcat_s这样的函数strcpy_s strcat_s ,您必须明确指定目标缓冲区的大小。

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

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

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

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

 char *foo = "foo"; char *bar = "bar"; char str[80]; strcpy(str, "TEXT "); strcat(str, foo); strcat(str, bar); 

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

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

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

另外malloc和realloc是有用的,如果你不知道提前多less个string串联。

 #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); } 

伙计们,请使用strpypy(),str cat()或s printf()。
超出你的缓冲区空间将会破坏内存中的任何其他内容!
(并且记住为空的'\ 0'字符留出空间!)

string也可以在编译时连接在一起。

 #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 */ ; 

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

 char out[1024] = ""; // must be initialized strcat( out, null_terminated_string ); // null_terminated_string has less than 1023 chars 

strcat()的第一个参数需要能够为连接string保留足够的空间。 因此,分配一个足够空间的缓冲区来接收结果。

 char bigEnough[64] = ""; strcat(bigEnough, "TEXT"); strcat(bigEnough, foo); /* and so on */ 

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

你不会得到一个新分配的string连接的第一个和第二个参数,我猜你会根据你的代码预期。

正如人们指出,string处理有了很大的改进 所以你可能想学习如何使用C ++string库而不是C风格的string。 然而,这是一个纯C的解决scheme

 #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中find更好的方法。

最好的方法是在不限制缓冲区大小的情况下使用asprintf()

 char* concat(const char* str1, const char* str2) { char* result; asprintf(&result, "%s%s", str1, str2); return result; } 

尝试修改string文字是未定义的行为,就像是:

 strcat ("Hello, ", name); 

会试图做的。 它会尝试将stringstring"Hello, "的末尾的namestring,这是没有很好的定义。

试试这个。 它实现了你似乎试图做的事情:

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

这将创build一个允许修改的缓冲区,然后将string文字和其他文本复制到它。 只要注意缓冲区溢出。 如果你控制input数据(或者事先检查它),那么使用像我这样的固定长度的缓冲区就可以了。

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

 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. 

你可以编写你自己的函数,它和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; } 

如果两个string的长度超过1000个字符,则会将该string切割为1000个字符。 您可以更改MAX_STRING_LENGTH的值以满足您的需求。

假设你有一个char [fixed_size]而不是一个char *,你可以使用一个单一的创造性的macros来同时使用一个<<cout<<like命令(“而不是%s的不连贯的%s \ n” “than”,“printf style format”)。 如果你正在使用embedded式系统,这个方法也将允许你省去malloc和像printprint snprintf()这样的大型*printf函数(这使得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()这样的非标准函数来将整数转换为stringtypes。
  • 注意3,如果你已经在你的程序中的任何地方使用了printf,没有理由不使用snprintf(),因为编译后的代码会更大(但是内联和更快)
 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; } 

您正试图将一个string复制到静态分配的地址中。 你需要进入一个缓冲区。

特别:

…略…

目的地

 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

这里也有一个例子。

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

现在这是很不方便的,因为你必须find最后一个字符来追加一些东西。 strcat会为你做到这一点。

所以strcatsearch第一个参数为空字符。 然后它将用第二个参数的内容replace它(直到以null结尾)。

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

 message = strcat("TEXT " + var); 

在这里,你要添加一些东西到指向文本“TEXT”的指针(“TEXT”的types是const char *。指针)。

这通常不会工作。 同样修改“TEXT”数组也不会工作,因为它通常放置在一个常量段中。

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

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

我会build议做这样的事情,而不是:

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

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

而现在重要的一点是:

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

这是我的解决scheme

 #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; } 

但是你需要指定你要连接的string数量

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

尝试类似这样的事情:

 #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; }