如何在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_s
和strcat_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, "
的末尾的name
string,这是没有很好的定义。
试试这个。 它实现了你似乎试图做的事情:
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; }