realloc() не может перераспределить память

Я пишу программу копирования файлов, в которой я столкнулся с трудностями, связанными с realloc(). Пожалуйста, посмотрите на следующий фрагмент (который я пишу, чтобы понять работу realloc()): -

int main(){
    char *p =(char *) malloc ( 10 ),*t;
    p = "this is";
    if (strlen (p)==7)
    {
        t = realloc ( p,14);
        if ( t==NULL)
        {
            printf ("no no\n");
        }
    }
    printf("%p\n%p\n%d",p,t,strlen(p));
    free (p);
    free (t);
    return 1;
}

вывод

no no      //because realloc () is unable to reallocate  the memory
00450357   //address of p
00000000   //address of t

почему realloc() не может перераспределить память и присвоить ее (ее адрес) t?

EDIT я использую блоки кода в Windows.


person OldSchool    schedule 29.03.2014    source источник
comment
Потому что вы затерли адрес, возвращаемый malloc, присваиванием строки. Если бы вы использовали strcpy, то realloc сработал бы, но вы бы получили двойное освобождение для free(p), потому что оно уже было освобождено во время realloc.   -  person cup    schedule 29.03.2014


Ответы (3)


Вы перезаписали значение, возвращаемое malloc, адресом статической строки. Затем realloc получает адрес статической строки в качестве параметра для перераспределения.

char *p =(char *) malloc ( 10 ),*t;
p = "this is";
t = realloc ( p,14);

То, что вы, вероятно, хотели, это:

char *p =(char *) malloc ( 10 ),*t;
strcpy(p, "this is");
t = realloc ( p,14);
person Marian    schedule 29.03.2014
comment
Является ли он перезаписанным из-за его (строковых литералов) типа const char * - person OldSchool; 29.03.2014
comment
Оператор p = "this is"; означает, что где-то в памяти (и уж точно не в куче) находится строка this и ее адрес присвоен p. Строка создается компилятором во время компиляции и обычно располагается в части памяти, отведенной под константы, взятые из кода программы. - person Marian; 29.03.2014
comment
если мы используем целочисленный массив, тогда случай будет другим? - person OldSchool; 29.03.2014
comment
Не уверен, что понял смысл целочисленного массива. Дело в том, что вы должны вызывать realloc с указателем, полученным от malloc. В вашем случае вы получили указатель от malloc, но затем получили другой указатель (и присвоили его p) и вызвали realloc с этим другим указателем. - person Marian; 29.03.2014
comment
как я написал free() (в конце программы) как для p, так и для t. Ничего, если я напишу это только для t? - person OldSchool; 29.03.2014
comment
Не совсем. realloc освобождает p, но только в случае его вызова. В вашем примере вы должны освободить t в ветке, вызывающей realloc, и p в ветке, не вызывающей ее. - person Marian; 29.03.2014
comment
Трудно сказать проще. Ваша программа имеет две ветви. В одной ветке вы выделяете p, затем перераспределяете ее на t. В этой ветке нужно освободить только t. В другой ветке (если размер строки не равен 7) вы ничего не перераспределяете на t и вам нужно освободить p. - person Marian; 29.03.2014

После выделения p вы делаете

p = "this is";

который переопределяет значение, возвращаемое malloc(). И поскольку память, указанная p, не может быть освобождена, realloc() терпит неудачу.

Чтобы скопировать строку, выполните

strcpy(p, "this is");

хотя проверка p имеет достаточно выделенной памяти, в противном случае используйте

strncpy(p, "this is", length_of_p);
person Rohan    schedule 29.03.2014
comment
но если у нас есть указатель целочисленного типа для хранения указателя, возвращаемого malloc, и мы используем цикл для сохранения значения по этому адресу как *p++=2.тогда он также перераспределяемый, так почему здесь это не так? - person OldSchool; 29.03.2014

На справочной странице realloc указано, что если первый аргумент realloc не равен NULL, он должен быть возвращен более ранним вызовом malloc, calloc или realloc.

t = realloc (p, 14);

Приведенный выше оператор передает p в realloc, что указывает на строковый литерал "this is", который имеет статическую продолжительность хранения и доступен только для чтения, но не имеет квалификации const. Таким образом, ваша программа вызывает неопределенное поведение (на моей машине произошел сбой из-за segfault.)

Кроме того, вы теряете управление динамически выделяемой памятью, когда переназначаете p адрес первого элемента строкового литерала, вызывая утечку памяти.

char *p =(char *) malloc ( 10 ),*t;
p = "this is";

Что вам действительно нужно сделать, так это скопировать содержимое строкового литерала в динамически выделяемый буфер, используя strcpy.

// include the required headers

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// explicitly state void in the parameter list of main
int main(void) {
    // do not cast the result of malloc
    char *p = malloc(10 * sizeof *p);
    char *t;
    if(p == NULL) {
        printf("malloc failed\n");
        return 1;
    }
    // beware of buffer overrun by strcpy
    // consider using the safer strncpy if it suits
    p = strcpy(p, "this is");
    if(strlen(p) == 7) {
        // save the result of realloc in t
        // in case, realloc fails to allocate
        t = realloc(p, 14);
        if(t == NULL) {
            printf("realloc failed\n");
            // handle it
            // p points to old buffer
        }
        else {
            t = NULL;
            // p points to new buffer
        }
    }

    // after your done with p, free it
    free(p);

    return 0;
}
person ajay    schedule 29.03.2014
comment
если я напишу t=realloc ( p,14 ), значит ли это, что p будет освобожден, а t указывает на тот же начальный адрес, но его диапазон увеличится? - person OldSchool; 29.03.2014
comment
@Bayant_singh Нет. Если realloc выполнено успешно, возвращается то же значение, что и у p. Здесь мы сохраняем результат realloc в t, потому что если realloc терпит неудачу, то он оставляет p без изменений и возвращает NULL. Следовательно, выполнение p = realloc(p, 14); приведет к потере дескриптора старого буфера, что приведет к утечке памяти в случае сбоя realloc. - person ajay; 29.03.2014
comment
@Bayant_singh Также обратите внимание, что если realloc может расширить старый буфер, то так оно и будет. Если это невозможно, то он выделит новый буфер, скопирует старый буфер в новый, а затем освободит старый буфер. Следовательно, возвращаемое значение realloc может совпадать или не совпадать в случае успешного вызова. Пожалуйста, прочитайте справочную страницу для получения подробной информации man7.org/linux/man-pages /man3/malloc.3.html - person ajay; 29.03.2014
comment
но как я могу скопировать старый буфер в новый? - person OldSchool; 29.03.2014
comment
@Bayant_singh realloc сделает это за вас. Вот для чего он используется. Когда realloc выделяет память, он сохраняет старые данные. - person ajay; 29.03.2014
comment
Короче говоря, если я напишу t=realloc (p,14), t может указывать или не указывать на тот же начальный адрес, что и у p, по указанной вами причине. - person OldSchool; 29.03.2014