Программа C аварийно завершает работу, вызывая realloc() несколько раз

Я то и дело работал над заданием для моего класса C в течение последних нескольких дней и столкнулся с любопытным сбоем, связанным с функцией realloc() в C. Даже программисты C/C++ в доме не могли сразу ответить мне, что может быть. неправильно с моим кодом.

Сначала я создаю блок памяти в одной функции:

char *line = (char *)malloc( sizeof(char) * BUFSIZE);

Затем я звоню getMoreBuf(start_of_block, end_of_block)

int getMoreBuf(char *start, char *end)
{
char *newBuf = 0;
int newSize = (end - start) + BUFSIZE;
    newBuf = (char *)realloc(start, sizeof(char) * newSize);
    if(NULL == newBuf) {
        printf("No virtual RAM available");
    }else{
        start = newBuf;
    }
    return newSize;
}

В зависимости от того, что я установил для BUFSIZE, он падает после 5-го вызова (BUFSIZE = 1) или 3-го вызова (BUFSIZE = 5) и заменяет прочитанные символы ерундой.

Может ли кто-нибудь указать мне на мою ошибку (ошибки) и дать предложения, где можно прочитать, чтобы исправить их? Любая помощь приветствуется. :)

Дополнительный вопрос: я выделяю блок памяти с указателем 1, указывающим на начало, а затем с указателем 2, указывающим на один блок в блоке памяти. Я realloc() блок, и блок перемещается из-за проблем с размером, указывает ли указатель 2 на старый (теперь бесполезный) блок или он «перемещается» с помощью realloc в новую позицию блока памяти?

(Кроме того, на будущее, должен ли я поместить этот дополнительный вопрос в новый вопрос или я могу оставить его здесь, поскольку он тесно связан с первым вопросом?)

Спасибо всем за ваш вклад, это очень помогло мне понять, что пошло не так. Если бы я мог, я бы отметил каждый как правильный ответ, поскольку каждый из них помог мне в той или иной форме понять немного больше обо всем этом чертовом бизнесе с указателями. =)


person Plastefuchs    schedule 14.02.2012    source источник
comment
Даже программисты Может быть, вам стоило попробовать программистов на C?   -  person cnicutar    schedule 14.02.2012
comment
Да, я пробовал программировать на C и C++, просто забыл упомянуть об этом. Я исправил это, и я посмотрю на ссылку.   -  person Plastefuchs    schedule 14.02.2012


Ответы (3)


Я думаю, ваша проблема в том, что вы меняете только локальную переменную start... Вам нужно использовать указатель.

int getMoreBuf(char **start, char **end)
{
    char *newBuf = 0;
    int newSize = (*end - *start) + BUFSIZE;
    newBuf = (char *)realloc(*start, sizeof(char) * newSize);
    if(NULL == newBuf) {
        printf("No virtual RAM available");
    } else {
        *start = newBuf;
        *end = *start + newSize;
    }
    return newSize;
}

И тогда вы бы назвали это так:

getMoreBuf(&start_of_block, &end_of_block)
person cha0site    schedule 14.02.2012
comment
Обратите внимание, что end, вероятно, тоже нужно пересчитать, иначе вычисление для newSize даст неверное значение... - person Martin B; 14.02.2012
comment
Спасибо за ваш ответ! Я надеялся на небольшой вклад, чтобы понять это самостоятельно, но это тоже работает. Я надеюсь, что смогу запомнить все это в следующий раз. :) - person Plastefuchs; 14.02.2012
comment
*start + newSize; не работает, мне нужно вычесть из него BUFSIZE до того, как оно сработает. И мне нужно подумать об этом еще некоторое время, чтобы придумать более аккуратный и понятный способ сделать это. Так что именно то, что мне нужно, больше пищи для размышлений! - person Plastefuchs; 14.02.2012
comment
@Plastefuchs: Вы уверены, что вам нужно вычесть BUFSIZE, а не 1? - person cha0site; 14.02.2012
comment
@Plastefuchs: Кстати, что касается вашего бонусного вопроса: указатель не меняется, он остается висящим в плохой памяти. - person cha0site; 14.02.2012
comment
@ cha0site: если я вычту единицу, я все еще только (BUFSIZE - 1) позади последнего указателя. Я пробовал несколько версий и смотрел на память в VS, и именно эти исправления заставили ее работать так, как мне нужно. :) - person Plastefuchs; 15.02.2012

Этот:

start = newBuf;

изменяет start. Но start — локальная переменная; это не повлияет на переменную, которую имеет вызывающий.

Чтобы решить эту проблему, вам нужно либо принять start в качестве указателя на указатель, либо вам нужно вернуть newBuf.

person Oliver Charlesworth    schedule 14.02.2012
comment
@Plastefuchs: Нет, не будет. Вам нужно изменить сам указатель, поэтому вам нужно передать ему указатель, то есть указатель на указатель. - person Oliver Charlesworth; 14.02.2012
comment
Спасибо за ваш ответ, это помогло мне переосмыслить несколько вещей, которые, как мне казалось, я уже знал об указателях и функциях. - person Plastefuchs; 14.02.2012

Проблема в том, что новое значение start не передается из функции getMoreBuf() — для этого вам понадобится двойной указатель, т. е. ваш прототип функции должен выглядеть так:

int getMoreBuf(char **start, char **end);

(Я также сделал end двойным указателем, поскольку вам, вероятно, также потребуется вычислить для него новое значение.)

person Martin B    schedule 14.02.2012
comment
Спасибо за Ваш быстрый ответ! - person Plastefuchs; 14.02.2012