Доступ к элементам динамически распределяемого массива указателей на структуры

#arrays #c #pointers #struct #malloc

#массивы #c #указатели #структура #malloc

Вопрос:

Мне нужно иметь глобальный динамический массив указателей, в котором я буду хранить свои структуры, потому что позже мне нужно будет выполнить итерацию по этому массиву, чтобы перечислить всю сохраненную информацию, мне также нужно иметь возможность считывать name age job переменные и с консоли и сохранять их в a person_t в iterator массиве.

 #include <stdio.h>
#include <stdlib.h>

typedef struct Person
{
    char name[30];
    int age;
    char job[30];
} person_t;

person_t **iterator;
int capacity = 10;
int size = 0;

int main()
{
    int i;
    *iterator = (person_t *)malloc(capacity * sizeof(person_t));
    for (i = 0; i < capacity;   i)
    {
        person_t p;
        p.age = i;
        *iterator[i] = p;
    }
    return 0;
}
 

Я не получаю ошибок / предупреждений при компиляции этого кода (gcc -ansi -pedantic -Wall -Wextra), но когда я пытаюсь его запустить, я Segmentation fault немедленно получаю.

Комментарии:

1. нет необходимости приводить malloc

Ответ №1:

Когда вы делаете это:

 *iterator = (person_t *)malloc(capacity * sizeof(person_t));
 

Вы откладываете iterator , однако в качестве переменной указателя области действия файла она инициализируется значением NULL. Попытка разыменования нулевого указателя вызывает неопределенное поведение.

Я подозреваю, что вам действительно нужен массив структур, а не массив указателей на структуры. В этом случае определите iterator как:

 person_t *iterator;
 

Затем вы выделяете для него память следующим образом:

 iterator = malloc(capacity * sizeof(person_t));
 

Затем присваивайте элементам массива следующим образом:

 iterator[i] = p;
 

Ответ №2:

Ваша заявленная цель — создать «глобальный динамический массив указателей, в котором я буду хранить свои структуры». Следующая модификация вашего кода (см. Комментарии) сделает это:

 person_t p[10] = {0};

int main()
{
    int i;
    // with declaration: person_t **iterator = NULL;, 
    //following is all that is needed to create an array of pointers:
    iterator = malloc(capacity * sizeof(person_t *));//no need to cast return of malloc
   
        
        for (i = 0; i < capacity;   i)
        {
            //person_t p;//moved to scope that will exist outside of main()
            p[i].age = i;
            iterator[i] = amp;p[i];//assign the address of the object to the pointer
                             //iterator[i] is the ith pointer in a collection of 
                             //pointers to be assigned to point to 
                             //instances of struct person_t 
        }
        //Once all fields are populated (to-do), the following will display the results:
        for (i = 0; i < capacity;   i)
        { 
           printf("%d) Name: %s Age: %d  Job: %sn",  i, iterator[i]->name,iterator[i]->age,iterator[i]->job);
        }

    return 0;
}
 

Комментарии:

1. Стоит отметить, что «итератор» на самом деле является неправильным, поскольку это основное хранилище для этой коллекции person_t . people имело бы больше смысла, а затем объявить a person_t *iterator для использования в качестве временного указателя для фактического перебора коллекции people .

2. @DavidC.Rankin — я не согласен. Однако моя попытка здесь заключалась в том, чтобы использовать строгую буквальную интерпретацию того, что запрашивал OP, и при этом придерживаться описаний переменных OP, что позволяет OP легко отслеживать элементы в запросе с помощью шагов в моей реализации. Использование соглашений об именовании операций помогает с этой целью.

3. Я понимаю, и я согласен, что это помогает отслеживать имена, используемые в вопросе. Вот почему я не предлагал изменения, а просто то, что на это стоило указать, так что, по крайней мере, они осознают, что описательное именование полезно. Комментарий подойдет.

Ответ №3:

вы неправильно выделяете память

Сначала вам нужно выделить память для указателя, который может хранить capacity номер адреса, т.е. выполненный, iterator = malloc(capacity * sizeof(person_t*)); а затем вам нужно выделить память для хранения каждого элемента структуры, т.е iterator[i] = malloc(sizeof(person_t));

вся malloc ‘отредактированная память должна быть free ‘общей, как только мы закончим с этим.

Кроме того, вы не выполнили проверку ошибок для malloc ‘s , которая оставлена для вас в качестве упражнения.

 int main()
{
    int i;
    // test data
    char *names[] = {"ABC", "DEF"};
    char *jobs[] = {"Accountant", "Security"};
    int ages[] = {50, 60};
    
    // first allocate memory for iterator , which can hold pointers to store iterator poniters
    iterator = malloc(capacity * sizeof(person_t*)); 
    
    for (i = 0; i < capacity;   i)
    {
        // now allocate memory for individual iterator
        iterator[i] = malloc(sizeof(person_t)); 
        strcpy(iterator[i]->name,names[i]);
        iterator[i]->age = ages[i];
        strcpy(iterator[i]->job, jobs[i]);
    }
    
    for (i = 0; i < capacity;   i)
    {
        printf("name = %s ", iterator[i]->name);
        printf("Age = %d ", iterator[i]->age);
        printf("Job = %sn", iterator[i]->job);
    }
    return 0;
}