多文件(工程)编译常见问题:
- 隐式声明:没有声明该函数。
解决方式:在工程头文件head.h中,添加该函数的声明。
- gcc链接器未发现函数(未定义函数)(全局变量同理)
解决方式:寻找所有编译的.c文件中是否存在该函数。
- gcc链接器发现多个同名函数(多重定义)(全局变量同理)
解决方式:打开提示的2个文件,删除掉其中的无用函数,或者修改其中一个的函数名。
练习:
根据proj2,定义结构体数组(长度50),初始化3个用户的信息。
需将usr_login函数移到usr.c中
修改usr_login函数,使得可以判断多个用户。
要求用户uid和密码可多次输入,当超过3次,提示次数过多,结束程序。
登录成功后,显示操作菜单:0: 显示用户信息 usr_show()
1: 修改密码 usr_update()
2: 新增用户 usr_add()
3: 删除用户 usr_del()
先完成修改密码功能,完成后思考一下如何实现用户新增、删除?
(可以添加显示信息功能,查看密码是否修改成功。)
练习:
参考proj1文件夹,创建一个自己的工程,放入4个文件:
main.c 放入main主函数
square.c 放入计算平方、立方函数。
sum.c 放入加减乘除的4个函数
head.h 工程头文件
在main函数中都使用子函数,计算一下。
head.h
#ifndef _HEAD_H #define _HEAD_H #include <stdio.h> /********** square.c函数声明 ***********/ // 计算a的平方 extern int func_square(int a); // 计算a的立方 extern int func_cube(int a); /********** sum.c函数声明 ***********/ // 计算两数之和 extern int func_sum(int a, int b); #endif
main.c
#include "head.h" int main() { int a=3, b=4; int a2=func_square(a); int b2=func_square(b); int sum = func_sum(a2, b2); printf("sum: %d\n", sum); int a3=func_cube(a); printf("a3: %d\n", a3); return 0; }
square.c
// 计算a的平方 int func_square(int a) { return a*a; } // 计算a的立方 int func_cube(int a) { return a*a*a; }
sum.c
// 计算两数之和 int func_sum(int a, int b) { return a+b; }
head.h
#ifndef _HEAD_H #define _HEAD_H // 系统头文件 #include <stdio.h> #include <string.h> // 类型声明 typedef unsigned int u32; // 用户信息结构体声明 struct usr{ u32 uid; // 1.用户ID char pwd[20]; // 2.用户密码(长度限定20字符) }; // 子函数外部声明 // 用户登录功能 extern int usr_login(int sum, struct usr *info); // 显示用户信息 extern void usr_show(int sum, struct usr *info); // 修改密码 extern void usr_update(int i, struct usr *info); // 新增用户 extern void usr_add(void); // 删除用户 extern void usr_del(void); #endif
main.c
#include "head.h" int main() { // 定义1个结构体数组 struct usr info[50] = { { .uid=1, .pwd="123456" }, { .uid=2, .pwd="223456" }, { .uid=100, .pwd="323456" } }; int sum=3; //当前人数(当前有效数据个数) // goto pos1; // 直接跳转到44行(调试结束后记得删除!) // 1.用户登录功能 int cnt=0; int ret; while(1) { ret = usr_login(sum, info); // printf("ret: %d\n", ret); if(ret >= 0) break; else if(ret == -1) printf("No Such User!\n"); else if(ret == -2) printf("Password ERROR!\n"); cnt++; printf("ERROR count: %d\n", cnt); if(cnt>3) { printf("byebye~\n"); return -1; //结束程序 } } printf("[%d] Success!\n", info[ret].uid); // pos1: // 2.用户操作 int cmd; while(1) { printf("=============CMD==============\n"); printf("0: 显示用户信息\n"); printf("1: 修改密码 \n"); printf("2: 新增用户\n"); printf("3: 删除用户\n"); printf("==============================\n"); printf("Pls Input CMD: "); scanf("%d", &cmd); while(getchar()!='\n'); switch(cmd) { case 0: //显示用户信息 usr_show(sum, info); break; case 1: //修改密码 usr_update(ret, info); break; case 2: //新增用户 usr_add(); break; case 3: //删除用户 usr_del(); break; } } return 0; }
usr.c
#include "head.h" // 用户登录功能 int usr_login(int sum, struct usr *info) { // 1.用户输入uid和密码 struct usr input_info; printf("Pls Input uid: "); scanf("%d", &input_info.uid); while(getchar()!='\n'); printf("Pls Input pwd: "); scanf("%s", input_info.pwd); while(getchar()!='\n'); // 2.循环判断用户输入 int i; for(i=0; i<sum; i++) { if(input_info.uid == info[i].uid) // ID判断 { // 进一步判断密码 if(strcmp(input_info.pwd, info[i].pwd) == 0) return i; // ID、密码正确,返回正确用户的下标 else return -2; // 密码错误 } } // 如果for正常循环完毕,说明不存在该ID if(i==sum) return -1; } // 显示用户信息(用于调试) void usr_show(int sum, struct usr *info) { int i; printf("============INFO============\n"); printf("UID\t PWD\n"); for(i=0; i<sum; i++) printf("%d\t %s\n", info[i].uid, info[i].pwd); } // 修改密码 void usr_update(int i, struct usr *info) { // 1.用户输入新密码 char input_pwd[20]; printf("Pls Input new pwd: "); scanf("%s", input_pwd); while(getchar()!='\n'); // 2.将新密码替换旧密码 // info[i].pwd = input_pwd; // 字符串不能直接赋值到数组中!需使用字符串拷贝函数 strcpy(info[i].pwd, input_pwd); } // 新增用户 void usr_add(void) { printf("usr_add 功能待完善...\n"); } // 删除用户 void usr_del(void) { printf("usr_del 功能待完善...\n"); }
head.h
#ifndef _HEAD_H #define _HEAD_H // 系统头文件 #include <stdio.h> #include <string.h> // 类型声明 typedef unsigned int u32; // 用户信息结构体声明 struct usr{ u32 uid; // 1.用户ID char pwd[20]; // 2.用户密码(长度限定20字符) }; // 子函数外部声明 // 用户登录功能 extern int usr_login(int sum, struct usr *info); // 显示用户信息 extern void usr_show(int sum, struct usr *info); // 修改密码 extern void usr_update(int i, struct usr *info); // 新增用户 extern void usr_add(void); // 删除用户 extern void usr_del(void); #endif
main.c
#include "head.h" int main() { // 定义1个结构体数组 struct usr info[50] = { { .uid=1, .pwd="123456" }, { .uid=2, .pwd="223456" }, { .uid=100, .pwd="323456" } }; int sum=3; //当前人数(当前有效数据个数) // goto pos1; // 直接跳转到44行(调试结束后记得删除!) // 1.用户登录功能 int cnt; int ret; for(cnt=2; cnt>=0; cnt--) // 2 1 0 { ret = usr_login(sum, info); // printf("ret: %d\n", ret); if(ret >= 0) // 如正确,直接跳出 break; else if(ret == -1) printf("ERROR: 无此用户![还剩%d次机会.]\n", cnt); else if(ret == -2) printf("ERROR: 密码错误![还剩%d次机会.]\n", cnt); } if(cnt<0) { printf("3次错误! 程序结束!\n"); return -1; } printf("欢迎登陆! 用户ID: [%d]!\n", info[ret].uid); // pos1: // 2.用户操作 int cmd; while(1) { printf("=============CMD==============\n"); printf("0: 显示用户信息\n"); printf("1: 修改密码 \n"); printf("2: 新增用户\n"); printf("3: 删除用户\n"); printf("==============================\n"); printf("Pls Input CMD: "); scanf("%d", &cmd); while(getchar()!='\n'); switch(cmd) { case 0: //显示用户信息 usr_show(sum, info); break; case 1: //修改密码 usr_update(ret, info); break; case 2: //新增用户 usr_add(); break; case 3: //删除用户 usr_del(); break; } } return 0; }
usr.c
#include "head.h" // 用户登录功能 int usr_login(int sum, struct usr *info) { // 1.用户输入uid和密码 struct usr input_info; printf("Pls Input uid: "); scanf("%d", &input_info.uid); while(getchar()!='\n'); printf("Pls Input pwd: "); scanf("%s", input_info.pwd); while(getchar()!='\n'); // 2.循环判断用户输入 int i; for(i=0; i<sum; i++) { if(input_info.uid == info[i].uid) // ID判断 { // 进一步判断密码 if(strcmp(input_info.pwd, info[i].pwd) == 0) return i; // ID、密码正确,返回正确用户的下标 else return -2; // 密码错误 } } // 如果for正常循环完毕,说明不存在该ID if(i==sum) return -1; } // 显示用户信息(用于调试) void usr_show(int sum, struct usr *info) { int i; printf("============INFO============\n"); printf("UID\t PWD\n"); for(i=0; i<sum; i++) printf("%d\t %s\n", info[i].uid, info[i].pwd); } // 修改密码 void usr_update(int i, struct usr *info) { // 1.用户输入新密码 char input_pwd[20]; printf("Pls Input new pwd: "); scanf("%s", input_pwd); while(getchar()!='\n'); // 2.将新密码替换旧密码 // info[i].pwd = input_pwd; // 字符串不能直接赋值到数组中!需使用字符串拷贝函数 strcpy(info[i].pwd, input_pwd); } // 新增用户 void usr_add(void) { printf("usr_add 功能待完善...\n"); } // 删除用户 void usr_del(void) { printf("usr_del 功能待完善...\n"); }