Realloc просто ничего не понимает, не ошибается

У меня есть следующий код:

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

int main(int argc, char ** argv)
{
    //just checking to see where the stack 
    printf("The stack is around %p\n", &argc); is, making sure arr isn't in it
    char ** arr = malloc(8*sizeof(char*));
    printf("arr is size %li, at %p\n", sizeof(arr), arr);
    arr = realloc(arr, 100); //I picked a weird number to show it isn't doing anything. I've picked different numbers (like 200, 2*sizeof(char*)*sizeof(arr), and 16)
    printf("arr is size %li, at %p\n", sizeof(arr), arr);
}

Это весь файл (это модульный тест, я заметил его в другом месте)

Вывод вышеизложенного выглядит следующим образом:

The stack is around 0x7fff5b94d12c
arr is size 8, at 0x120f010
arr is size 8, at 0x120f010

Возможно, я неправильно понимаю, что должен делать realloc. Я ожидаю следующего результата.

The stack is around 0x7fff5b94d12c
arr is size 8, at 0x120f010
arr is size <size>, at <somewhere>

где <size> это... что-то странное вроде 12... по крайней мере, не 8, а <somewhere> скорее всего 0x120f010, но, возможно, в любом разумном месте.

Мои ожидания неверны или я неправильно использую realloc?


person River Tam    schedule 26.01.2014    source источник
comment
Настоящая проблема в том, что вы неправильно понимаете sizeof...   -  person Oliver Charlesworth    schedule 26.01.2014
comment
Вы правы, я. Спасибо... теперь нужно отладить исходную программу.   -  person River Tam    schedule 26.01.2014


Ответы (4)


Вывод вашей программы правильный, потому что

  • Ни malloc, ни realloc не имеют ничего общего с автоматическим хранилищем (то есть «стеком»). Они выделяют память из области динамического хранения (то есть «кучи»). Не следует ожидать, что положение вершины стека изменится в ответ на вызовы malloc, realloc или любой другой функции.
  • Значение sizeof(arr) не зависит от того, что вы ему выделили. Он вычисляется во время компиляции и всегда равен размеру указателя. В вашей системе указатели используют 8 байтов.
  • malloc часто дает вам больше памяти, чем вы просите, и сохраняет фактическое значение в специальном месте, к которому realloc может получить доступ позже. Если вы realloc вниз или realloc в пределах границ, значение, возвращаемое realloc, не изменится. Вот почему он может работать лучше, чем просто вызов malloc и memcpy.
person Sergey Kalinichenko    schedule 26.01.2014
comment
Спасибо за ваш ответ (который я, очевидно, нашел наиболее точным, хотя ответ Эда тоже был великолепен). Что касается стека по сравнению с кучей, я просто пытался убедиться, что я не неправильно распределял ресурсы и не переписывал его части с помощью стека. В исходной программе у меня были проблемы, которые выглядели так, как будто определенные строки перезаписывались (так и было; я перераспределял пространство намного меньше, чем необходимо), поэтому здесь была эта строка. - person River Tam; 26.01.2014

sizeof arr

Это то же самое, что

sizeof char**

Размер указателя не изменится, и размер указателя не скажет вам, к какому объему памяти он относится. Указатели не являются массивами, и sizeof оценивается во время компиляции.

Что касается бита адреса, realloc не гарантирует, что блок памяти был перемещен. Он может просто успешно расширить его и вернуть тот же адрес.

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

person Ed S.    schedule 26.01.2014
comment
Педантично: в C99 sizeof может быть операцией времени выполнения (если используется в массиве переменной длины). См. stackoverflow.com/q/10078283/575615. - person Medo42; 26.01.2014
comment
@Medo42: Ах, да, хороший звонок. Я уже некоторое время пишу C на земле C89, не думал об этом. - person Ed S.; 26.01.2014

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

Это не то, от чего вы когда-либо должны зависеть. Это просто особенность реализации

person JaredPar    schedule 26.01.2014
comment
На самом деле это совсем не то, на чем сосредоточен этот вопрос. - person River Tam; 26.01.2014

Если вы предполагаете, что realloc() должен возвращать другой указатель, то ваше предположение неверно.

Обычно, если вы уменьшаете размер выделенной памяти или оставляете ее «как есть», то realloc() может вернуть тот же указатель и избежать копирования данных и т. д.

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

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

person Brendan    schedule 26.01.2014