【问题标题】:C compiler error: undefined reference to functionC 编译器错误:未定义的函数引用
【发布时间】:2017-12-01 01:16:28
【问题描述】:

执行 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;
}

【问题讨论】:

  • 我的代码imgur.com/a/evZqc
  • my code 将您的代码作为文本添加到问题中。以及 full 错误消息。
  • 其实我只是想明白为什么会出现这样的错误,我的代码不完整
  • 你刚刚回答了自己的问题。
  • 我编辑了我的代码

标签: c struct compiler-errors


【解决方案1】:

发布的代码在main() 中定义了StudentScan()。但是 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%[] 读取字符串时,应始终指定最大宽度以避免缓冲区溢出。例如:

scanf("%19s", list[i].firstName);

请注意,使用 19,即使 firstName 字段是 20 个 char 值的数组。请记住,必须为\0 终止符保留一个空格。由于您使用%s 将字符串读入AverageNum 字段,因此您还应该:

scanf("%1s", list[i].AverageNum);

也就是说,这个字段只能保存一位数字。如果打算保留两位数,则必须将 struct 内的此字段更改为:char AverageNum[3]

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

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;
    }
}

如果未按预期输入数字,则此代码要求用户再次输入。请注意,如果用户确实输入了非数字,则此字符将保留在输入流中,并且必须在尝试处理更多用户输入之前将其清除。 while 循环是完成此任务的典型结构。

编辑

基于 OP 制作的 cmets,这里是发布代码的修改版本。此版本对structAverageNum 字段使用float 值而不是字符数组。对于存储平均值,浮点类型可能比整数类型更有用。通常最好将double 用于浮点值,但在这种情况下,AverageNum 似乎几乎不需要精度(char 数组原本打算只保存两位数); float 可能足以满足此用途。如果需要不同的类型,只需修改下面的代码即可。

实现了一些输入验证,但请注意,还可以做更多工作。当在预期输入数字的地方发现非数字输入时,提示用户输入数字。在这样的输入错误之后,输入流被while 循环构造清理;例如,最好将此代码删除到名为 clear_input() 的单独函数中。

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

填充list[] 数组的循环似乎运行效率低下,每次通过两次请求AverageNum。这已被简化。

请注意,对malloc() 的调用可以重写为:

studentp = malloc(length * sizeof *studentp);

这是编写此类分配的一种非常惯用的方式。这里,不是使用显式类型作为sizeof 的操作数,也就是说,不是sizeof (struct student),而是使用保存分配地址的变量。 sizeof 只使用了表达式*studentp 的类型,所以这里没有取消引用这个变量。在代码的维护生命周期中,当类型发生变化时,这种编码方式不易出错且更易于维护。

然而,尚不清楚为什么首先为studentp 分配内存。在发布的代码中,firstNameAverageNum 字段都在循环调用StudentScan() 时为动态分配的studentp 的成员填充;相同的循环用不同的输入填充list[]structs 的不同数组)成员的AverageNum 字段。似乎不需要studentstructs 的这些数组之一;我已经注释掉了动态分配的数组以支持静态分配的版本。

这里是修改后的代码:

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

struct student {
    char firstName[20];
    float AverageNum;
};

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: ");
    while (scanf ("%d", &length) < 1) {
        puts("Please enter a number");
        int c;
        while ((c = getchar()) != '\n' && c != EOF) {
            continue;
        }
    }

    struct student list[length];

    /* This is fine */
//    studentp = malloc(length * sizeof (struct student));

    /* But this is better */
//    studentp = malloc(length * sizeof *studentp);

//    if (studentp == NULL)
//    {
        /* Not wrong, but... */
//        printf("Out of memory!");
//        return 0;
//        fprintf(stderr, "Allocation failure\n");
//        exit(EXIT_FAILURE);
//    }

    for(i = 0; i < length; i++) {
        StudentScan(i, list);
    }

    /* Code to display results here */

//    free (studentp);

    return 0;
}

void StudentScan(int i, struct student list[])
{
    putchar('\n');
    printf("Enter first name: ");
    if (scanf("%19s", list[i].firstName) != 1) {
        puts("Input error");
        exit(EXIT_FAILURE);
    }

    printf("Enter average number: ");
    while (scanf("%f", &list[i].AverageNum) < 1) {
        puts("Please enter a number");
        int c;
        while ((c = getchar()) != '\n' && c != EOF) {
            continue;
        }
    }
}

【讨论】:

  • @Rockyy。 - 当然。我添加了更多关于对scanf() 的调用的cmets;特别是我想知道真正的意图是否是在structAverageNum 字段中只存储一位数字?
  • 我真正想做的是列出 2 个列表。一个名为 firstName 的列表将托管学生的姓名,一个名为 AverageNum 的列表将托管平均成绩(即 2digit )。例如列奥尼达斯,13 岁。约翰 09
  • 用户会给你学生的数量,你会列出这些名单。我正在尝试制作一个从键盘接收此信息的功能,以及另一个打印此信息的功能
  • 您希望将成绩存储为字符串而不是整数值的任何原因?
  • 我实际上不知道为什么,但我无法将它们存储为 int 值..(我想我只是愚蠢,我不能这样做)
【解决方案2】:

您必须从主程序中删除扫描功能。您也没有声明 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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多