C语言客户端程序:如何读取文件最后ID及文件变量读取方法
嘿,我来帮你搞定这两个问题,咱们先从代码里的基础错误改起,不然连编译都通不过,再一步步解决你的核心需求~
先修正代码里的编译错误
你现在的代码里,client cl;和client c[nombre_de_clients];写在了typedef struct client的前面,编译器根本不知道client是什么类型,所以必须把结构体定义移到变量声明之前。调整后的结构体和变量顺序应该是这样:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define nombre_de_clients 50 // 先定义日期结构体 typedef struct date{ int j,m,a; } date; // 再定义客户端结构体 typedef struct client{ int id; char nom [30]; char prenom [30]; date date_nais; char adresse[30] ; char tel [30]; } client; // 现在才能声明client类型的变量 client cl; client c[nombre_de_clients];
问题1:重启程序后ID不再重置,读取最后一个ID
你现在每次启动程序都把cl.id设为1,所以重启后自然会从头开始。要解决这个,咱们可以写一个函数,在程序启动时读取client.txt的最后一个客户端ID,然后把cl.id设为这个ID+1(如果文件为空,就设为1)。
你的文件里每个客户端占6行,最后一行是ID,所以咱们可以遍历文件的所有行,记录最后一个有效ID:
// 获取文件中最后一个客户端的ID int get_last_client_id() { FILE *f = fopen("client.txt", "r"); if (!f) { // 文件不存在,返回0,后续cl.id设为0+1=1 return 0; } int last_id = 0; char line[100]; // 遍历所有行,每6行是一个客户端,最后一行是ID int line_count = 0; while (fgets(line, sizeof(line), f) != NULL) { line_count++; // 每第6行是ID if (line_count % 6 == 0) { // 把字符串转成整数 sscanf(line, "%d", &last_id); } } fclose(f); return last_id; }
然后在main函数里,把cl.id=1;改成:
cl.id = get_last_client_id() + 1;
这样每次启动程序,就会自动从文件里拿到最后一个ID,然后从下一个数开始分配。
问题2:从文件中读取所有客户端变量
如果需要把文件里的所有客户端信息加载到数组c里,咱们可以写一个加载函数,逐行读取每个字段:
// 从文件加载所有客户端到数组c中,并返回已加载的客户端数量 int load_clients() { FILE *f = fopen("client.txt", "r"); if (!f) { return 0; } int client_count = 0; char line[100]; while (client_count < nombre_de_clients) { // 读取nom if (!fgets(c[client_count].nom, sizeof(c[client_count].nom), f)) break; // 去掉换行符 c[client_count].nom[strcspn(c[client_count].nom, "\n")] = '\0'; // 读取prenom if (!fgets(c[client_count].prenom, sizeof(c[client_count].prenom), f)) break; c[client_count].prenom[strcspn(c[client_count].prenom, "\n")] = '\0'; // 读取adresse if (!fgets(c[client_count].adresse, sizeof(c[client_count].adresse), f)) break; c[client_count].adresse[strcspn(c[client_count].adresse, "\n")] = '\0'; // 读取tel if (!fgets(c[client_count].tel, sizeof(c[client_count].tel), f)) break; c[client_count].tel[strcspn(c[client_count].tel, "\n")] = '\0'; // 读取date_nais(格式是jj/mm/aaaa) if (!fgets(line, sizeof(line), f)) break; sscanf(line, "%d/%d/%d", &c[client_count].date_nais.j, &c[client_count].date_nais.m, &c[client_count].date_nais.a); // 读取id if (!fgets(line, sizeof(line), f)) break; sscanf(line, "%d", &c[client_count].id); client_count++; } fclose(f); // 更新cl.id为下一个可用ID if (client_count > 0) { cl.id = c[client_count-1].id + 1; } else { cl.id = 1; } return client_count; }
然后在main函数开头调用这个函数:
int main(){ int a; // 加载已有的客户端 int loaded_count = load_clients(); printf("已加载%d个客户端\n", loaded_count); // ... 后面的菜单代码 }
修改后的完整代码
把上面的所有部分整合起来,完整代码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define nombre_de_clients 50 typedef struct date{ int j,m,a; } date; typedef struct client{ int id; char nom [30]; char prenom [30]; date date_nais; char adresse[30] ; char tel [30]; } client; client cl; client c[nombre_de_clients]; // 获取文件中最后一个客户端的ID(如果不需要加载所有数据,用这个函数即可) int get_last_client_id() { FILE *f = fopen("client.txt", "r"); if (!f) { return 0; } int last_id = 0; char line[100]; int line_count = 0; while (fgets(line, sizeof(line), f) != NULL) { line_count++; if (line_count % 6 == 0) { sscanf(line, "%d", &last_id); } } fclose(f); return last_id; } // 从文件加载所有客户端到数组c中 int load_clients() { FILE *f = fopen("client.txt", "r"); if (!f) { return 0; } int client_count = 0; char line[100]; while (client_count < nombre_de_clients) { // 读取nom if (!fgets(c[client_count].nom, sizeof(c[client_count].nom), f)) break; c[client_count].nom[strcspn(c[client_count].nom, "\n")] = '\0'; // 读取prenom if (!fgets(c[client_count].prenom, sizeof(c[client_count].prenom), f)) break; c[client_count].prenom[strcspn(c[client_count].prenom, "\n")] = '\0'; // 读取adresse if (!fgets(c[client_count].adresse, sizeof(c[client_count].adresse), f)) break; c[client_count].adresse[strcspn(c[client_count].adresse, "\n")] = '\0'; // 读取tel if (!fgets(c[client_count].tel, sizeof(c[client_count].tel), f)) break; c[client_count].tel[strcspn(c[client_count].tel, "\n")] = '\0'; // 读取date_nais if (!fgets(line, sizeof(line), f)) break; sscanf(line, "%d/%d/%d", &c[client_count].date_nais.j, &c[client_count].date_nais.m, &c[client_count].date_nais.a); // 读取id if (!fgets(line, sizeof(line), f)) break; sscanf(line, "%d", &c[client_count].id); client_count++; } fclose(f); if (client_count > 0) { cl.id = c[client_count-1].id + 1; } else { cl.id = 1; } return client_count; } void ajouter(){ FILE *f; f=fopen("client.txt","a+"); // 注意:这里应该用cl.id-1作为数组下标,因为cl.id是下一个要分配的ID int current_id_index = cl.id - 1; printf("donnez le nom \n"); scanf("%s",c[current_id_index].nom); // 这里不需要&,因为数组名本身是指针 printf("donnez le prenom:"); scanf("%s",c[current_id_index].prenom); printf("donnez l'adresse:"); scanf("%s",c[current_id_index].adresse); printf("donnez num de tel:"); scanf("%s",c[current_id_index].tel); printf("donnez la date de naissance jj mm aaaa:"); scanf("%d %d %d",&c[current_id_index].date_nais.j,&c[current_id_index].date_nais.m,&c[current_id_index].date_nais.a); // 写入文件时,ID是当前的cl.id fprintf(f,"%s\n%s\n%s\n%s\n%d/%d/%d\n%d\n",c[current_id_index].nom,c[current_id_index].prenom,c[current_id_index].adresse,c[current_id_index].tel,c[current_id_index].date_nais.j,c[current_id_index].date_nais.m,c[current_id_index].date_nais.a,cl.id); fclose(f); cl.id++; printf("sucess\n"); } int main(){ int a; // 加载已有的客户端 int loaded_count = load_clients(); printf("已加载%d个客户端\n", loaded_count); do { printf(" *------------- menu --------------*\n"); printf(" | ajouter un client :1 |\n"); printf(" | supprimer un client :2 |\n"); printf(" | rechercher un client:3 |\n"); printf(" | modifer un client :4 |\n"); printf(" | gestion de comptes :5 |\n"); printf(" | quitter le programme:6 |\n"); printf(" *---------------------------------*\n"); scanf("%d",&a); switch(a){ case(1): if(cl.id>nombre_de_clients){ printf("nombre de client maximal\n");break;} ajouter();break; // 其他case可以后续补充 default: printf("选项无效,请重新输入\n"); } }while(a!=6); return 0; }
另外还要注意:你原来的ajouter函数里,scanf("%s",&c[cl.id].nom);这里不需要&,因为c[cl.id].nom是数组名,本身就是指向数组首元素的指针,加&反而会导致类型不匹配,我已经在修改后的代码里修正了这个问题。
内容的提问来源于stack exchange,提问作者Chihab
相关产品推荐
相关产品推荐

