вопросы новичка о malloc и sizeof - PullRequest
       22

вопросы новичка о malloc и sizeof

8 голосов
/ 07 октября 2009

Может кто-нибудь объяснить мне, почему мой вызов malloc с размером строки 6 возвращает размер 4 байта? Фактически, любой целочисленный аргумент, который я даю malloc, получает размер 4. Затем я пытаюсь скопировать две строки. Почему мой вывод скопированной строки (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);
}

Ответы [ 8 ]

17 голосов
/ 07 октября 2009

sizeof(str) возвращает размер указателя типа char*. Что вам нужно сделать, это malloc размер строки, которую он сам:

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

Также эти строки:

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

Можно легко переписать на С, например:

while(*copy++ = *str++);
4 голосов
/ 08 октября 2009

Во-первых, вы должны понимать, что sizeof (xxx), где xxx - любое выражение левого значения (переменная), всегда эквивалентно типу sizeof () типа xxx * 1006. *). Следовательно, то, что действительно делает ваш sizeof (str), возвращает размер char *, то есть размер любого другого указателя. В 32-битной архитектуре вы получите 4, в 64-битной архитектуре это будет 8 и т. Д.

Итак, как и другие объяснили, вы должны знать длину строки, которую вы хотите выделить, а затем добавить 1 для хранения терминала \ 0, C неявно используется для помещения в конец строк.

Но чтобы делать то, что вы хотите (скопировать строку и выделить необходимое пространство), будет проще и эффективнее использовать strdup , который делает именно это: a malloc и a 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.

3 голосов
/ 07 октября 2009

Вы получаете размер указателя str (4 байта), а не то, на что он указывает?

2 голосов
/ 07 октября 2009

sizeof(str) возвращает пространство, необходимое для хранения указателя на строку, а не самой строки. Вы можете увидеть размер строки, например, strlen(str).

Затем вы воздействуете на copy указатель на целое число со значением 0 (символ '\0') Это то же самое, что и copy = NULL, что показывает функция printf ().

1 голос
/ 07 октября 2009
  • sizeof () возвращает вам размер указателя, а не количество выделенных байтов. Вам не нужно считать выделенные байты, просто проверьте, не является ли возвращенный указатель NULL.
  • Линия copy = '\0'; сбрасывает указатель и делает его NULL.
1 голос
/ 07 октября 2009

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
1 голос
/ 07 октября 2009

Чтобы ответить на ваши вторые вопросы, выполнив инструкцию 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);
0 голосов
/ 17 января 2014

Вы можете использовать:

size_t malloc_usable_size (void * ptr);

вместо: sizeof

Но он возвращает реальный размер выделенного блока памяти! Не тот размер, который вы передали malloc!

...