C语言 为什么会出现这个错误:数组类型有不完整的元素类型,形参类型不完整?

mkh04yzy  于 2023-10-16  发布在  其他
关注(0)|答案(2)|浏览(583)

我正在做一个作业,涉及到用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

我无法理解是什么导致了这些错误。我该如何纠正它们?我在哪里读到过,我可以用指针来解决这个问题。这是怎么回事?

vc9ivgsu

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

wz3gfoph

wz3gfoph2#

在这些函数声明中:

void accept(int no, struct student arr[20]); 
void display(int no, struct student arr[20]);

用作函数参数的说明符的两个类型说明符struct student在函数原型范围之外是不可见的。
它与在函数声明之后声明的结构不相同:

struct student
{
    char name [15];
    int rollno;
    float marks;
};

来自C标准(6.2.1标识符的范围)
4每个其他标识符的作用域由其声明的位置决定(在声明符或类型说明符中)。如果声明标识符的声明符或类型说明符出现在函数原型(不是函数定义的一部分)的参数声明列表中,则标识符具有函数原型作用域,该作用域在函数声明符的末尾终止
你需要首先声明结构,然后才能放置函数声明。例如

struct student
{
    char name [15];
    int rollno;
    float marks;
};

void accept(int no, struct student arr[20]); 
void display(int no, struct student arr[20]);

在参数列表中使用幻数20没有多大意义,因为编译器将函数声明调整为以下声明

void accept(int no, struct student *arr); 
void display(int no, struct student *arr);

也就是说,具有数组类型的参数由编译器调整为指向数组元素类型的指针。
此外,第二个函数甚至应该声明为

void display(int no, const struct student *arr);

因为传递的数组在函数中不会改变。
另外,在main中声明的变量n

int main()
{
    int no, n;
    //...
}

根据C标准,应声明如下:

int man( vood )

不使用。
使用变量no从用户那里获取一个包含20个元素的数组是不安全的。相反,你可以至少声明一个可变长度的数组,比如:

int no;

printf("Enter the number of students: ");
if ( scanf("%d", &no) == 1 && no > 0 )
{
    struct student arr[no];
    accept(no, arr);
    display(no, arr);
}

在scanf的这个电话中:

scanf("%s", &arr[i].name);

第二个参数表达式具有转换说明符s所需的错误类型。为了使通话更安全,最好这样写:

scanf("%14s", arr[i].name);

相关问题