在C中使用strcat

好的,所以我有下面的代码在C#中将一个字符串附加到另一个,注意这只是一个例子 ,所以在C#中给出替代字符串连接方法并不是必须的,这只是为了简化示例。

string Data = ""; Data +="\n\nHTTP/1.1 " + Status_code; Data += "\nContent-Type: " + Content_Type; Data += "\nServer: PT06"; Data += "\nContent-Length: " + Content_Lengt; Data += "\nDate: " + Date; Data += "\n" + HTML; 

现在我想在C中做同样的事情,我试图通过以下方式做到这一点

 time_t rawtime; time ( &rawtime ); char *message = "\n\nHTTP/1.1 "; message = strcat(message, Status_code); message = strcat(message, "\nContent-Type: "); message = strcat(message, Content_Type); message = strcat(message, "\nServer: PT06"); message = strcat(message, "\nContent-Length: "); message = strcat(message, Content_Lengt); message = strcat(message, "\nDate: "); message = strcat(message, ctime(&rawtime)); message = strcat(message, "\n"); message = strcat(message, HTML); 

现在,这给了我一个Segment故障,我知道为什么,我访问和读取内存,我不应该。 但问题是,我该如何解决? 我可以使用string.h,就像我在C#中那样做吗?

更改

 char *message = "\n\nHTTP/1.1 "; 

 char message[1024]; strcpy(message,"\n\nHTTP/1.1 "); 

你应该没问题,总消息长度为1023。

编辑:(根据mjy的评论)。 以这种方式使用strcat是获得缓冲区溢出的好方法。 您可以随时编写一个小函数来检查缓冲区的大小和传入字符串添加的长度以克服此问题,或者在动态缓冲区上使用realloc。 IMO,程序员有责任检查使用它们的正确缓冲区大小,就像sprintf和其他C字符串函数一样。 我假设出于性能原因,C正在使用C ++,因此STL不是一个选项。

编辑:根据Filip评论的请求,一个基于固定大小的char缓冲区的简单strcat实现:

 char buffer[MAXSIZE] = ""; int mystrcat(char *addition) { if (strlen(buffer) + strlen(addition) + sizeof(char) >= MaxSize) return(FAILED); strcat(buffer,addition); return(OK); } 

使用动态分配:

 char *buffer = NULL; int mystrcat(char *addition) { buffer = realloc(buffer, strlen(buffer) + strlen(addition) + sizeof(char)); if (!buffer) return(FAIL); strcat(buffer, addition); return(OK); } 

在这种情况下,您必须在完成后手动释放缓冲区。 (由C ++等价物中的析构函数处理)

附录(Pax):

好的,既然你没有真正解释为什么你必须创建message[1024] ,这里就是。

使用char * x =“hello”时,实际字节(’h’,’e’,’l’,’l’,’o’,0)(末尾为null)存储在与内存区分开的区域中变量(很可能是只读的)和变量x设置为指向它。 在null之后,可能还有其他非常重要的东西。 所以你根本无法附加。

char x[1024]; strcpy(x,"hello"); char x[1024]; strcpy(x,"hello"); ,你首先分配1K om内存,完全专用于x。 然后你将“hello”复制到其中,并在最后留下相当多的空间来附加更多的字符串。 在你追加超过1K的允许数量之前,你不会遇到麻烦。

最终附录(Pax):

我想知道为什么没有人提到stdio.h中的snprintf() 。 这是输出多个值的C方式,您甚至不必事先将基元转换为字符串。

以下示例使用堆栈分配的固定大小的缓冲区。 否则,你必须malloc()缓冲区(并存储它的大小),这将使溢出realloc()成为可能…

 char buffer[1024]; int len = snprintf(buffer, sizeof(buffer), "%s %i", "a string", 5); if(len < 0 || len >= sizeof(buffer)) { // buffer too small or error } 

编辑:您也可以考虑使用asprintf()函数。 它是广泛使用的GNU扩展,是TR 24731-2的一部分(这意味着它可能会成为下一个C标准)。 上面的例子将会读到

 char * buffer; if(asprintf(&buffer, "%s %i", "a string", 5) < 0) { // (allocation?) error } 

记得使用它时free()缓冲区free()

从使用更安全的strncat函数开始。 通常总是使用更安全的’n’函数,如果字符串的大小大于特定大小,则不会溢出。

在C中,您需要自己处理字符串大小。 因此,您需要知道生成的字符串有多大并适应它。 如果你知道左侧所有字符串的大小,你应该创建一个足够大的缓冲区来保存结果字符串。

消息指向一个你无法写入的char const [],但这正是strcat编写的地方。 你需要malloc()一个足够大的缓冲区。

如前所述,您必须写入足够大的缓冲区。 不幸的是,这样做是一项额外的工作。 大多数处理字符串的C应用程序使用动态可resize的字符串缓冲区来进行连接。

glib包含了一个glib字符串的实现,我建议将其用于任何使用字符串的应用程序。 它使管理内存更容易,并防止缓冲区溢出。

还没有看到strlcpy,strlcat函数的提及,它类似于’n’函数,除了还考虑了尾部0.两者都取第三个参数表示输出缓冲区的最大长度,可以在string.h中找到。

例:

 char blah[]="blah"; char buffer[1024]; strlcpy(buffer,"herro!!!",sizeof(buffer)); strlcat(buffer,blah,sizeof(buffer)); printf("%s\n",buffer); 

将输出“herro !!! blah”

 char blah[]="blah"; char buffer[10]; strlcpy(buffer,"herro!!!",sizeof(buffer)); strlcat(buffer,blah,sizeof(buffer)); printf("%s\n",buffer); 

由于缓冲区[]的大小有限,将输出“herro !!! b”,没有segfaulting。 ^^

唯一的问题并不是所有平台似乎都将它包含在他们的libc中(例如linux ._。),大多数BSD变种似乎都有它。

在这种情况下,可以在这里找到这两个函数的代码并轻松添加: strlcpy , strlcat , string.h的其余部分

以经典C风格执行此操作的安全方法是:

  char *strconcat(char *s1, char *s2) { size_t old_size; char *t; old_size = strlen(s1); /* cannot use realloc() on initial const char* */ t = malloc(old_size + strlen(s2) + 1); strcpy(t, s1); strcpy(t + old_size, s2); return t; } ... char *message = "\n\nHTTP/1.1 "; message = strconcat (message, Status_code); message = strconcat (message, "\nContent-Type: "); 

现在你可以说很多关于它的坏事:它效率低下,它会破坏你的记忆,它很难看……但它或多或少都是字符串连接运算符和C类型(零终止)字符串的语言(除了大多数这些语言都内置了垃圾收集)。