结构数组作为参数和访问成员混淆

Array of structure as arguments and acessing members confusion

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;
        }

    }

}

你的函数的原型应该清楚地表明它适用于数组:

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

这样,您就知道数组的大小 (n),并且可以确保您不会尝试访问超出该大小的内容,这将以 segmentation fault 如果你幸运的话(阅读这个:How dangerous is it to access an array out of bounds?)。


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)++ 两边的括号,因为运算符优先级(阅读:How to increment a pointer address and pointer's value?)。


至于访问数组内部的struct,你要知道你访问的是一个struct的数组;这只是许多 struct 放在一起,因为 int 的数组将是:

astruct 的数组。

a[i] 是数组中的第 i 个结构。

a[i].name 是结构 a[i].

中的元素 name

要将一个字符串复制到另一个字符串中,您必须逐个元素地复制它,因为在内部它们是一个 char 的数组,并且由于数组在 C 中的工作方式,您不能复制它们使用 = 但通过逐个元素迭代和复制。

如果是普通数组,函数 memcpy() 会为您完成(阅读:http://man7.org/linux/man-pages/man3/memcpy.3.html)。

当你处理字符串时,你想用来复制它们的函数是strncpy()(读这个:http://man7.org/linux/man-pages/man3/strncpy.3p.html)。

strncpy() 的正确用法在这个答案中有解释:

基本上你会像这样使用它:

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] = '[=13=]';
}
(*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] = '[=14=]';
(*tam)++;

最后说明:我在 strncpy() 中使用 40 因为你使用 40 创建数组,但是 应该 是一个宏你会在两个地方都使用它,这样当你改变数组的大小时你不会忘记在 strncpy() 中也改变它,这会引入一个错误。使用宏是安全的,因为您只需更改一个数字,所有代码都会更新。