Динамически выделяемый массив структур, передаваемых в функцию и доступ к которым осуществляется с помощью индексации.

Я пытаюсь динамически выделить массив структур, передав указатель на функцию. Мне нужно получить доступ к массиву с помощью индексации. У меня есть аналогичный процесс, работающий без перехода к функции. У меня есть простая структура под названием Account, в которой есть только один член, accountNo. Ниже перечислены соответствующие вызовы malloc.

int8_t dynamicStruct(struct Account **all_accounts,int8_t num_accounts){
    *all_accounts = (struct Account*)malloc(sizeof(struct Account)*num_accounts);
}

Переменная all_accounts инициализируется и вызывается с помощью следующего фрагмента кода, где num_accounts на данный момент равно 10;

struct Account *all_accounts_dyn;
dynamicStruct(&all_accounts_dyn,num_accounts);

Доступ к переменной-члену accountNo с помощью следующего метода

all_accounts[i]->accountNo = i;

Программа компилируется нормально, память выделяет, но segfaults при доступе к элементу (num_accounts = 10).

Составлено с

gcc -std=gnu99 -Wall -Werror structify.c -o structify

"Небольшой автономный пример"

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

struct Account{
    int8_t accountNo;
};
int8_t dynamicStruct(struct Account **all_accounts,int8_t num_accounts);

int main(){
    struct Account *all_accounts_dyn;
    int8_t num_accounts = 10;
    dynamicStruct(&all_accounts_dyn,num_accounts);
    return 1;
}
int8_t dynamicStruct(struct Account **all_accounts,int8_t num_accounts){
        *all_accounts = (struct Account*)malloc(sizeof(struct Account)*num_accounts);
        for(int i = 0; i<num_accounts;i++){
            printf("initializing %d\n",i);
            all_accounts[i]->accountNo = i;
        }
        return 1;
}

person NathanielJPerkins    schedule 18.10.2016    source источник
comment
Опубликуйте минимальный автономный пример, пожалуйста.   -  person 2501    schedule 18.10.2016
comment
Вы хотите сказать, что выделили 10 структур Account и обращаетесь к ним с помощью all_accounts[10], что, конечно, выходит за рамки допустимого?   -  person ad absurdum    schedule 18.10.2016
comment
Нет, я говорю, что если я попытаюсь получить доступ к переменной-члену, это вызовет ошибку, а не 10 конкретно.   -  person NathanielJPerkins    schedule 18.10.2016
comment
Ваш пример не компилируется.   -  person 2501    schedule 18.10.2016
comment
В вашей программе нет массива структур. Это просто указатель на структуру, а не массив структур, поэтому он segfaults.   -  person ckruczek    schedule 18.10.2016
comment
Не является -› сокращенной записью для (*struct). обозначение? почему они здесь не взаимозаменяемы?   -  person NathanielJPerkins    schedule 18.10.2016
comment
all_accounts[x] является указателем на эту структуру, не так ли?   -  person NathanielJPerkins    schedule 18.10.2016
comment
all_accounts[0] — это указатель на all_accounts_dyn, но основные индексы — это UB...   -  person LPs    schedule 18.10.2016
comment
основные индексы какие? УБ?   -  person NathanielJPerkins    schedule 18.10.2016
comment
@NathanielJPerkins Неопределенное Bповедение   -  person LPs    schedule 18.10.2016
comment
В C функции выделения памяти в куче (malloc, calloc, realloc) возвращают значение с типом void* Такой тип может быть присвоен любому другому указателю. Приведение возвращаемого типа просто загромождает код, затрудняя его понимание, отладку и поддержку. Настоятельно рекомендуем удалить приведение значения, возвращаемого вызовом любой из этих функций. При вызове любой из функций выделения памяти всегда проверяйте (!=NULL) возвращаемое значение, чтобы убедиться, что операция прошла успешно.   -  person user3629249    schedule 20.10.2016
comment
относительно возвращаемого значения из функции main(). Любое значение, отличное от 0, указывает на сбой. Настоятельно рекомендуем (в функции main()) заменить return 1; на return 0 (или в современных компиляторах не используйте return 0;, и компилятор будет иметь функцию main(), возвращающую 0   -  person user3629249    schedule 20.10.2016
comment
Я компилирую с -Wall и -Werror, если бы я захотел, это не позволило бы мне. Хотя я не думаю, что кастинг с помощью malloc вообще усложняет понимание, отладку или поддержку.   -  person NathanielJPerkins    schedule 20.10.2016
comment
для простоты чтения и понимания, 1) последовательно делать отступы в коде. никогда не используйте вкладки, так как в каждом текстовом процессоре/редакторе позиции табуляции/ширина табуляции устанавливаются в соответствии с индивидуальными предпочтениями.   -  person user3629249    schedule 20.10.2016
comment
при компиляции всегда включайте все предупреждения, а затем исправьте эти предупреждения. (для gcc как минимум используйте: -Wall -Wextra -pedantic я также использую: -Wconversion -std=gnu99 ).   -  person user3629249    schedule 20.10.2016
comment
функция: dynamicStruct() возвращает int8_t некоторого странного значения 1, и вызывающая сторона не проверяет это значение. Предложите изменить возвращаемый тип на void   -  person user3629249    schedule 20.10.2016
comment
Теперь вы действительно просто переходите к предпочтениям программирования и руководству по стилю, что не имеет значения и не требуется. Это не было критикой моего использования табуляции или пробелов или правильной проверки выделения NULL. Он спрашивал об очень конкретной проблеме, причем из кода было удалено абсолютно все нерелевантное. Есть причина, по которой вы не видите, что я проверяю NULL или возвращаю что-либо еще, это не имеет значения для проблемы, о которой я спрашивал.   -  person NathanielJPerkins    schedule 20.10.2016
comment
Как правило, не делайте #include файлы заголовков, которые не используются.   -  person user3629249    schedule 20.10.2016


