C编译器错误:对函数的未定义引用 [英] C compiler error: undefined reference to function

查看:97
本文介绍了C编译器错误:对函数的未定义引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

执行exe后出现此错误:

After I execute the exe I get this error :

对"StudentScan"的未定义引用
错误:ld返回1个退出状态|

undefined reference to `StudentScan'
error: ld returned 1 exit status|

注意:我对编码不好而且还很陌生,所以请不要介意我的编码不好^^注意2:我只是在弄乱随机函数.

Note: I'm bad and new to coding so don't mind my bad coding please^^ Note2: I'm just messing with random functions.

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

推荐答案

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

The posted code has defined StudentScan() within main(). But nested function definitions are not allowed in C. This should generate a compiler warning, such as:

警告:ISO C禁止嵌套函数[-Wpedantic]
void StudentScan(int i,结构学生列表[])

warning: ISO C forbids nested functions [-Wpedantic]
void StudentScan(int i, struct student list[])

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

Pay attention to all compiler warnings and fix them. If no warning is seen when compiling this code, turn up the level of compiler warnings. On gcc, I suggest to always use at least gcc -Wall -Wextra, and I always add -Wpedantic. The -Wpedantic is needed with gcc to see a warning for this. Some compilers, and gcc is one of these, do support nested function definitions as a compiler extension. Still, this feature is nonstandard, and it is best to not rely on it.

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

The fix is simple: move the definition of StudentScan() out of 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);
}

还请注意,在使用%s %[] scanf()系列函数读取字符串时,应始终指定最大宽度避免缓冲区溢出.例如:

Also note that you should always specify maximum widths when reading strings using scanf() family functions with %s or %[] to avoid buffer overflow. For example:

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

请注意,即使 firstName 字段是20个 char 值的数组,也将使用19.请记住,必须为 \ 0 终止符保留一个空格.并且由于您正在使用%s 将字符串读取到 AverageNum 字段中,因此您还应该具有:

Note that 19 is used, even though the firstName field is an array of 20 char values. Remember that one space must be reserved for the \0 terminator. And since you are using %s to read a string into the AverageNum field, you should also have:

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

即,此字段只能保留一位数字.如果要保留两位数,则必须在 struct 中将此字段更改为: char AverageNum [3] .

That is, this field can only hold one digit. If the intention is to hold two digits, this field must be changed within the struct to: char AverageNum[3].

在讨论 scanf()时,请注意,此函数返回在函数调用期间成功进行分配的次数.如果未进行分配,则返回0.此返回值应始终进行检查.请考虑:如果用户在期望输入数字时错误地输入了字母,则预期的变量中将不存储任何内容.这可能导致不确定的行为.您可以尝试执行以下操作来验证数字输入:

And while we are discussing scanf(), note that this function returns the number of successful assignments made during the function call. If no assignments are made, 0 is returned. This return value should always be checked. Consider: if the user mistakenly enters a letter when a digit is expected, nothing is stored in the intended variable. This may lead to undefined behavior. You may try something like this to validate numeric input:

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 循环是完成此任务的典型构造.

This code asks the user to enter input again if a number is not entered when expected. Note that if the user does enter a non-digit, this character remains in the input stream and must be cleared before attempting to process more user input. The while loop is a typical construction which accomplishes this task.

根据OP的评论,这是发布代码的修改版本.此版本使用 float 值代替 struct AverageNum 字段的字符数组.对于存储平均值,浮点类型可能比整数类型更有用.通常最好对浮点值使用 double ,但是在这种情况下, AverageNum 看起来几乎不需要精度( char 数组只能容纳两位数); float 可能足以用于此用途.如果需要使用其他类型,则修改下面的代码就足够简单了.

Based on comments made by the OP, here is a modified version of the posted code. This version uses a float value instead of a character array for the AverageNum field of the struct. A floating-point type may be more useful than an integer type for storing averages. It is usually best to use double for floating-point values, but in this case it looks like AverageNum has little need for precision (the char array was intended to hold only two digits); float is probably sufficient for this use. If a different type is desired, it is simple enough to modify the code below.

实现了一些输入验证,但是请注意,还可以做更多的工作.当发现非数字输入时,要求用户输入数字,这是希望输入数字的地方.输入错误后,将使用 while 循环构造清除输入流;例如,最好将此代码删除到名为 clear_input()的单独函数中.

Some input validation is implemented, but note that more could be done. The user is prompted to enter a number when non-numeric input is found where numeric input is expected. The input stream is cleaned with the while loop construction after such an input mistake; it would be good to remove this code to a separate function called clear_input(), for example.

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

If the user signals end-of-file from the keyboard, scanf() will return EOF; the code below chooses to exit with an error message rather than continue with malformed input in this case. This could also occur with input redirected from a file, and this condition may need to be handled differently if such input is expected.

填充 list [] 数组的循环似乎运行效率低下,每遍请求两次 AverageNum .这已经简化了.

The loop that populated the list[] array seemed to be operating inefficiently, asking for AverageNum twice in each pass. This has been streamlined.

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

Note that the call to malloc() can be rewritten as:

studentp = malloc(length * sizeof *studentp);

这是编写此类分配的非常惯用的方式.在这里,不是使用显式类型作为 sizeof 的操作数,即代替了 sizeof(struct student)的操作数,而是使用保存分配地址的变量. sizeof 仅使用表达式 * studentp 的类型,因此此处未取消引用此变量.这种方式编码的代码较少出错,并且在代码的维护期内更改类型时更易于维护.

This is a very idiomatic way of writing such an allocation. Here, instead of using an explicit type as the operand of sizeof, that is, instead of sizeof (struct student), the variable which holds the address of the allocation is used. sizeof only uses the type of the expression *studentp, so this variable is not dereferenced here. Coding this way is less error-prone and easier to maintain when types change during the maintenance life of the code.

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

Yet, it is unclear why memory is allocated for studentp in the first place. In the posted code, both the firstName and AverageNum fields are filled for members of the dynamically allocated studentp in calls to StudentScan() in a loop; the same loop fills the AverageNum field of the members of list[] (a different array of structs) with different input. There seems to be no need for one of these arrays of student structs; I have commented-out the dynamically allocated array in favor of the statically allocated version.

这是修改后的代码:

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

这篇关于C编译器错误:对函数的未定义引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