Перераспределение массива строк

Поэтому я сделал эту функцию, которая получает неизвестное количество строк и добавляет их в массив строк.

char **receiveCode(int socket){
    int line = 0;
    size_t lines = 1;
    size_t size = 1;
    char** code = malloc(sizeof(char)*size);

    while(1){
        package_struct *aPackage = receivePackage(socket);
        if(aPackage->type=='F'){break;}
        size = size + aPackage->size;
        code = realloc(code, size);
        code[line] = malloc(sizeof(char)*aPackage->size);
        strcpy(code[line],aPackage->package);
        line++;
        lines++;
        free(aPackage);
    }
    code = realloc(code, size + 2);
    code[line] = malloc(sizeof(char)*3);
    code[lines]=NULL;
    return code;
}

Иногда, когда я запускаю этот код, я получаю следующую ошибку

* glibc обнаружен ./pp: realloc(): неверный следующий размер: 0x00007f0f88001220 **

Что, по словам Вальгринда, и происходит в этой функции.

Вероятно, я использую слишком много mallocs и reallocs... хотя не уверен.


person Matías Hernán García    schedule 21.11.2012    source источник
comment
Множество правильных ответов ниже: Боковая панель, избавьтесь от привычки ptr=realloc(ptr,size), если только вас действительно не волнует, если сбой перераспределения приведет к утечке вашей ранее выделенной памяти. Назначьте временный и перезапишите указатель prev только в случае успеха, если вам это небезразлично.   -  person WhozCraig    schedule 22.11.2012


Ответы (3)


Думаю проблема вот в чем:

char** code = malloc(sizeof(char)*size);

Внутри sizeof() должно быть char * вместо char

char** code = malloc(sizeof(char*)*size);

Поскольку code является указателем на строку, поэтому выделяйте память для указателей, равных char*.

Также есть такая же проблема в realloc

person Omkant    schedule 21.11.2012

Я предполагаю, что это для выделения массива char* :

code = realloc(code, size);

Должно быть

code = realloc(code, size * sizeof(char*));
// and this one too
code = realloc(code, size + 2 * sizeof(char*));

Кроме того, вам не нужно это:

char** code = malloc(sizeof(char)*size);

Если вы называете realloc(NULL, size), это эквивалентно malloc(size)

size_t size = 0;
char** code = NULL;
...
code = realloc(code, size * sizeof(char*));

Примечание: lines кажется мне бесполезным, на самом деле в последних двух строках вы перезаписываете память, которую вы только что выделили с line==lines

person iabdalkader    schedule 21.11.2012

Вот версия, которая использует strdup() для упрощения выделения памяти для каждой новой строки текста. Он также использует 'x' версии функций распределения памяти для упрощения обработки ошибок нехватки памяти (довольно распространенная идиома, даже если она нестандартна).

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

// these variants allocate memory, but abort program on failure
//  for simplified error handling - you may need different
//  error handling, but often this is enough
//
//  Also, your platform may or may not already have these functions
//      simplified versions are in the example.

void* xmalloc( size_t size);
void* xrealloc(void* ptr, size_t size);
char* xstrdup(char const* s);


char** receiveCode(int socket){
    size_t lines = 0;
    char** code = xmalloc( (lines + 1) * sizeof(*code));

    *code = NULL;

    while(1){
        package_struct *aPackage = receivePackage(socket);
        if(aPackage->type=='F') {
            free(aPackage); // not 100% sure if this should happen here or not.
                            // Is a `package_struct` with type 'F' dynamically
                            // allocated or is a pointer to a static sentinel 
                            // returned in this case?
            break;
        }


        // why use `aPackage->size` when you use `strcpy()` to
        //  copy the string anyway? Just let `strdup()` handle the details
        //
        // If the string in the `pckage_struct` isn't really null terminated, 
        // then use `xstrndup(aPackage->package, aPackage->size);` or something
        // similar.

        char* line = xstrdup(aPackage->package);
        ++lines;

        // add another pointer to the `code` array
        code = xrealloc(code, (lines + 1) * sizeof(*code));
        code[lines-1] = line;
        code[lines] = NULL;

        free(aPackage);
    }

    return code;
}


void* xmalloc(size_t size)
{
    void* tmp = malloc(size);

    if (!tmp) {
        fprintf(stderr, "%s\n", "failed to allocate memory.\n";
        exit(EXIT_FAILURE);
    }

    return tmp;
}

void* xrealloc(void *ptr, size_t size)
{
    void* tmp = realloc(ptr, size);

    if (!tmp) {
        fprintf(stderr, "%s\n", "failed to allocate memory.\n";
        exit(EXIT_FAILURE);
    }

    return tmp;
}


char* xstrdup(char const* s)
{
    char* tmp = strdup(s);

    if (!tmp) {
        fprintf(stderr, "%s\n", "failed to allocate memory.\n";
        exit(EXIT_FAILURE);
    }

    return tmp;
}

Кроме того, я думаю, следует уточнить, является ли aPackage->package строковым указателем или это фактическое местоположение char[], содержащего строковые данные (т. е. следует ли &aPackage->package передавать strcpy()/xstrdup()?). Если это действительно указатель, должен ли он быть освобожден до того, как aPackage?

person Michael Burr    schedule 21.11.2012