连续使用两次fread 错误和fread返回值
时间: 2024-05-26 15:16:55 浏览: 127
连续使用两次fread可能会导致读取到的数据不正确,因为第二次读取时文件指针已经改变。这个问题可以通过使用fseek函数将文件指针重新定位到正确的位置来解决。
fread函数的返回值是成功读取的数据块数,如果返回值小于请求的数据块数,可能是因为已经读到了文件结尾或者发生了错误。此时可以使用feof和ferror函数来分别判断是否读到了文件结尾或者是否出现了错误。
相关问题
如何让fread最后一次读取时返回实际大小而不是
当使用 fread 函数读取文件时,如果读到文件末尾,则返回值会小于请求读取的字节数。如果希望在读取到文件末尾时返回实际大小而不是小于请求大小的值,可以在调用 fread 函数之前使用 ftell 函数获取文件当前位置,然后在调用 fread 函数之后再次使用 ftell 函数获取文件位置,计算两次位置之差即可得到实际读取的字节数。
下面是一个示例代码:
```
#include <stdio.h>
int main() {
FILE *fp;
long int start, end, size;
char buffer[1024];
fp = fopen("test.txt", "rb");
if (fp == NULL) {
printf("Failed to open file\n");
return -1;
}
start = ftell(fp);
fseek(fp, 0, SEEK_END);
end = ftell(fp);
fseek(fp, 0, SEEK_SET);
size = end - start;
fread(buffer, size, 1, fp);
printf("Actual size read: %ld bytes\n", size);
fclose(fp);
return 0;
}
```
在这个示例中,我们首先使用 ftell 函数获取文件开始位置,然后使用 fseek 函数将文件指针移动到文件末尾,并再次使用 ftell 函数获取文件结束位置。然后我们计算两次位置的差,即实际读取的字节数。最后,我们使用 fread 函数读取文件,读取的字节数为实际大小,而不是请求大小。
需要注意的是,如果文件的大小超过了 ftell 函数返回值的最大值,这种方法可能不会正确地计算实际读取的字节数。在这种情况下,可以使用其他方法来计算实际读取的字节数,例如使用 fseek 函数将文件指针移动到文件末尾之前的位置,然后读取文件的最后部分。
#include <stdio.h> #include <string.h> #define n 20 void zhuce(); void denglu(); char yhm[n],mm[n]; struct imz { char yhm[n]; char mm[n]; }; int main() { int i; printf("-----------\n1.注册\n2.登陆\n0.退出\n"); scanf("%d",&i); switch(i) { case 0: break; case 1: zhuce(); break; case 2: denglu(); break; } return 0; } void zhuce( ) { struct imz z; char temp1[n],temp2[n],yhmtmp[n]; FILE *fp; fp=fopen("zhanghao","ab"); printf("输入用户名\n"); scanf("%s",yhmtmp); printf("输入密码\n"); scanf("%s",temp1); printf("输入密码确认\n"); scanf("%s",temp2);; if(!strcmp(temp1,temp2)) { strcpy(z.yhm,yhmtmp); strcpy(z.mm,temp1); fwrite(&z,sizeof(struct imz),1,fp); printf("注册成功\n"); } else { printf("注册失败\n"); zhuce(); } fclose(fp); } void denglu( ) { FILE *fp; struct imz h; char s1[n],s2[n]; fp=fopen("zhanghao","r"); printf("输入用户名\n"); scanf("%s",s1); printf("输入密码\n"); scanf("%s",s2); fread(&h,sizeof(struct imz),1,fp); if(s1==h.yhm) { if(s2==h.mm) { printf("登陆成功\n"); } } else { printf("用户名或密码错误\n"); } fclose(fp); }
这段代码是一个简单的用户注册和登录系统,使用 C 语言编写。
具体分析如下:
1. `#include<stdio.h>` 和 `#include<string.h>` 是用来引入标准输入输出库和字符串处理库的头文件。
2. `#define n 20` 定义了一个宏,表示用户名和密码的最大长度为 20 个字符。
3. `void zhuce();` 和 `void denglu();` 是两个函数的声明,分别用来处理用户注册和登录。
4. `char yhm[n],mm[n];` 定义了两个字符数组,用来存储用户输入的用户名和密码。
5. `struct imz { char yhm[n]; char mm[n]; };` 定义了一个结构体 `imz`,其中包含了两个成员变量 `yhm` 和 `mm`,分别用来存储用户名和密码。
6. `int main()` 是程序的入口函数,其中 `int` 表示函数返回值类型为整型,`main` 是函数名,空括号表示该函数没有参数。
7. `printf("-----------\n1.注册\n2.登陆\n0.退出\n");` 输出菜单,提供用户三个选项:注册、登录和退出。
8. `scanf("%d",&i);` 用户输入选项,并将其存储在变量 `i` 中。
9. `switch(i)` 根据用户输入的选项进行分支处理。
10. `case 0: break;` 如果用户选择退出,则直接退出程序。
11. `case 1: zhuce(); break;` 如果用户选择注册,则调用函数 `zhuce()` 进行注册处理。
12. `case 2: denglu(); break;` 如果用户选择登录,则调用函数 `denglu()` 进行登录处理。
13. `void zhuce( ) { ... }` 函数定义,用来处理用户注册。
14. `struct imz z;` 定义了一个结构体变量 `z`,用来存储用户注册信息。
15. `char temp1[n],temp2[n],yhmtmp[n];` 定义了三个字符数组,分别用来存储用户输入的密码和用户名。
16. `FILE *fp; fp=fopen("zhanghao","ab");` 定义了一个文件指针 `fp`,并打开了一个名为 `zhanghao` 的文件,以追加写入的方式打开。
17. `scanf("%s",yhmtmp); scanf("%s",temp1); scanf("%s",temp2);` 分别获取用户输入的用户名、密码和确认密码。
18. `if(!strcmp(temp1,temp2)) { ... } else { ... }` 如果两次输入的密码相同,则将用户名和密码存储到结构体变量 `z` 中,并将其写入文件中。否则,提示用户注册失败,并重新调用 `zhuce()` 函数。
19. `fclose(fp);` 关闭文件。
20. `void denglu( ) { ... }` 函数定义,用来处理用户登录。
21. `FILE *fp; struct imz h; char s1[n],s2[n];` 定义了一个文件指针 `fp`,一个结构体变量 `h`,以及两个字符数组 `s1` 和 `s2`,分别用来存储从文件中读取的用户名和密码,以及用户输入的用户名和密码。
22. `fopen("zhanghao","r");` 打开文件 `zhanghao`,以只读方式打开。
23. `scanf("%s",s1); scanf("%s",s2);` 获取用户输入的用户名和密码。
24. `fread(&h,sizeof(struct imz),1,fp);` 从文件中读取一个结构体大小的数据,并将其存储到变量 `h` 中。
25. `if(s1==h.yhm) { ... } else { ... }` 如果用户输入的用户名和从文件中读取的用户名相同,则比较用户输入的密码和从文件中读取的密码是否相同。如果相同,则提示用户登录成功;否则,提示用户名或密码错误。
26. `fclose(fp);` 关闭文件。
注意:该程序存在一些问题,例如在比较字符串时应该使用 `strcmp()` 函数而不是 `==` 运算符,还有一些其他的细节问题,需要进一步完善。
阅读全文