好吧所以我有以下代码在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#中那样做吗?
答案 0 :(得分:19)
更改
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");
,首先分配1K om内存,完全专用于x。然后你将“hello”复制到其中,并在最后留下相当多的空间来附加更多的字符串。在你追加超过1K的允许数量之前,你不会遇到麻烦。
结束附录(Pax):
答案 1 :(得分:8)
我想知道为什么没有人提到snprintf()
来自stdio.h
。这是输出多个值的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()
缓冲区!
答案 2 :(得分:6)
从使用更安全的strncat
功能开始。通常总是使用更安全的'n'函数,如果字符串的大小大于特定大小,则不会溢出。
在C中你需要自己处理字符串大小。因此,您需要知道生成的字符串有多大并适应它。如果您知道左侧所有字符串的大小,您应该创建一个足以容纳结果字符串的缓冲区。
答案 3 :(得分:2)
消息指向您无法写入的char const [],但这正是strcat编写的地方。你需要malloc()一个足够大的缓冲区。
答案 4 :(得分:1)
如前所述,您必须写入足够大的缓冲区。不幸的是,这样做是一项额外的工作。处理字符串的大多数C应用程序使用动态可调整大小的字符串缓冲区来进行连接。
glib包含了这个glib strings的实现,我建议将其用于任何严重使用字符串的应用程序。它使管理内存更容易,并防止缓冲区溢出。
答案 5 :(得分:1)
还没有看到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, the rest of string.h
答案 6 :(得分:-2)
以经典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类型(零终止)字符串的语言会这样做(除了大多数这些语言都内置了垃圾收集)。