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

2023-12-02

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

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

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

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

修复方法很简单:移动 的定义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);
}

另请注意,在使用读取字符串时应始终指定最大宽度scanf()家庭功能与%s or %[]以避免缓冲区溢出。例如:

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

请注意,尽管使用了 19firstName字段是一个 20 的数组char价值观。请记住,必须为以下内容保留一个空间\0终结者。既然你正在使用%s将字符串读入AverageNum字段,您还应该有:

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

也就是说,该字段只能保存一位数字。如果打算保留两位数字,则必须在以下时间内更改此字段struct to: char AverageNum[3].

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

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

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

Edit

根据 OP 的评论,这里是已发布代码的修改版本。这个版本使用了一个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仅使用表达式的类型*studentp,所以这里没有取消引用该变量。当类型在代码的维护生命周期内发生变化时,以这种方式编码更不容易出错并且更易于维护。

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

这是修改后的代码:

#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;
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C 编译器错误:未定义的函数引用 的相关文章

随机推荐

  • 监控和维护应用程序在光盘上的大小的解决方案

    我正在构建一个广泛使用 CoreData 的应用程序 并且我的许多模型都具有 UIImage 和 NSData 属性 用于图像和视频 由于将数据直接存储到 CoreData 中并不是一个好主意 因此我构建了一个文件管理器类 该类根据创建的上
  • RapidXML 给出空的 CDATA 节点

    我编写了下面的代码来获取 CDATA 节点值 我得到了节点的名称 但值是空白的 我将解析标志更改为 parse full 但它也不起作用 如果我从 XML 中手动删除 它会给出预期的值 但在解析之前删除它不是一个选项 代码 include
  • Promises - 在 Promise.all 中捕获所有拒绝[重复]

    这个问题在这里已经有答案了 我有这个虚拟代码 var Promise require bluebird function rej1 return new Promise reject new Error rej1 function rej2
  • Bootstrap 导航栏在滚动时折叠

    我在我的项目中使用引导灰度主题 它有一个在滚动时折叠的导航栏 或者如果我转到同一页面上的链接 download 等 问题是当我从其他页面转到锚链接时 导航栏在滚动之前不会折叠 我想解决方案是在java脚本中添加该行 但我真的不知道要添加什么
  • 如何解决OSError:[WinError 2]不可能找到指定文件:'c:\\ python39 \\ Scripts \\ chardetect.exe'

    正如标题中所述 每次我尝试通过 pip 安装某些内容时 在安装结束时都会出现错误 WARNING Failed to write executable trying to use deleteme logic Rolling back un
  • 如何获取JRadioButton的文本值

    我正在用java创建一个项目 我的程序有 80 个 JRadioButtons 我需要获取它们的文本值 现在这些单选按钮已添加到 ButtonGroup 每个单选按钮有 4 个单选按钮 我知道如何通过以下代码从单选按钮获取文本值 radio
  • 如何不屏蔽 GitHub Actions 中的输出?

    作为 GitHub Actions 中 PowerShell 脚本的一部分 我尝试输出一个 json 对象列表 以便稍后作为另一个作业的矩阵重新使用 使用以下命令我将编写输出 Write Host set output name value
  • XSLT 更改元素中的名称空间

    我正在尝试使用以下 xsl 代码更改元素属性的命名空间
  • ZendGdata框架路径设置错误

    你好 我正在使用 ZendGdata 1 12 5 框架在 youtube 上上传视频 我在我的 php 代码中使用了以下内容 path ZendGdata 1 12 5 library set include path get inclu
  • 如何使用 WS-UsernameToken 获取结果摘要?

    我有来自以下文档ONVIF 程序员指南 我目前正在尝试重现结果摘要使用指南中给出的相同条目 这是我的代码 private string GenerateHashedPassword string nonce string created s
  • Cassandra 无法在 Java 10 上启动

    我有一个全新的 Windows 10 家庭版安装 并全新安装了 JDK 10 0 1 这是我访问 JDK 下载站点时 Oracle 推荐的安装版本 我刚刚下载了 Cassandra 3 11 2 解压缩 d 它 并将 bin 目录放在我的类
  • firebase 云函数 API Google Cloud Storage 错误

    随着 Firebase Cloud Functions 的推出 我们正在考虑将当前的一些 Node js 服务器端代码迁移到云函数 我遇到的一个问题是从 GCS 存储桶下载文件到磁盘上的临时文件 然后将其作为附件通过电子邮件发送 使用 ma
  • 在初始 init“firebase”后添加/编辑 pod 文件

    因此 当我将 pod 文件安装到我的项目中时 我忘记添加到 FirebaseDatabase 中 现在我想将其添加到我该如何做 再次执行 pod init 过程会不会把事情弄乱 我的 Pod 文件照片 您应该只添加所需的新 Pod 然后运行
  • Vanilla JS 中具有 Momentum 的水平滚动

    我目前正在开发一个项目 我想要一个水平滑块 我使这个滑块可拖动 并找到了一些代码使其能够随动量滑动 我设法用鼠标滚轮进行水平滚动 但我不知道如何使其与动量效果一起工作 我能怎么做 Lorem ipsum dolor sat amet con
  • 带 Ifelse 条件的 Cbind/Rbind

    这是我正在使用的代码 x lt c Yes No No Yes Maybe y lt t 1 10 z lt t 11 20 rbind data frame ifelse x Yes y z 这会产生 X1L X12L X13L X4L
  • 提升.Interprocess notification() 性能

    我有两个进程 A 和 B 它们应该在 Windows 10 上使用 Boost Interprocess 通过共享内存快速交换数据 我的问题 之间的时间notify all 和wait 似乎很慢 通常为 15 毫秒 我最终编写了一个简单的应
  • 文字分隔符( \Q \E 块内的分隔符)

    我一直在尝试制作一些基于的功能RegEx他们中的大多数人都使用 Q and E作为一些RegEx pattern是用户输入 所以 假设我们正在使用delimiter 并想将其与 该函数将在以下行中构造一些东西 Q E 我不知道为什么 Q E
  • 阻止对 docker 容器的外部访问[关闭]

    Closed 这个问题不符合堆栈溢出指南 目前不接受答案 我想阻止从外部直接访问 docker 容器 我使用 haproxy 希望只允许访问端口 80 443 我在 iptables 中添加了以下规则 但我仍然可以通过不同的端口访问 doc
  • 在类中使用 boost::numeric::odeint

    对于模拟 我使用 boost numeric odeint 但遇到问题 我在我的一个类的方法中使用集成函数 但出现 没有匹配的函数可用于调用集成 的错误 为了更清楚 这是我的代码的压缩版本 include MotionGeneration
  • C 编译器错误:未定义的函数引用

    执行 exe 后 我收到此错误 对 StudentScan 的未定义引用错误 ld 返回 1 退出状态 注意 我的编码能力很差 而且是新手 所以请不要介意我的糟糕编码 注2 我只是在搞乱随机函数 include