Ответы (4)


Когда у вас есть struct my_struct;, вы получаете доступ к членам следующим образом:

mystuff = my_struct.stuff;

Но когда у вас есть указатель на структуру struct *my_struct;, вы делаете:

mystuff = my_struct->stuff;

Это эквивалентно:

mystuff = (*my_struct).stuff;

Другими словами, вы должны разыменовать указатель на структуру, прежде чем вы сможете получить доступ к ее полям-членам.

Когда вы выделяете память для 10 структур:

*all_accounts = (struct Account*)malloc(sizeof(struct Account)*num_accounts);

а затем доступ с записью массива, у вас есть all_accounts[i] ==> *(all_accounts + i). Таким образом, all_accounts[i] — это структура, а не указатель на структуру, и доступ к ней должен осуществляться с помощью оператора точки.

person ad absurdum    schedule 18.10.2016
comment
Спасибо. Это была моя главная проблема. Я думал, что all_accounts[i] возвращает указатель на структуру, а не на структуру. Точечная нотация теперь имеет больше смысла. - person NathanielJPerkins; 18.10.2016

Как вы написали, чтобы выделить место для all_accounts_dyn, вы использовали

*all_accounts = malloc(sizeof(struct Account)*num_accounts);

Это правильно из-за двойного указателя.

Двойной указатель принимает адрес указателя all_accounts_dyn

Возвращенный адрес malloc назначается all_accounts_dyn, то есть *all_accounts внутри функции dynamicStruct.

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

    for(int i = 0; i<num_accounts;i++)
    {
        (*all_accounts)[i].accountNo = i;

        printf("initialized %d\n", (*all_accounts)[i].accountNo);

    }
person LPs    schedule 18.10.2016

Если вы пытаетесь выделить массив структур, то почему вы используете двойные указатели.

all_acounts=(Acount*)malloc(sizeof(Acount)*num_acounts) и в функции dynamicStruct установите аргумент как обычный недвойной указатель *all_acounts

person JPX    schedule 18.10.2016
comment
stackoverflow.com/questions/5580761/ Второй ответ: используйте **, когда вы хотите сохранить (или сохранить изменения) выделение памяти или назначение даже вне вызова функции. - person NathanielJPerkins; 18.10.2016
comment
Это не отвечает на вопрос. Если вы что-то не понимаете в вопросе, пожалуйста, воздержитесь от публикации ответа. Вместо этого задайте новый вопрос. - person Lundin; 18.10.2016
comment
Это не дает ответа на вопрос. Получив достаточную репутацию, вы сможете /comment">прокомментировать любой пост; вместо этого дайте ответы которые не требуют разъяснений от спрашивающего. – Из обзора - person ljedrz; 18.10.2016

размещенный код содержит несколько проблем.

  1. неверное возвращаемое значение из main()
  2. неиспользованное возвращаемое значение из dynamicStruct()
  3. использование неправильного типа при передаче num_accounts
  4. требуется соответствующий интервал по вертикали и горизонтали для удобочитаемости
  5. неправильно устанавливает значения в массиве структур
  6. не может проверить наличие ошибок при вызове malloc()
  7. содержит несколько рискованных преобразований между различными числовыми типами
  8. содержит вкладки для отступа кода
  9. не делает отступ в коде последовательно
  10. возвращает вводящее в заблуждение значение из функции main()
  11. возвращает возвращаемое значение из malloc(), что является плохой практикой в ​​C

а теперь исправленный код:

#include <stdio.h>   // printf()
#include <stdint.h>  // int8_t 
#include <stdlib.h>  // malloc(), exit(), EXIT_FAILURE
//#include <stdbool.h>

struct Account
{
    int8_t accountNo;
};

void dynamicStruct( struct Account **all_accounts, size_t num_accounts );

int main( void )
{
    struct Account *all_accounts_dyn;
    size_t num_accounts = 10;
    dynamicStruct( &all_accounts_dyn, num_accounts );
} // end function: main


void dynamicStruct( struct Account **all_accounts, size_t num_accounts )
{
        *all_accounts = malloc(sizeof(struct Account)*num_accounts);
        if( NULL == *all_accounts )
        {
            perror( "malloc for account array failed" );
            exit( EXIT_FAILURE );
        }

        // implied else, malloc successful


        for( int8_t i = 0; i<(int8_t)num_accounts; i++ )
        {
            printf("initializing %d\n",i);
            (*all_accounts)[i].accountNo = i;
        }
} // end function: dynamicStruct

Приведенный выше код выводит следующее:

initializing 0
initializing 1
initializing 2
initializing 3
initializing 4
initializing 5
initializing 6
initializing 7
initializing 8
initializing 9
person user3629249    schedule 20.10.2016