fgetc的正确打开方式

fgetc是C语言的标准函数。如果不做深究,从函数名就很自然的认为就是get一个char,因此就产生了如下代码,函数的作用是读取文本文件中的一行:

注:该段代码中的 LINE_LENGTH 是自定义的宏,可以在自己的头文件中定义 

#define LINE_LENGTH 1024
int fgetline(FILE* file_p, char* line_string){
    char ch='\0';
    int i=0;
    if(file_p==NULL){
        return -1;
    }
    reset_string(line_string);
    do{
        ch=fgetc(file_p);
        if(ch!=EOF&&ch!='\n'){
            *(line_string+i)=ch;
            i++;
        }
    }while(ch!=EOF&&ch!='\n'&&i!=LINE_LENGTH); 
    if(i==LINE_LENGTH){
        return -127; 
    }
    *(line_string+i)='\0'; 
    if(ch==EOF&&i==0){
        return 1;
    }
    else{
        return 0;
    }
}

基于上述函数,做一个简单的main,如下:

#include <stdio.h>
#define LINE_LENGTH 1024

int main(int argc, char** argv){
    char line_buffer[LINE_LENGTH]="";
    int i;

    FILE* file_p=fopen("my_test.txt","r");
    if(file_p==NULL){
        return 1;
    }

    while(!feof(file_p)){
        fgetline(file_p,line_buffer);
        printf("%s\n",line_buffer);
        for(i=0;i<LINE_LENGTH;i++){
            *(line_buffer+i)='\0';
        }
    }
    fclose(file_p);
    return 0;
}

然而,上述代码却有内在问题。实测在 x86 平台上的各个 OS 都未发现异常。但是当移植到 ARM64 架构的 Linux 系统时,却出现了问题。明明已经读到了文件末尾,但是 fgetline 中的循环却还在进行。这就导致了 segmentation fault。

实际上,fgetc 返回的是一个 int 类型,可正可负。如果是-1,则说明读取失败或读到了 EOF。然而如果系统环境和编译器默认 char 类型时 unsigned char,那么问题就来了。

unsigned char 的范围是0~255,此时,如果fgetc 返回了-1,上面代码示例中的fgetline中的循环并不会跳出,因为 ch 的取值到不了-1,而只能是255,判断循环跳出的语句不能触发。

正确的代码如下:

int fgetline(FILE* file_p, char* line_string){
    int ch='\0'; //使用 int 类型
    int i=0;
    if(file_p==NULL){
        return -1;
    }
    reset_string(line_string);
    do{
        ch=fgetc(file_p);
        if(ch!=EOF&&ch!='\n'){
            *(line_string+i)=ch;
            i++;
        }
    }while(ch!=EOF&&ch!='\n'&&i!=LINE_LENGTH); 
    if(i==LINE_LENGTH){
        return -127; 
    }
    *(line_string+i)='\0'; 
    if(ch==EOF&&i==0){
        return 1;
    }
    else{
        return 0;
    }
}

数据类型还是要经常学习。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值