我正在做一项作业,其中涉及使用 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);
}
}
以下是我使用 gcc 在 cmd 上显示的错误:
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
我无法理解是什么导致了这些错误。我该如何纠正它们?我在某处读到可以通过使用指针来解决这个问题。这是如何运作的?
出现
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
。