Как создать динамический массив структур, используя функцию realloc - PullRequest
0 голосов
/ 23 декабря 2018

Я пытаюсь создать динамический массив структур (в данном случае фото) с использованием realloc.Я хочу сделать это в функции, но есть проблема: переменные в main не изменяются этой функцией.Должна быть проблема с указателями, но я не могу ее найти.PS: функция UploadFile работает правильно.Есть функция:

int AddPicture(struct Picture ***tab, int *PicCounter)
{
    struct Picture *temp;
    struct Picture pic;
    (*PicCounter)++;
    temp = realloc(*tab, (*PicCounter) *sizeof(*temp));
    if (temp != NULL)
    {
        UploadFile(&pic);
        **tab = temp;
        (*tab)[*PicCounter-1]->name = pic.name;
        (*tab)[*PicCounter-1]->type[0] = pic.type[0];
        (*tab)[*PicCounter-1]->type[1] = pic.type[1];
        (*tab)[*PicCounter-1]->width = pic.width;
        (*tab)[*PicCounter-1]->height = pic.height;
        (*tab)[*PicCounter-1]->scale = pic.scale;
        (*tab)[*PicCounter-1]->table = pic.table;
    }
    else {
        printf("Memory reallocation error");
        free(temp);
        return 1;
    }
return 0;
}

Вот как я ее называю в основном:

struct Picture *tabofpics;
int piccounter = 0;
tabofpics = malloc(1 * sizeof(*tabofpics));
AddPicture(&tabofpics,&piccounter);

Спасибо за помощь.

РЕДАКТИРОВАТЬ: я пробовал ** вкладку вместоof *** tab и значения в main правильные, но он действует так, как будто память не перераспределяется должным образом, даже если realloc не возвращает NULL.

  int AddPicture(struct Picture **tab, int *PicCounter)
{
    struct Picture *temp;
    struct Picture pic;
    (*PicCounter)++;
    temp = realloc(*tab, (*PicCounter) * sizeof(*temp));
    if (temp != NULL)
    {
    UploadFile(&pic);
    *tab = temp;    
    tab[*PicCounter - 1]->name = pic.name;
    tab[*PicCounter - 1]->type[0] = pic.type[0];
    tab[*PicCounter - 1]->type[1] = pic.type[1];
    tab[*PicCounter - 1]->width = pic.width;
    tab[*PicCounter - 1]->height = pic.height;
    tab[*PicCounter - 1]->scale = pic.scale;
    tab[*PicCounter - 1]->table = pic.table;
}
else {
    printf("Memory reallocation error");
    free(*tab);
    return 1;
}
return 0;
}                                                                                                                             

Идея состоит в том, чтобы поместить в программу столько картинок, сколько захотите, выполнить несколько операций над ней и выйти.Должна быть функция для добавления и удаления изображений, когда пользователь захочет, однако, когда я вызываю функцию с ** tab в аргументе во второй раз, я получаю местоположение нарушения доступа, поэтому, как я упоминал ранее, realloc не должен работать должным образом.

Ответы [ 3 ]

0 голосов
/ 23 декабря 2018

Центральная проблема может быть лучше всего описана двумя выдержками из вашего кода:

    temp = realloc(*tab, (*PicCounter) *sizeof(*temp));

[...]

        **tab = temp;

Выперераспределяя пространство, на которое указывает значение *tab, но в случае успеха вы сохраняете указатель на новое пространство в **tab, , которое является другим местоположением .Независимо от того, какое из них является правильным местом для указателя, комбинация определенно неправильная.

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

struct Picture *tabofpics;

[...]

AddPicture(&tabofpics,&piccounter);

... тип фактического аргумента struct Picture **.И это подходит для ваших целей, поэтому вы должны настроить определение функции, чтобы оно соответствовало:

int AddPicture(struct Picture **tab, int *PicCounter)

.Кроме того, вы должны убедиться, что соответствующее объявление функции присутствует в заголовочном файле, который находится #include d в исходном файле, содержащем определение AddPicture, и во всех исходных файлах, содержащих вызов этой функции.Это, плюс обеспечение включения предупреждений компилятора, должно дать возможность компилятору помочь вам диагностировать несоответствия между определением и использованием этой функции.

