我已经定义了一个char
数组,该数组具有以下预定义的HTTP帖子字符串:
char header[] = "POST /api/add HTTP/1.1\r\nHost: xxxxxxx:3000\r\nContent-Type: application/octet-stream; charset=utf-8\r\nContent-Length: 500\r\nName: ";
strcat(header, strDevicename); \\
strcat(header, "\r\n\r\n");
其中strDevicename
是一个char
变量名,每个请求都会更改。
问题是,当我第一次运行它时,它正在运行,但是之后用Name
覆盖了a96ed5ÿÿa96ed58e8355
。
在HTTP帖子标头中使用C语言添加具有一个实时更改变量的两个字符串的最佳方法是什么?
答案 0 :(得分:4)
在您的代码中,数组header
的大小由所提供的初始化程序字符串的大小决定,并且它没有任何额外的空间来存储(或附加 )其他字符。
引用C11
,第§6.7.9章
如果初始化了一个未知大小的数组,则其大小由索引最大的数组确定 带有显式初始化程序的元素。数组类型在其末尾完成 初始化程序列表。
接下来,对于strcat()
,来自第7.24.3.1章
strcat
函数附加由s2
指向的字符串的副本(包括 终止空字符)到s1
所指向的字符串的末尾。 [...]
表示目标s1
(此处为header
)应该有足够的存储空间来容纳串联的字符串。
因此,当您经过分配的内存时,尝试以strcat()
为源的header
会在此处调用未定义的行为。
在用初始化字符串填充header
后,需要留有足够的空间。对数组使用固定的大小,在使用初始化字符串填充数组后,该大小会很大,例如
#define STRSIZ 512
char header[STRSIZ] = "POST /api/add HTT.........
答案 1 :(得分:2)
来自man 3 strcat
:
字符串不能重叠,dest字符串必须有足够的空间容纳结果。如果dest不够大,则程序行为是不可预测的; 缓冲区溢出是攻击安全程序的最常用途径。
您需要确保为header
数组分配足够大的空间,以确保除了初始大小外还可以向其中写入strlen(strDeviceName) + 5
个字节;否则,您有一个(可能是远程利用的)缓冲区溢出漏洞。
大概header
是在本地分配给该函数的吗?在这种情况下,您应该考虑使用alloca
或malloc
来获取适当大小的内存块,而不是依赖静态大小。您还需要处理这些函数中的错误。
此外,您应该始终选择安全的替代方案strncat
而不是普通的strcat
,因为strncat
接受了一个附加参数来附加要添加的字节数,并确保缓冲区始终即使以其他方式发生溢出,也要以null终止。
答案 2 :(得分:0)
您需要为整个字符串分配足够的空间。 手册页:
char * strcat(char *restrict s1, const char *restrict s2);
The string s1 must have sufficient space to hold the result.
您可以按照“正确”的方式进行操作,并准确分配所需的内容:
char *buf;
char header[] = "POST /api/add HTTP/1.1\r\nHost: xxxxxxx:3000\r\nContent-Type: application/octet-stream; charset=utf-8\r\nContent-Length: 500\r\nName: "
buf = malloc(strlen(header)+strlen(strDeviceName)+strlen("\r\n\r\n")+1);
if(buf==NULL) abort();
strcpy(buf, header);
strcat(buf, strDevicename); \\
strcat(buf, "\r\n\r\n");
或者以懒惰的方式进行总体布置:
char header[1024] = "POST /api/add HTTP/1.1\r\nHost: xxxxxxx:3000\r\nContent-Type: application/octet-stream; charset=utf-8\r\nContent-Length: 500\r\nName: "
strcat(header, strDevicename); \\
strcat(header, "\r\n\r\n");
答案 3 :(得分:0)
问题是您正在[str]串联到一个没有多余空间(无法更改C数组大小)的数组(header
)。
snprintf
在这里可能更合适。
如果知道strDevicename
的最大可能长度,则可以使用固定大小的缓冲区:
const char header[] = "POST /api/add HTTP/1.1\r\nHost: xxxxxxx:3000\r\nContent-Type: application/octet-stream; charset=utf-8\r\nContent-Length: 500\r\nName: ";
const char tail[] = "\r\n\r\n";
char buf[(sizeof header - 1) + MAX_DEV_LENGTH + (sizeof tail - 1) + 1];
/* sizeof would count the null byte in header & tail arrays. */
snprintf(buf, sizeof buf, "%s%s%s", header, strDevicename, tail);
如果strDevicename
的长度未知,则可以使用asprintf
(GNU函数):
char *buf = NULL;
if (asprintf(&buf, "%s%s%s", header, strDevicename, tail) == -1) {
/* handle memory allocation failure */
}
...
free(buf);
如果asprintf
不可用,则可以使用malloc
自己分配足够的内存(如上所述),然后使用snprintf
。
答案 4 :(得分:0)
由于需要足够的空间,因此可以在新的空间中复制两个空间:
char *mystrcat(const char *src1, const *char src2)
{
char *dest
size_t src1Len = strlen(src1);
dest = malloc(src1Len + strlen(src2) + 1);
if(dest)
{
memcpy(dest, src1, src1Len);
strcpy(dest + src1Len, src2);
}
return dest;
}