13

有人可以向我解释为什么我对字符串大小为 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);
}
4

8 回答 8

20

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

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

此外,这些行:

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

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

while(*copy++ = *str++);
于 2009-10-07T19:01:58.770 回答
5

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

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

但是要做你想做的(复制一个字符串并分配必要的空间),使用strdup会更简单、更有效,它就是这样做的:一个malloc和一个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。

于 2009-10-07T20:13:25.900 回答
3

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

于 2009-10-07T19:01:45.500 回答
3

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

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

于 2009-10-07T19:04:17.380 回答
2

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
于 2009-10-07T19:45:54.053 回答
1

为了解决你的第二个问题,通过执行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);
于 2009-10-07T19:09:41.407 回答
1
  • sizeof() 返回指针的大小而不是分配的字节数。您不需要计算分配的字节数,只需检查返回的指针是否不是NULL.
  • 线copy = '\0'; 重置指针并使其成为NULL.
于 2009-10-07T19:47:35.950 回答
-1

您可以使用:

size_t malloc_usable_size (void *ptr);

而不是:sizeof

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

于 2014-01-17T11:51:37.450 回答