После этого выражение *tab в функции AddPicture()будет ссылаться на тот же объект, на который ссылается выражение tabofpics (no *) в main().Похоже, это согласуется с тем, как вы на самом деле используете его, за исключением несоответствия, которое я описал в начале.

Есть и другие разумные критические замечания по поводу вашего кода, которые могут быть сделаны, но @Iharob ужепроделал хорошую работу, обращаясь к тем, кто в своем ответе.

0 голосов
/ 25 декабря 2018

Согласно ответам @Iharob и @John, я смог написать рабочую функцию:

 int AddPicture(struct Picture **tab, int *PicCounter)
{
struct Picture *temp;
(*PicCounter)++;
temp = realloc(*tab, (*PicCounter) * sizeof(*temp));
if (temp != NULL)
{
    struct Picture *pic;
    pic = malloc(sizeof(*pic));
    UploadFile(pic);
    *tab = temp;
    (*tab)[(*PicCounter)-1] = *pic;
    free(pic);
}
else {
    printf("Memory reallocation error");
    free(*tab);
    (*PicCounter)--;
    return 1;
}
return 0;
}

Она не идеальна, но работает правильно.Спасибо за помощь!

0 голосов
/ 23 декабря 2018

На мой взгляд, вам нужно улучшить логику вашего кода, например

  1. Не увеличивать PicCounter пока
  2. У вас есть несоответствие в ваших указателяхуровень косвенности, в функции вызывающего абонента у вас есть struct Picture *, и вы передаете его как struct Picture ** функции, принимающей struct Picture ***.Вы должны рассуждать об этом и что вы действительно хотите.Кажется, вам нужен массив struct Picture *.

Style,

  1. Не используйте PicCounter для переменной, используйте number_of_pictures или что-то еще
  2. Не пишите 1 * sizeof(...) это слишком явно, и вам не нужно быть таким большим.

Инструмент,

  1. Включитьпредупреждения компилятора, чтобы определить простые ошибки, которые вы делаете, не замечая, или те, которые являются концептуальной ошибкой, такой как несовпадение указателей в вашем коде.1031 *
    int
    AddPicture(struct Picture ***tab, int *counter)
    {
        struct Picture **array;   
        array = realloc(*tab, (*counter + 1) * sizeof(*array));
        if (array != NULL)
        {
            struct Picture *current;
            // We will avoid using the `tab' variable because it's
            // confusing, the only reason why it's a *** pointer is
            // to do this here, and below where we set it to `NULL'
            *tab = array;
            // We also need to allocate space for a new image to store
            // the results in.
            current = malloc(sizeof(*current));
            if (current == NULL)
                goto error;    
            // This is a guess, but isn't the code just initializing
            // the `pic' that you allocated on the stack?
            //
            // Well, the following is the same.
            //
            // Oh, and should we check for errors here?
            UploadFile(current);            
            // Now we can increase counterand update our array
            array[(*counter)++] = current;
            // We have succeded, so return 0
            return 0;
        }
    error:
        printf("Memory reallocation error");
        // Release memory allocated so far
        free(*tab);
        // Prevent dangling pointer
        *counter = 0;
        *tab = NULL;
        // A non zero value means, an error
        return 1;
    }
    

    А функция вызывающего абонента должна выглядеть примерно так:

    struct Picture **tabofpics;
    int counter = 0;
    // `realloc' will take car of the allocation
    tabofpics = NULL;
    if (AddPicture(&tabofpics, &picounter) == 0)
        // Everything ok, picture added
    else
        // Error
    

    Пожалуйста, будьте осторожны с *** указателями, они могут вызвать много путаницы.Я должен подумать 4 или 5 раз о

    (*tab)[*counter] = current;
    

    , чтобы понять, что это правильно.Поэтому я решил изменить его, как вы можете видеть в коде.

    Ваш код должен быть как можно более описательным, и использование указателей *** идет в неправильном направлении.

...