2016-02-08 2 views
1

Я читаю K & R указатели в разделе 5.4, где выполнены стеки malloc() и free(). Я использую gdb для отладки кода, а часть alloc() работает должным образом. Но для части afree() указатели все еще указывают на то же место, что и раньше. Вот код:C: Выполнение стека malloc и бесплатно

#include <stdio.h> 
#define ALLOCSIZE 10000 

static char allocbuf[ALLOCSIZE]; 
static char* allocp = allocbuf; 

char* alloc(int n) 
{ 
    if(allocbuf + ALLOCSIZE - allocp >= n) 
    { 
     allocp += n; 
     return (allocp - n); 
    } 
    else 
     return 0; 
} 


void afree(char* p) 
{ 
    if(p >= allocbuf && p < allocbuf + ALLOCSIZE) 
     allocp = p; 
} 


int main() 
{ 
    char* a = alloc(10); 
    a = "ayushnair"; 
    char*b = alloc(5); 
    b = "snea"; 
    printf("%p %p\n", a, b); 
    afree(b); 
    afree(a); 
    printf("%p %p\n", a, b); 
    return 0; 
} 

Новое распределение

allocp 0x601080

после char* a = alloc(10);

allocp 0x60108a

после char* b = alloc(5);

allocp 0x60108f

после afree(b);

allocp 0x60108f

после afree(a);

allocp 0x60108f

allocp все еще указывает на 0x60108f. Почему он не обновляется в соответствии с кодом?

+2

'return (alloc - n);' is strange: function pointer - 'n'? – chux

+1

@chux Скорее всего, опечатка должна быть 'allocp'. –

+0

Почему вы увеличиваете 'allocp'? Вы уже потеряли память, поэтому не нужно заботиться об этом специальном состоянии. – Olaf

ответ

4

В своем коде, говоря

a = "ayushnair"; 

вы не хранить "ayushnair"в памяти, на который указывает a. "ayushnair" является строковый литерал и говоря

a = "ayushnair"; 

вы храните базовый адрес строкового литерала в a. Таким образом, вы по существу переписываете возвращаемый указатель по вызову alloc().

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

Тем не менее, в соответствии с действующим кодом, а затем по телефону

afree(b); 
afree(a); 

вы вызывающую undefined behavior, как вы пытаетесь comapre указатели, которые не указывают на тот же объект.

Котировка C11, глава §6.5.8, Операторов отношения

Когда два указателя сравнивается, результат зависит от относительных местоположений в адресном пространстве объектов указует на. Если два указателя на типы объектов указывают на один и тот же объект, либо оба указывают один за последним элементом одного и того же объекта массива, они сравниваются с равным числом . Если объекты, на которые указывают, являются членами одного и того же совокупного объекта, указатели , чтобы объявить составные члены, сравниваются больше, чем указатели на члены , объявленные ранее в структуре, и указатели на элементы массива с большим индексом значения сравниваются больше, чем указатели на элементы тот же массив с более низкими значениями индекса. Все указатели на члены одного и того же объекта объединения сравниваются одинаково. Если выражение P указывает на элемент объекта массива, а выражение Q указывает на последний элемент этого объекта массива , выражение указателя Q + 1 сравнивается больше, чем P. Во всех остальных случаях поведение не определено.

+0

Просто добавьте: на вашем обычном ПК это, скорее всего, будет работать; происходит то, что значение указателя не находится внутри буфера статического выделения, т. е. «p> = allocbuf && p

+0

«Будет работать» относительно, где задействован UB. ;-) Алгоритм alloc()/afree() будет * not * работать после назначения строкового литерала. ;-) – DevSolar

+0

@DevSolar Вы правы сэр, но, возможно, мне не хватает вашей точки здесь. Что-нибудь, что я могу добавить, чтобы уточнить? –

-2

Он не обновляет указатель (на Afee), как этот алгоритм mememory распределителя является прогрессивным и не имеет «никакой памяти» previuosly выделенных частей памяти. Таким образом, возвращает только указатель на неиспользуемую память. После выделения ALLOCSIZE не удастся выделить больше mem. Большинство распределителей памяти делают некоторые предположения о потребленной памяти.

+0

Совершенно очевидно, что 'allocp' должен быть обновлен, но это не так. Вы правы, что реализация malloc не имеет «памяти»; информация указана в указателе. –

+0

@Peter A. Schneider Не прямо в указателе, поскольку указатель просто указывает на mem и сам по себе не имеет больше информации в нем, но указывает на mem, где какая-то часть может содержать дополнительную встроенную информацию об занятой памяти. –

2
char* a = alloc(10); 

Этот «выделяет» память из allocbuf, и присваивает указатель на эту память в a.

a = "ayushnair"; 

Это присваивает разные указатель на a - тот, который указывает на строку буквального "ayushnair", который не находится в allocbuf но где-то в памяти целиком.

Отныне ваша программа становится все более запутанной (тем более, что вы делаете аналогичную ошибку с b). Звонок на afree(a) не имеет смысла, поскольку a больше не указывает на то, что возвращает alloc(), а сравнение, выполненное с помощью afree(), фактически вызывает неопределенное поведение, поскольку Сурав Гош указал, но ошибка a = "ayushnair" (и аналогичное назначение для b).


Язык C не имеет понятия о «строке объекта», только конвенции, что указатель на последовательность char, которая заканчивается '\0' называется «строкой» и имеют некоторые вспомогательные функции. Подходящее определение оператора = означает «копировать содержимое» - это не часть этих вспомогательных функций.

Что вы хотели делать было:

char * a = alloc(10); 
strcpy(a, "ayushnair"); 

Что бы скопировать из строки буквального к памяти, на которую указывает a.


Таким образом, нижняя линия, ваша проблема не о логических или сравнения операторов, а не о массивах - это про указатели и строки. Надеюсь, я смог немного разъяснить.

Смежные вопросы