C编译器错误:未定义的函数引用

时间:2017-12-01 01:16:29

标签: c struct compiler-errors

执行exe后,我收到此错误:

  

未定义参考`StudentScan'
  错误:ld返回1退出状态|

注意:我对编码很不好,所以请不要介意我的编码错误^^ 注2:我只是搞乱随机函数。

#include <stdio.h>
#include <stdlib.h>

struct student {
char firstName[20];
char AverageNum[2];
};
void StudentScan(int, struct student[]);
void StudentPrint(int, struct student[]);

int main() {
int i;
int length;
struct student *studentp;
printf ("\nEnter the host of students: ");
scanf ("%d ", &length);
struct student list[length];

studentp=malloc(length*sizeof(struct student));

if (studentp==NULL)
{
    printf("Out of memory!");
    return 0;
}

for(i = 0; i < length; i++) {
StudentScan(i,studentp);
printf("\nEnter average number: ");
scanf("%s", list[i].AverageNum);
}
free (studentp);

   void StudentScan(int i, struct student list[])
{  printf("\nEnter first name : ");
  scanf("%s", list[i].firstName);
  printf("\nEnter average number: ");
  scanf("%s", list[i].AverageNum);
}



return 0;
}

2 个答案:

答案 0 :(得分:1)

已发布的代码已在StudentScan()中定义main()。但是C中不允许嵌套函数定义。这应该生成编译器警告,例如:

  

警告:ISO C禁止嵌套函数[-Wpedantic]
       void StudentScan(int i,struct student list [])

注意所有编译器警告并修复它们。如果在编译此代码时未看到警告,请调高编译器警告的级别。在gcc上,我建议始终至少使用gcc -Wall -Wextra,并且我总是添加-Wpedantic。 gcc需要-Wpedantic才能看到此警告。一些编译器和gcc就是其中之一, do 支持嵌套函数定义作为编译器扩展。尽管如此,这个功能还是非标准的,最好不要依赖它。

修复很简单:将StudentScan()的定义移出main()

#include <stdio.h>
#include <stdlib.h>

struct student {
    char firstName[20];
    char AverageNum[2];
};
void StudentScan(int, struct student[]);
void StudentPrint(int, struct student[]);

int main(void) {
    int i;
    int length;
    struct student *studentp;
    printf ("\nEnter the host of students: ");
    scanf ("%d ", &length);
    struct student list[length];

    studentp=malloc(length*sizeof(struct student));

    if (studentp==NULL)
    {
        printf("Out of memory!");
        return 0;
    }

    for(i = 0; i < length; i++) {
        StudentScan(i,studentp);
        printf("\nEnter average number: ");
        scanf("%s", list[i].AverageNum);
    }
    free (studentp);

    return 0;
}

void StudentScan(int i, struct student list[])
{  printf("\nEnter first name : ");
    scanf("%s", list[i].firstName);
    printf("\nEnter average number: ");
    scanf("%s", list[i].AverageNum);
}

另请注意,在使用带有scanf()%s的{​​{1}}族函数读取字符串时,应始终指定最大宽度,以避免缓冲区溢出。例如:

%[]

请注意,即使scanf("%19s", list[i].firstName); 字段是包含20个firstName值的数组,也会使用19。请记住,必须为char终结符保留一个空格。由于您使用\0将字符串读入%s字段,因此您还应该:

AverageNum

也就是说,这个字段只能容纳一位数。如果打算保留两位数,则必须在scanf("%1s", list[i].AverageNum); 内将此字段更改为:struct

在我们讨论char AverageNum[3]时,请注意此函数返回函数调用期间成功分配的次数。如果未进行任何分配,则返回0。应该总是检查此返回值。考虑:如果用户在预期数字时错误地输入了一个字母,则没有任何内容存储在预期的变量中。这可能会导致未定义的行为。您可以尝试这样的方法来验证数字输入:

scanf()

如果在预期时未输入数字,此代码会要求用户再次输入输入。请注意,如果用户 输入非数字,则此字符将保留在输入流中,并且必须先清除,然后再尝试处理更多用户输入。 printf ("\nEnter the host of students: "); while (scanf ("%d ", &length) < 1) { puts("Please enter a number"); int c; while ((c = getchar()) != '\n' && c != EOF) { continue; } } 循环是完成此任务的典型构造。

修改

根据OP的评论,这里是已发布代码的修改版本。对于while的{​​{1}}字段,此版本使用float值而不是字符数组。浮点类型可能比整数类型更有用于存储平均值。通常最好使用AverageNum作为浮点值,但在这种情况下看起来struct几乎不需要精度(double数组只能保存两位数) ; AverageNum可能足以满足此用途。如果需要不同的类型,则修改下面的代码非常简单。

已实施某些输入验证,但请注意可以执行更多操作。当找到期望数字输入的非数字输入时,提示用户输入数字。在输入错误之后,使用char循环结构清理输入流;例如,将此代码移除到名为float的单独函数中会很好。

如果用户通过键盘发出文件结束信号,while将返回clear_input();下面的代码选择退出并显示错误消息,而不是在这种情况下继续输入格式错误的输入。对于从文件重定向的输入也可能发生这种情况,如果需要这样的输入,则可能需要以不同方式处理此情况。

填充scanf()数组的循环似乎运行效率低,每次传递都要求EOF两次。这已经简化了。

请注意,对list[]的调用可以重写为:

AverageNum

这是编写此类分配的非常惯用的方式。这里,不使用显式类型作为malloc()的操作数,而是使用保存分配地址的变量而不是studentp = malloc(length * sizeof *studentp); sizeof仅使用表达式sizeof (struct student)的类型,因此此变量不会在此处取消引用。在代码的维护生命周期中,当类型发生变化时,以这种方式编码不易出错,并且更易于维护。

然而,目前尚不清楚为什么首先为sizeof分配内存。在发布的代码中,*studentpstudentp字段都填充了循环调用firstName中动态分配的AverageNum的成员;同一个循环使用不同的输入填充studentp成员的StudentScan()字段(AverageNum s的不同数组)。似乎不需要其中一个list[] struct s阵列;我已经注释掉动态分配的数组,转而使用静态分配的版本。

以下是修改后的代码:

student

答案 1 :(得分:0)

您必须从主屏幕中删除扫描功能。此外,您没有声明的printstudent功能。您必须从printf和scanf函数中删除/ n并相应地放置它们。然后,您可以使用简单的循环测试是否在结构中正确添加了数据。

#include <stdio.h>
#include <stdlib.h>

struct student {

    char firstName[20];
    char AverageNum[2];

};

int main() {

    int i=0;
    int length;
    struct student *studentp;
    printf ("Enter the host of students:");
    scanf ("%d", &length);
    struct student list[length];

    studentp=malloc(length*sizeof(struct student));

    if (studentp==NULL)
    {
        printf("Out of memory!");
        return 0;
    }

    for(i = 0; i < length; i++) {

        printf("Enter first name :");
        scanf("%s", list[i].firstName);
        printf("Enter average number: ");
        scanf("%1s", list[i].AverageNum);

    }

    for(i = 0; i< length; i++){
        printf("number of host is: %d , his/her first name: %s , his/her avg number: %s \n", i, list[i].firstName, list[i].AverageNum);
    }
    free (studentp);

    return 0;
}