【问题标题】:newbie questions about malloc and sizeof关于 malloc 和 sizeof 的新手问题
【发布时间】:2021-06-23 13:27:44
【问题描述】:

有人可以向我解释为什么我对字符串大小为 6 的 malloc 调用返回的 sizeof 为 4 个字节吗?事实上,我给 malloc 的任何整数参数都会得到一个 4 的 sizeof。接下来,我试图复制两个字符串。为什么我的复制字符串的输出是(NULL)? 以下是我的代码:

int main()
{
    char * str = "string";
    char * copy = malloc(sizeof(str) + 1);
    printf("bytes allocated for copy: %d\n", sizeof(copy));
    while(*str != '\0'){
        *copy = *str;
        str++;
        copy++;
    }
    copy = '\0';
    printf("%s\n", copy);
}

【问题讨论】:

  • copy='\0' 应该是 *copy='\0'

标签: c malloc sizeof


【解决方案1】:

您得到的是 str 指针 的大小(4 个字节),而不是它所指向的大小?

【讨论】:

  • 为什么是问号?你不确定你的答案;)这是正确的。 :)
  • 并非如此。它指向的内容(即char 类型)的大小是1,这更没用。您需要@AraK 的答案中的字符串长度。
【解决方案2】:

sizeof(str) 返回char* 类型指针的大小。你应该做的是malloc它自己的字符串的大小:

char * copy = malloc(strlen(str) + 1);

另外,这些行:

while(*str != '\0'){
        *copy = *str;
        str++;
        copy++;
}
copy = '\0';

可以像这样在 C 中轻松重写:

while(*copy++ = *str++);

【讨论】:

  • 它们也可以重写为strcpy(copy, str);,这可能比你现在的效率更高。
  • @Chris 哎呀。我重新发明了轮子:)
  • @AraK:同意。 C中一个很常见的习语
  • 常用成语代码也容易出错。我会用{} 或更好的continue; 语句替换空的';' null 语句。是的,@Lutz、strcpy() 可能更高效且更具可读性。
  • copy='\0' 应该是 *copy='\0'
【解决方案3】:

sizeof(str) 返回存储指向字符串的指针所需的空间,而不是字符串本身。例如,您可以使用strlen(str) 查看字符串的大小。

然后你将copy 指针指向一个值为0 的整数(字符'\0')。它与copy = NULL 相同,即 printf() 函数向您显示的内容。

【讨论】:

    【解决方案4】:

    要解决您的第二个问题,通过执行语句copy++,您已经更改了copy 的值(即内存中包含char 数组的地址),以便在您打印出来时,它指向数组的末尾而不是开头(malloc() 返回的值)。您将需要一个额外的变量来更新字符串并且能够访问字符串的开头:

    编辑以修复 malloc/sizeof 问题 - 感谢 CL。

    char * str = "string";
    /*   char * copy = malloc(sizeof(str) + 1);  Oops  */
    char * copy = malloc(strlen(str) + 1);
    char * original_copy = copy;
    printf("bytes allocated for copy: %d\n", sizeof(copy));
    while(*str != '\0'){
        *copy = *str;
        str++;
        copy++;
    }
    copy = '\0';
    printf("%s\n", original_copy);
    

    【讨论】:

    • malloc(sizeof(str) + 1)还有一个问题——sizeof(str)sizeof(char *)在大多数平台上是4,和字符串的长度无关。
    • 啊!我忘记了,因为我增加了指针 printf 正在打印我在末尾附加的空字符,而不是整个字符串。非常感谢。
    • copy='\0' 应该是 *copy='\0'
    【解决方案5】:

    sizeof() 返回变量实际类型的大小。因此,当您将类型定义为 char * 时,它会返回指针的大小。

    但是如果你把你的变量设为一个数组,sizeof 会返回数组本身的大小,这会做你想做的事:

    char *ptr = "moo to you";
    char arr[] = "moo to you";
    
    assert(sizeof(ptr) == 4);   // assuming 32 bit
    assert(sizeof(arr) == 11);  // sizeof array includes terminating NUL
    assert(strlen(arr) == 10);  // strlen does not include terminating NUL
    

    【讨论】:

    • 为了对称和完整性,您应该包含assert(strlen(ptr) == 10);
    【解决方案6】:
    • sizeof() 返回指针的大小,而不是分配的字节数。你不需要统计分配的字节数,只要检查返回的指针是否不是NULL即可。
    • 线copy = '\0';重置指针并使其变为NULL

    【讨论】:

    • 此时指针已经递增,所以不就是让字符串的最后一个字节指向空吗?
    • @unknown - 不,您遗漏了取消引用运算符。你想要的是*copy = '\0',因为copy = '\0' 将指针设置为'\0'(即NULL 作为int 类型)。
    【解决方案7】:

    首先你应该明白 sizeof(xxx) 其中 xxx 是任何左值表达式(一个变量)总是等价于 do sizeof(type of xxx )。因此,您的 sizeof(str) 真正在做的是返回 char * 的大小,即任何其他指针的大小。在 32 位架构上,您将获得 4,在 64 位架构上,您将获得 8,等等。

    所以,正如其他人也解释的那样,您必须知道要分配的字符串的长度,然后加1来存储终端\ 0,C隐式使用放在字符串的末尾。

    但是要做你想做的事(复制一个字符串并分配必要的空间),使用 strdup 会更简单、更有效,这正是这样做的:a ma​​lloc 和一个 strcopy

    您也不应该忘记释放您自己分配的空间(使用 malloc、calloc、strdup 或任何其他分配函数)。在 C 中,当分配的变量超出范围时,它不会消失。它将一直使用到程序结束。这就是你所说的内存泄漏。

    #include <string.h> /* for strdup, strlen */
    #include <stdio.h> /* for printf */
    
    int main()
    {
        char * str = "string";
        char * copy = strdup(str);
        printf("bytes at least allocated for copy: %d\n", strlen(copy)+1);
        printf("%s\n", copy);
        free(copy);
    }
    

    最后一点:我将消息更改为 至少分配的字节数,因为您并不真正知道调用 malloc 时分配的大小。它通常会分配比您要求的更多的空间。一个原因是在许多内存管理器中,空闲块使用一些隐藏的数据结构链接在一起,并且任何分配的块都应该能够包含至少这样的结构,另一个原因是分配的块总是以与任何类型兼容的方式对齐对齐。

    希望它能帮助你更好地理解 C。

    【讨论】:

    • 对于它的价值,strdup() 是一个非标准函数,但它非常容易推出你自己的,这没什么大不了的。
    • 是的,你说得对,它不是 C 的标准,甚至 C99,但很常见(你会在 ISO C++ 中获得 _strdup、_wcsdup 和其他一些)。另一方面,库实现通常是相当优化的,并不像看起来那么简单。我检查了 Linux strdup 上的 gcc 是否比 while 循环快 30%,比我能想到的第二好的解决方案(malloc 然后 strncpy)快近 8%。它也更容易阅读。最大的缺点是 malloc 是隐藏的,因此程序员经常忘记释放 strduped var。 :-(
    【解决方案8】:

    你可以使用:

    size_t malloc_usable_size (void *ptr);

    而不是:sizeof

    但它返回分配的内存块的实际大小!不是您传递给 malloc 的大小!

    【讨论】:

    猜你喜欢
    • 2011-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-29
    • 1970-01-01
    • 2011-02-01
    • 2011-02-17
    相关资源
    最近更新 更多