Malloc,为字符串 [duplicate] 动态分配错误大小的内存

Malloc, dynamically allocating wrong size memory for a string [duplicate]

提问人:Genata339 提问时间:12/16/2022 最后编辑:Genata339 更新时间:12/16/2022 访问量:52

问:

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

数组 c char malloc sizeof

评论

0赞 pm100 12/16/2022
malloc 返回的内存包含垃圾,您必须将其设置为某些东西,printf(我假设您正在这样做)在单一化内存上产生未定义的行为
0赞 Genata339 12/16/2022
我给出前 10 个符号的值并打印整个字符串,我希望只包含 10 个符号。
0赞 pm100 12/16/2022
由于您没有显示任何代码 a) 加载值或 b) 打印,因此很难找出您的问题所在。我的猜测,您使用的是 %s 输出并且没有 0 终止。请在问题中发布您的所有代码
1赞 Oka 12/16/2022
强制性:为什么 gets 函数如此危险,以至于不应该使用它?

答:

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'

intsize_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)NULLA[]fgets(A)NULLA[]fgets()