我正在做一个作业,涉及到用C语言创建一个程序来创建一个使用结构数组的学生数据库。
下面是我的代码:
#include<stdio.h>
void accept(int no, struct student arr[20]);
void display(int no, struct student arr[20]);
struct student
{
char name [15];
int rollno;
float marks;
};
int main()
{
int no, n;
printf("Enter the number of students: ");
scanf("%d", &no);
struct student arr[20];
accept(no, arr);
display(no, arr);
}
void accept(int no, struct student arr[20])
{
for(int i=0; i<no; i++)
{
printf("Enter the name of the student: ");
scanf("%s", &arr[i].name);
printf("\nEnter the Roll No: ");
scanf("%d", &arr[i].rollno);
printf("\nEnter the marks: ");
scanf("%f", &arr[i].marks);
}
}
void display(int no, struct student arr[20])
{
for(int i=0; i<no; i++)
{
printf("Name: %s ", arr[i].name);
printf("Roll No: %d", arr[i].rollno);
printf("Marks: %f", arr[i].marks);
}
}
以下是我的cmd使用gcc时显示的错误:
ass3.c:5:36: error: array type has incomplete element type 'struct student'
void accept(int no, struct student arr[20]);
^~~
ass3.c:5:28: warning: 'struct student' declared inside parameter list will not be visible outside of this definition or declaration
void accept(int no, struct student arr[20]);
^~~~~~~
ass3.c:6:37: error: array type has incomplete element type 'struct student'
void display(int no, struct student arr[20]);
^~~
ass3.c:6:29: warning: 'struct student' declared inside parameter list will not be visible outside of this definition or declaration
void display(int no, struct student arr[20]);
^~~~~~~
ass3.c: In function 'main':
ass3.c:24:16: error: type of formal parameter 2 is incomplete
accept(no, arr);
^~~
ass3.c:25:17: error: type of formal parameter 2 is incomplete
display(no, arr);
^~~
ass3.c:24: confused by earlier errors, bailing out
我无法理解是什么导致了这些错误。我该如何纠正它们?我在哪里读到过,我可以用指针来解决这个问题。这是怎么回事?
2条答案
按热度按时间vc9ivgsu1#
在出现
void accept(int no, struct student arr[20]);
的地方,struct student
以前没有被声明。所以struct student
是编译器第一次看到这个结构标记。它作为标记的声明,并使编译器创建一个名为struct student
的新类型。此时,编译器只知道类型存在。它不知道结构的成员是什么,因此它不知道结构的大小。这就是所谓的不完整类型。
struct student arr[20]
声明arr
是这种类型的数组。C 2018中有一条规则6.7.6.2 1,数组的元素类型不能不完整。所以编译器会抱怨你的struct student arr[20]
声明了一个元素类型不完整的数组。因为这是参数声明,它将自动调整为指针。可以有指向不完整类型的指针;
struct student *arr
是允许的。但是,编译器在应用自动调整之前应用有关数组元素类型的规则。第二个问题是标签的作用域。如上所述,
struct student
在这个函数声明中声明了一个新的结构标记。此标记具有函数原型作用域。它的作用域在函数声明的末尾结束。当编译器稍后看到
struct student
的定义和成员定义时,这是在一个新的作用域中,并创建一个新的struct student
示例,该示例与旧示例分开。这是一个新的类型,与以前的类型不兼容。那么基本上不可能以符合C标准规则的有用方式调用此函数。因为第一个struct student
的作用域结束了,所以函数的调用者无法创建一个struct student
,并将其地址传递给函数。更糟糕的是,当定义函数时,函数定义中的参数声明无法引用与原始函数声明相同的struct student
。要解决这个问题,请将
struct student
的定义放在任何在参数声明中使用它的函数的声明之前,而不是之后。然后,当编译器在参数声明中看到struct student
时,它将把它作为对现有struct student
类型的引用,而不是作为新类型的声明。或者,您可以在函数声明之前声明
struct student;
。这将创建一个struct student
类型,其标记具有文件范围。这解决了在函数声明中新创建的类型的问题,但它没有解决不完整的元素类型问题。要解决这个问题,请将参数声明从struct student arr[20]
更改为struct student *arr
。wz3gfoph2#
在这些函数声明中:
用作函数参数的说明符的两个类型说明符
struct student
在函数原型范围之外是不可见的。它与在函数声明之后声明的结构不相同:
来自C标准(6.2.1标识符的范围)
4每个其他标识符的作用域由其声明的位置决定(在声明符或类型说明符中)。如果声明标识符的声明符或类型说明符出现在函数原型(不是函数定义的一部分)的参数声明列表中,则标识符具有函数原型作用域,该作用域在函数声明符的末尾终止
你需要首先声明结构,然后才能放置函数声明。例如
在参数列表中使用幻数
20
没有多大意义,因为编译器将函数声明调整为以下声明也就是说,具有数组类型的参数由编译器调整为指向数组元素类型的指针。
此外,第二个函数甚至应该声明为
因为传递的数组在函数中不会改变。
另外,在
main
中声明的变量n
:根据C标准,应声明如下:
不使用。
使用变量
no
从用户那里获取一个包含20个元素的数组是不安全的。相反,你可以至少声明一个可变长度的数组,比如:在scanf的这个电话中:
第二个参数表达式具有转换说明符
s
所需的错误类型。为了使通话更安全,最好这样写: