Массив структуры как аргументы и растущая путаница членов - PullRequest
0 голосов
/ 20 февраля 2019
typedef struct Calendar {
    int day;
    int month;
    int year;
}Calendar;

typedef struct Person {
    char name[40];
    int age;
    float salary;
    Calendar birth;
}Person;
void add(Person * a, int * tam);

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

for (int i = 0; i < *tam + 1; i++)
{
        printf("Insert your name:\n");
        fgets(name, 30, stdin);
        *a[i].name = name;
}

В последней строке выдается предупреждение C4047: char отличается по уровням косвенных указаний.Если я удаляю '*', он не компилируется.Как правильно получить доступ к элементу массива из массива структуры?

РЕДАКТИРОВАТЬ 1: Для пояснения здесь есть полная функция add() и main() функция.

void add(Person * a, int * tam) {

    char name[30];
    int op = 0;
    int c, day = 0, month = 0, year = 0, Calendar = -1;
    float sal = -1;

    for (int i = 0; i < *tam + 1; i++)
    {
        printf("Insert your name:\n");
        fgets(name, 30, stdin);
        *a[i].name = name;

        while ((c = getchar()) != '\n' && c != EOF)
            ;
        do
        {
            printf("Insert %s's age:\n", name);
            scanf("%d", &op);
            while ((c = getchar()) != '\n' && c != EOF)
                ;
            if (!op)
                printf("invalid age!\n");
            else
                a[i].age = op;
        } while (op <= 0);
        do
        {
            printf("Insert %s's salary:\n", name);
            scanf("%f", &sal);
            while ((c = getchar()) != '\n' && c != EOF)
                ;
            if (sal < 0)
                printf("Invalid salary!\n");
            else
                a[i].salary = sal;

        } while (sal < 0);
        do
        {
            printf("Insert %s's date birth\n", name);
            printf("Day:\n");
            scanf("%d", &day);
            while ((c = getchar()) != '\n' && c != EOF)
                ;
            printf("Month:\n");
            scanf("%d", &month);
            while ((c = getchar()) != '\n' && c != EOF)
                ;
            printf("Year:\n");
            scanf("%d", &year);
            while ((c = getchar()) != '\n' && c != EOF)
                ;

            if ((day > 0 && day < 31) && (month > 0 && month < 12) && (year > 0))
            {
                Calendar = 1;
                a[i].birth.day = day;
                a[i].birth.month = month;
                a[i].birth.year = year;
            }
            else
                printf("Invalid calendar!\n");

        } while (Calendar != 1);

    }
    *tam++;
}

main() {
    Person book[10];
    int c, tam = 0;
    char op, out = 0;
    while (!out)
    {

        do
        {
            printf("1: Insert a profile\n");
            printf("2: Change a profile\n");
            printf("3: Erase a Profile\n");
            printf("4: Show all profiles\n");
            printf("5: Search\n");
            printf("0: Exit\n");
            scanf("%c", &op);
            while ((c = getchar()) != '\n' && c != EOF)
                ;

        } while (op < '0' || op > '5');

        switch (op)
        {
        case '1':
            add(book, &tam);
            break;
        case '2':

            break;
        case '3':

            break;
        case '4':
            read(book, &tam);
            break;
        case '5':

            break;
        case '0':
            out = 1;
            break;
        default:
            break;
        }

    }

}

Ответы [ 2 ]

0 голосов
/ 20 февраля 2019

Прототип вашей функции должен прояснить, что она работает с массивом:

void add(size_t n, struct Person arr[n], int *tam);

Таким образом, вы знаете размер массива (n), и вы можете убедиться, что выне пытайтесь получить доступ за пределами этого размера, который в итоге окажется segmentation fault, если вам повезет (прочитайте это: Насколько опасно обращаться к массиву за пределами границ? ).


Цикл for будет затем зацикливаться на массиве:

for (int i = 0, *tam = 0; i < n; i++, (*tam)++) {
    printf("Insert your name:\n");
    fgets(name, 30, stdin);
    /* a[i].name = name; */
}
(*tam)++;

Вам нужно круглые скобки вокруг (*tam)++ из-за предшествующего оператора (прочитайте это: Как увеличить адрес указателя и значение указателя? ).


Что касается доступа к struct s внутри массива, вы должны знать, что вы обращаетесь к массивуstruct с;это просто много struct с, вместе взятых, так как массив int с будет:

a - это массив struct с.

a[i]i th-структура в массиве.

a[i].name - это элемент name в структуре a[i].


Чтобы скопировать строку в другую, у вас естькопировать его элемент за элементом, потому что внутренне они являются массивом char s, и из-за того, как массивы работают в C, вы не можете копировать их с помощью =, но повторяя и копируя элемент по элементу.

В случае обычных массивов, функция memcpy() делает это за вас (прочитайте это: http://man7.org/linux/man-pages/man3/memcpy.3.html).

Когда вы имеете дело со строками, функция, которую вы хотите использовать для их копирования, является strncpy()(прочитайте это: http://man7.org/linux/man-pages/man3/strncpy.3p.html).

В этом ответе объясняется правильное использование strncpy(): https://stackoverflow.com/a/14067026/6872717

В основном вы будете использовать его так:

strncpy(a[i].name, name, n - 1);

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

for (int i = 0, *tam = 0; i < n; i++, (*tam)++) {
    printf("Insert your name:\n");
    fgets(name, 30, stdin);
    strncpy(a[i].name, name, 40 - 1);
    a[i].name[40 - 1] = '\0';
}
(*tam)++;

Это больше комментарий, и я могу удалить его позже, если это не то, что вы хотите, ноЗдесь я могу лучше отформатировать код:

Я не уверен, почему существует цикл for, но для контекста, я думаю, эта функция предназначена только для записи в один struct в массиве,Поэтому, возможно, вместо цикла for вы можете захотеть что-то вроде этого:

if (*tam = (n - 1))
    goto err_array_full;
if (*tam > (n - 1)  ||  *tam < 0)
    goto err_invalid_index;

printf("Insert your name:\n");
fgets(name, 30, stdin);
strncpy(a[*tam].name, name, 40 - 1);
a[*tam].name[40 - 1] = '\0';
(*tam)++;

Последнее замечание: я использовал 40 в strncpy(), потому что вы использовали 40 для создания массива, но должен быть макросом, который вы бы использовали в обоих местах, чтобы при изменении размера массива вы не забыли изменить его также в strncpy(), что привело бы к ошибке.С макросом вы в безопасности, потому что вы меняете только один номер, и весь ваш код обновляется.

0 голосов
/ 20 февраля 2019

Правильный способ передачи массива структуры Person и установки имени члена:

Person tab[10]; /* array of 10 Person */

void add(Person *a, int tam)
{
    [...]

    for (int i = 0; i < tam; i++) {
        printf("Insert your name:\n");
        fgets(name, 30, stdin);
        strncpy(a[i].name, name, 30);
    }

    [...]
}

/* Call add() like that */
add(tab, 10);

Массив struct похож на обычный массив (например, массив int).Когда вы находитесь внутри функции, вы имеете дело с указателем, но все еще можете использовать нотацию массива.Чтобы получить доступ к имени члена внутри функции, вы просто делаете это a[i].name.Поскольку name является массивом char, вам нужно использовать что-то вроде strncpy (), а не =, чтобы установить его значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...