提问人:Genata339 提问时间:12/16/2022 最后编辑:Genata339 更新时间:12/16/2022 访问量:52
Malloc,为字符串 [duplicate] 动态分配错误大小的内存
Malloc, dynamically allocating wrong size memory for a string [duplicate]
问:
int main() {
char A[200], B[200];
printf("Enter 2 words or sentences.\n");
gets(A);
gets(B);
char* C = (char*)malloc((strlen(A) + strlen(B)) * sizeof(char));
for (int i = 0; i < strlen(A); i++)
C[i] = A[i];
for (int i = 0; i < strlen(B); i++)
C[i + strlen(A)] = B[i];
printf("%s", C);
}
的初始值是 ,比请求的长 4 个符号,并且 4 个符号在打印时也显示为输出。我不知道为什么有 4 个符号,这就是我在这里寻求解释的原因。C
ÍÍÍÍÍÍÍÍÍÍýýýý
C
答:
1赞
cHao
12/16/2022
#1
malloc
只是返回一个指向它为您分配的一些内存的指针。它不会初始化该内存,将其清零或类似的东西。所以当你把它打印出来时,你看到的是以前那里的垃圾。
坦率地说,你很幸运,你没有打开虫洞什么的。C 字符串是以 nul 结尾的,因此当您传递该指针时,从技术上讲,您还没有传递字符串。当你把它传递给一个需要字符串的函数时,各种古怪的事情都会随之而来。
您应该在获得内存时对其进行初始化。最简单的初始化是类似 or ,它将内存转换为零长度字符串。但是你可能已经有东西要放在那里了,或者你为什么要首先分配内存?:P*C = '\0';
C[0] = '\0';
现在有了代码,我们可以稍微调整一下来解决这个问题......
int main() {
char A[200], B[200];
printf("Enter 2 words or sentences.\n");
// BTW: you should never, ever be using `gets`.
// use `fgets` and pass the size of your buffer to avoid overruns.
// note: it returns a null pointer if it fails...at which point you
// can't trust that A and B are strings, and should probably bail
if (!fgets(A, sizeof A, stdin)) return 1;
if (!fgets(B, sizeof B, stdin)) return 1;
// you don't want to call `strlen` over and over. save these lengths
size_t Alen = strlen(A);
size_t Blen = strlen(B);
// lop off the newlines
if (Alen && A[Alen - 1] == '\n') A[--Alen] = '\0';
if (Blen && B[Blen - 1] == '\n') B[--Blen] = '\0';
// You need enough space for both strings, plus a nul at the end.
// side note: you don't need to cast the pointer to a `char *`.
// also, sizeof(char) is 1 by definition, so no need to multiply by it.
char* C = malloc(Alen + Blen + 1);
if (!C) return 1;
// compare to the length variable instead
for (int i = 0; i < Alen; i++)
C[i] = A[i];
for (int i = 0; i < Blen; i++)
C[i + Alen] = B[i];
// important: nul-terminate the string
C[Alen + Blen] = '\0';
printf("%s", C);
// not strictly necessary at the end of main on a modern OS, but
// you should free what you malloc
free(C);
}
评论
1赞
cHao
12/16/2022
@chux : ooo....狡猾。甚至没有考虑给 stdin 喂一个 nul。:P谢谢
-1赞
Genata339
12/16/2022
#2
C[strlen(A) + strlen(B)] = '\0';
在摆脱垃圾之后,感谢大家的想法。malloc
评论
2赞
Lundin
12/16/2022
不,它没有,因为您尚未为该数组位置分配空间。所以你越界访问数组,如果它有效,那纯粹是运气。
3赞
chux - Reinstate Monica
12/16/2022
#3
问题:
非 null 字符终止
代码尝试,这是未定义的行为,因为不是 所需的字符串。printf("%s", C);
C[]
"%s"
// Append a \0
C[strlen(A) + strlen(B)] = '\0';
分配的内存不足
为 null 字符腾出空间。
// (strlen(A) + strlen(B)) * sizeof(char)
strlen(A) + strlen(B) + 1
自 C11 以来,gets()
不再是标准 C 库的一部分
使用并消除类似行为的潜在尾随。fgets()
'\n'
int
与 size_t
int
对于很长的字符串来说是不够的。 适用于所有字符串。size_t
避免可能重新计算字符串长度
int main(void) {
char A[200], B[200];
printf("Enter 2 words or sentences.\n");
// Code should check the return value of fgets()
// Omitted for brevity.
fgets(A, sizeof A, stdin);
A[strcspn(A, "\n")] = '\0'; // Lop off potential \n
fgets(B, sizeof B, stdin);
B[strcspn(B, "\n")] = '\0';
size_t A_len = strlen(A);
size_t B_len = strlen(B);
char* C = malloc(A_len + B_len + 1);
if (C) {
for (size_t i = 0; A[i]; i++) {
C[i] = A[i];
}
for (size_t i = 0; B[i]; i++) {
C[A_len + i] = B[i];
}
C[A_len + B_len + i] = '\0';
printf("%s\n", C);
free(C); // Good housekeeping to free allocations.
}
}
评论
0赞
cHao
12/16/2022
极端情况:如果失败,则无法知道缓冲区中有什么。fgets
0赞
chux - Reinstate Monica
12/16/2022
@cHao 几乎正确。当由于输入错误而返回时,是不确定的。当由于文件末尾而返回时,保持不变。IAC,检查返回值更健壮。fgets(A)
NULL
A[]
fgets(A)
NULL
A[]
fgets()
评论
gets
函数如此危险,以至于不应该使用它?