Использование Realloc в C

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

Мне просто интересно, можно ли использовать realloc в приведенном ниже коде, чтобы упростить его, любые советы, примеры кода или даже подсказки о том, как его реализовать, очень ценятся!

Ваше здоровье.

void reverse(char *s) {
char p;

switch(toupper(s[0])) 
{
    case 'A': case 'E': case 'I': case 'O': case 'U':
        p = s[strlen(s)-1];
        while( p >= s )
            putchar( p-- );
        putchar( '\n' );
        break;
    default:
        printf("%s", s);
        break;
}
printf("\n");
    }

    int main(void) {
char c;
int buffer_size = 256;
char *buffer, *temp;
int i=0;

buffer = (char*)malloc(buffer_size);
while (c=getchar(), c!=' ' && c!='\n' && c !='\t') 
{
    buffer[i++] = c;
    if ( i >= buffer_size )
    {
        temp = (char*)malloc(buffer_size*2);
        memcpy( temp, buffer, buffer_size );
        free( buffer );
        buffer_size *= 2;
        buffer = temp;
    }
}
buffer[i] = '\0';
reverse(buffer);

return 0;

}


person PnP    schedule 29.11.2011    source источник
comment
Примечание по стилю: лучше не приводить возвращаемое значение malloc.   -  person Oliver Charlesworth    schedule 30.11.2011
comment
И reverse должен принять аргумент как const char *.   -  person Kerrek SB    schedule 30.11.2011


Ответы (4)


Да — это короткий ответ. Вот как это будет выглядеть:

if ( i >= buffer_size )
{
    temp = realloc(buffer, buffer_size*2);
    if (!temp)
        reportError();
    buffer_size *= 2;
    buffer = temp;
}

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

person Graham Borland    schedule 29.11.2011
comment
Поправьте меня, если я ошибаюсь, но buffer=temp, разве это не копирует адрес памяти temp? То есть, если я потом освобожу temp, я также освобожу buffer? Если да, то когда мне освободить переменную temp, чтобы не тратить память на выделение двух одинаковых строк? Извините, я пытаюсь узнать, как это работает. - person Salviati; 30.04.2019

Realloc — это именно то, что вы ищете — вы можете заменить весь этот блок внутри if ( i >= buffer_size ) чем-то вроде:

buffer = (char*)realloc(buffer, buffer_size*2);
buffer_size *= 2;

Обратите внимание, что это игнорирует условие ошибки (если возврат из realloc равен NULL); улавливание этого условия предоставляется читателю.

person Tim    schedule 29.11.2011

Да, realloc можно использовать, чтобы немного упростить код. Если вас не интересует обработка ошибок, то это:

char *tmp = malloc(size*2);
memcpy(temp, buffer, size);
free(buffer);
buffer = tmp;

по существу эквивалентен этому:

buffer = realloc(buffer, size*2);

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

person Oliver Charlesworth    schedule 29.11.2011
comment
-1. если realloc терпит неудачу (возвращая NULL), вы потеряли ссылку на исходный блок. - person Graham Borland; 30.11.2011
comment
@Graham: я прямо сказал, если вас не интересует обработка ошибок. В исходном коде OP также нет обработки ошибок. - person Oliver Charlesworth; 30.11.2011
comment
Эта обработка ошибок — не просто детская забава вроде проверки std::cin >> n; этот здесь может и почти наверняка вызовет UB ... - person Kerrek SB; 30.11.2011

Да, чтобы упростить код, вы можете заменить

if ( i >= buffer_size )
{
    temp = (char*)malloc(buffer_size*2);
    memcpy( temp, buffer, buffer_size );
    free( buffer );
    buffer_size *= 2;
    buffer = temp;
}

с участием

if ( i >= buffer_size )
    buffer = realloc(buffer, buffer_size *= 2);

Это не учитывает проверку ошибок, поэтому вам нужно будет убедиться, что realloc не возвращает NULL.

person Seth Carnegie    schedule 29.11.2011
comment
realloc может вернуть NULL, что приведет к мгновенной неисправимой утечке. - person Kerrek SB; 30.11.2011
comment
-1. если realloc терпит неудачу (возвращая NULL), вы потеряли ссылку на исходный блок. - person Graham Borland; 30.11.2011
comment
@GrahamBorland Я сказал, что вы можете заменить его исходный код этим кодом. Он не проверил там NULL, как и я. Но я добавил примечание, чтобы упомянуть об этом. - person Seth Carnegie; 30.11.2011