结构数组作为参数和访问成员混淆
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
的数组将是:
a
是 struct
的数组。
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()
中也改变它,这会引入一个错误。使用宏是安全的,因为您只需更改一个数字,所有代码都会更新。
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
的数组将是:
a
是 struct
的数组。
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()
中也改变它,这会引入一个错误。使用宏是安全的,因为您只需更改一个数字,所有代码都会更新。