如何连接两个字符串并保存在C中的第三个变量中?

时间:2018-07-26 15:09:44

标签: c

我已经定义了一个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语言添加具有一个实时更改变量的两个字符串的最佳方法是什么?

5 个答案:

答案 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是在本地分配给该函数的吗?在这种情况下,您应该考虑使用allocamalloc来获取适当大小的内存块,而不是依赖静态大小。您还需要处理这些函数中的错误。

此外,您应该始终选择安全的替代方案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;
}