C和指针 第15章 输入/输出函数 15.20 问题

1. 如果对fopen函数的返回值不进行错误检查,可能会出现什么后果? 
解析:
如果由于任何原因导致打开失败,函数的返回值将是NULL。当这个值传递给后续的I/O函数时,该函数就会失败。至于程序是否失败,则取决于编译器。如果程序并不终止,那么I/O操作可能会修改内存中某些不可预料的位置的内容。 

2. 如果试图对一个从未打开过的流进行I/O操作,会发生什么情况?
解析:
程序将会失败,因为试图使用的FILE结构没有适当地初始化。某个不可预料的内存地址的内容可能会被修改。 

3. 如果一个程序fclose调用失败,但程序并未对它的返回值进行错误检查,可能会出现什么后果? 
解析:
fclose中的参数可能会因为fopen和fclose之间的一个程序bug而发生修改。而这个bug无疑将导致程序失败。在那些并不检查fopen函数返回值的程序中,fclose中的参数甚至可能是NULL。在任何一种情况下,fclose都将失败,而且程序很可能在fclose被调用之前很早便已终止。 

4. 如果一个程序员在执行时它的标准输入已重定向到一个文件,程序如何检测到这个情况呢? 
解析:
不同的操作系统提供不同的机制来检测这种重定向,但程序员通常并不需要知道输入来自于文件还是键盘。操作系统负责处理绝大多数与设备无关的输入操作的许多方面,剩余部分则由库I/O函数提供。对于绝大多数应用程序,程序从标准输入读取的方式相同,不管输入实际来自何处。

 5. 如果调用fgets函数时使用一个长度为1的缓冲区,会发生什么呢?长度为2呢? 
解析:
fgets无法把字符串读入到一个长度小于两字符的缓冲区,因为其中一个字符需要为NUL字节保留。长度为2时只能读入一个字符到缓冲区。
#include <stdio.h>
#include <stdlib.h>

#define ARR_LEN 20

int main( void ){
    char buffer[ARR_LEN];
    int buffer_size;
    
    buffer_size = 1;
    fgets( buffer, buffer_size, stdin );
    if( *buffer == '\0' ){
        printf( "there is an only \'\\0\'.\n" );
    } else{
        printf( "there are more one character, buffer = %s\n", buffer );
    }
    buffer_size = 2;
    fgets( buffer, buffer_size, stdin );
    if( *buffer == '\0' ){
        printf( "there is a only \'\0\'.\n" );
    } else{
        printf( "there are more one character, buffer = %s\n", buffer );
    }
    
    return EXIT_SUCCESS;
}
输出:

6. 为了保证下面这条sprintf语句所产生的字符串不溢出,缓冲区至少应该有多大?假定你的机器的上整数的长度为2字节。
    sprintf( buffer, "%d %c %x", a, b, c );
解析:
缓冲区的长度至少应该为:有符号整数a中的数字个数+字符b的个数+ 无符号整数c中的数字个数+每个空格字符的个数+'\0'字符的个数,这个办法不会浪费内存空间 
更简单的操作就是INT_MAX中的数字个数+字符b的个数+UINT_MAX中的数字个数+每个空格字符的个数+'\0'字符的个数,不过这个办法会浪费一定的内存空间。 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

int strlen_dec_int( int n );
int strlen_hex_int( int n );
int strlen_char( char c );

int main( void ){
    int total;
    int a;
    char b;
    int c;
    
    total = 0; 
    a = 123;
    b = 'a';
    c = 0xa;
    printf( "c = %d\n", c );
    total += strlen_dec_int( a );
    total += strlen_char( b );
    total += strlen_char( (char)' ' ); 
    total += strlen_char( (char)' ' );
    total += strlen_char( (char)'\0' );
    total += strlen_hex_int( c );
    printf( "total = %d\n", total );
    
    char buffer[total]; 
    buffer[total - 1] = '\0';
    sprintf( buffer, "%d %c %x", a, b, c );
    
    int buf_len;
    buf_len = strlen( buffer );
    printf( "buf_len = %d, buffer = %s\n", buf_len, buffer );
    if( *(buffer + total - 1) == '\0' ){
        printf( "true!\n" );
    } else{
        printf( "false!\n" );
    }
    
    return EXIT_SUCCESS;
}

int strlen_dec_int( int n ){
    int counter = 1;
    
    while( n / 10 ){
        counter++;
        n /= 10;
    }
    
    return counter;
}

int strlen_hex_int( int n ){
    int counter = 1;
    
    while( n / 16 ){
        counter++;
        n /= 16;
    }
    
    return counter;
}

int strlen_char( char c ){
    return 1;
}
输出:

7. 为了保证下面这条sprintf语句所产生的字符串不溢出,缓冲区至少应该有多大?
    sprintf( buffer, "%s", a );
解析:
缓冲区大小至少应该为:strlen(a) + '\0'字符的个数。 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* method:this method need the size of a during compilation */ 
char a[] = "hello, world!";
size_t a_size = sizeof(a) / sizeof(*a);
char buffer[sizeof(a) / sizeof(*a)];

int main( void ){
    printf( "a = %s, a_size = %zd\n", a, a_size );
    sprintf( buffer, "%s", a );
    printf( "buffer = %s\n", buffer );
    if( *(buffer + a_size - 1) == '\0' ){
        printf( "true!\n" );
    } else{
        printf( "false!\n" );
    }
    
    /* method2:this method can know the length of a during the time of running */
    int size;
    printf( "please input the size of ps:" );
    scanf( "%d", &size );
    int ch;
    while( (ch = getchar()) != EOF && ch != '\n' ){
        ;
    }
    char *ps;
    ps = (char *)malloc( sizeof(char) * (size + 1) );
    *(ps + size ) = 0;
    char *result;
    printf( "please input the content of ps:" );
    result = fgets( ps, size + 1, stdin );
    if( !result ){
        exit( EXIT_FAILURE );
    }
    char *pline;
    pline = strchr( result, '\n' );
    if( !pline ){
        while( (ch = getchar()) != EOF && ch != '\n' ){
            ;
        }
    } else{
        *pline = '\0';
    } 
    size_t buffer2_len = strlen( ps );
    char buffer2[buffer2_len + 1];
    sprintf( buffer2, "%s", ps ); 
    *(buffer2 + buffer2_len) = 0;
    printf( "buffer2 = %s\n", buffer2 );
    if( *(buffer2 + buffer2_len) == '\0' ){
        printf( "true!\n" );
    } else{
        printf( "false!\n" );
    }
    
    return EXIT_SUCCESS;
}
 输出:

8. %f格式代码所打印的最后一位数字是经过四舍五入呢,还是未打印的数组被简单地截掉呢? 
解析:
四舍五入。
#include <stdio.h>
#include <stdlib.h>

int main( void ){
    float f = 0.5678856f;
    
    printf( "f = %f\n", f );
     
    return EXIT_SUCCESS;
}
输出:

9. 如何得到perror函数可能打印的所有错误信息列表? 
解析:
perror输出的错误原因依照全局变量errno的值来决定要输出的字符串。
标准库函数在一个外部整型变量errno(在errno.h中定义)中保存错误代码代码之后把这个信息
传递给用户程序,提示操作失败的准确原因。perror函数简化向用户报告这些特定错误的过程。
perror打印出一条用于解释errno当前错误代码的信息。所以,我们只需要查看errno可能的值就能知道perror能够打印的所有的错误信息列表。 

10. 为什么fprintf、fscanf、fputs和fclose函数都接受一个指向FILE结构的指针作为参数而不是FILE结构本身。
解析:
传递一个指针的效率更高。首先指针的字节大小小于FILE结构的字节大小,这可以提高实参向形参进行赋值的效率。传递一个指针是为了能够修改它所指向变量的成员的值,假如传递一个结构,还必须返回一个结构,再一次进行赋值操作修改原来的变量的值,效率就会降低。 
#include <stdio.h>
#include <stdlib.h>

int main( void ){
    printf( "sizeof(FILE *) = %zd, sizeof(FILE) = %zd\n", sizeof(FILE *), sizeof(FILE) );
    
    return EXIT_SUCCESS;
}
输出:

11. 你希望打开一个问题进行写入,假定:不希望文件原来的内容丢失;希望能够写入到文件的任何位置。那么该怎样设置打开模式呢? 
解析:
the mode r+ does the job,The w modes truncate the file,and the a modes restrict writing to the end of the file.
(r+ 这个模式可以做这个工作,w模式会截断文件,a模式会限制只能在文件末尾添加)。
参考链接:《C与指针》第十五章练习 - _monster - 博客园 (cnblogs.com)
#include <stdio.h> /* 这个问题的源码可以选择性查看 */
#include <stdlib.h>
#include <string.h>

int main( void ){
    FILE *file;
    
    file = fopen( "data.txt", "wb" );
    if( !file ){
        printf( "fail to create a data.txt file.\n" );
        perror( "data.txt" );
        exit( EXIT_FAILURE ); 
    }
    char buffer[] = "I am a student.\n";
    char buffer2[] = "I am a teacher.\n";
    /*
    ** You can check the answer of expression If you are interested in it.
    ** int size3 = sizeof("I am a student.\n") / sizeof(*"I am a student.\r\n") ;
    */
    int size = sizeof(buffer) / sizeof(*buffer);
    int size2 = sizeof(buffer2) / sizeof(*buffer2);
    printf( "size = %d, size2 = %d\n", size, size2 );
    fpos_t current_pos;
    int result;
    result = fgetpos( file, &current_pos );
    printf( "result = %d, current_pos = %d\n", result, current_pos );
    fwrite( buffer, size, 1, file );
    result = fgetpos( file, &current_pos );
    printf( "after fwrite( buffer1, size, 1, file ), result = %d, current_pos = %d\n", 
    result, current_pos );
    fwrite( buffer2, size2, 1, file );
    result = fgetpos( file, &current_pos );
    printf( "after fwrite( buffer2, size2, 1, file ), result = %d, current_pos = %d\n", 
    result, current_pos );
    fflush( file );
    fclose( file );
    
    file = fopen( "data.txt", "rb+" );
    if( !file ){
        printf( "fail to open a data.txt file.\n" );
        perror( "data.txt" );
        exit( EXIT_FAILURE );
    }
    rewind( file );
    fgetpos( file, &current_pos );
    printf( "after rewind( file ), result = %d, current_pos = %d\n", result, current_pos );
    char *d_buffer;
    char *d_buffer2;
    d_buffer = (char *)malloc( sizeof(char) * size ); 
    d_buffer2 = (char *)malloc( sizeof(char) * size2 );
    printf( "print original content of data.txt:\n" );
    if( d_buffer ){
        fread( d_buffer, size, 1, file );
        fgetpos( file, &current_pos );
        printf( "after fread( d_buffer, size, 1, file ), current_pos = %d\n", current_pos );
        printf( "%s", d_buffer );
    }
    if( d_buffer2 ){
        fread( d_buffer2, size2, 1, file );
        fgetpos( file, &current_pos );
        printf( "after fread( d_buffer2, size2, 1, file ), current_pos = %d\n", current_pos );
        printf( "%s", d_buffer2 );
    }
    /*
    ** set current location is the first location. rewind func can achieve the same function. 
    ** current_pos = 0;
    ** result = fsetpos( file, &current_pos );
    */
    rewind( file );
    result = fgetpos( file, &current_pos );
    printf( "after rewind( file), current_pos = %d, result = %d\n", current_pos, result );
    char buffer3[] = "I am a worker.\n";
    int size3 = sizeof(buffer3) / sizeof(*buffer3);
    printf( "size3 = %d\n", size3 );
    printf( "add the content to the beginning of file:\n" );
    fwrite( buffer3, size3, 1, file );
    fgetpos( file, &current_pos );
    printf( "after fwrite( buffer3, size3, 1, file ), current_pos = %d\n", current_pos );
    printf( "print content of data.txt added:\n" );
    rewind( file );
    fgetpos( file, &current_pos );
    char *d_buffer3;
    /*char *d_buffer4;*/
    d_buffer3 = (char *)malloc( sizeof(char) * size3 );
    if( d_buffer3 ){
        fread( d_buffer3, size3, 1, file );
        result = fgetpos( file, &current_pos );
        printf( "1:after fread( d_buffer3, size3, 1, file ),"
        " current_pos = %d, d_buffer3 = %s", current_pos, d_buffer3 );
    }
    /*
    d_buffer4 = (char *)malloc( sizeof(char) * (strlen( buffer4 ) + 1) );
    if( d_buffer4 ){
        fread( d_buffer4, size4, 1, file );
        printf( "2:%s", d_buffer4 );
    }
    */
    free( d_buffer );
    d_buffer = (char *)malloc( sizeof(char) * size );
    if( d_buffer ){
        fread( d_buffer, size, 1, file );
        fgetpos( file, &current_pos ); 
        printf( "2:after fread( d_buffer, size, 1, file ),"
        " current_pos = %d, d_buffer = %s", current_pos, d_buffer );
    }
    free( d_buffer2 );
    d_buffer2 = (char *)malloc( sizeof(char) * size2 );
    if( d_buffer2 ){
        fread( d_buffer2, size2, 1, file );
        fgetpos( file, &current_pos );
        printf( "4:after fread( d_buffer2, size2, 1, file ),"
        " current_pos = %d, d_buffer2 = %s", current_pos, d_buffer2 );
    }
    free( d_buffer );
    free( d_buffer2 );
    free( d_buffer3 );
    /*
    free( d_buffer4 );
    */
    fclose( file );
    
    return EXIT_SUCCESS;
}
输出:

这个代码的输出是这样的,但是不能得到相应的结果。这里使用的是fgetpos、rewind、fsetpos函数,所以我采用的是二进制形式读写的方式来证明我的猜想。有问题的原因在于rb+进行写操作时会修改该文件原来存在该位置的内容,而不是把原来的内容依次后移。
下面是采用文本形式的参考,也可以证明采用文本形式读写的方式会修改原来该位置的内容,并且如果小于原来存在于此处的字符串大小,那么它只会改变前面部分的字符。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main( void ){
    FILE *file;
    
    file = fopen( "data_2.txt", "w" );
    if( !file ){
        printf( "fail to create a data_2.txt file.\n" );
        perror( "data_2.txt" );
        exit( EXIT_FAILURE ); 
    }
    char buffer[] = "I am a student.\n";
    char buffer2[] = "I am a teacher.\n";
    /*
    ** You can check the answer of expression If you are interested in it.
    ** int size3 = sizeof("I am a student.\n") / sizeof(*"I am a student.\r\n") ;
    */
    int size = sizeof(buffer) / sizeof(*buffer);
    int size2 = sizeof(buffer2) / sizeof(*buffer2);
    printf( "size = %d, size2 = %d\n", size, size2 );
    long location = ftell( file );
    printf( "location = %d\n", location );
    fputs( buffer, file );
    location = ftell( file );
    printf( "after fputs( buffer, file ), location = %d\n", location );
    fputs( buffer2, file );
    location = ftell( file );
    printf( "after fputs( buffer2, file ), location = %d\n", location );
    fflush( file );
    fclose( file );
    
    file = fopen( "data_2.txt", "r+" );
    if( !file ){
        printf( "fail to open a data_2.txt file.\n" );
        perror( "data_2.txt" );
        exit( EXIT_FAILURE );
    }
    location = ftell( file );
    printf( "location = %d\n", location );
    char *d_buffer;
    char *d_buffer2;
    d_buffer = (char *)malloc( sizeof(char) * size ); 
    d_buffer2 = (char *)malloc( sizeof(char) * size2 );
    printf( "print original content of data_2.txt:\n" );
    if( d_buffer ){
        fgets( d_buffer, size, file );
        /*fgetc( file );*/
        location = ftell( file );
        printf( "after fgets( d_buffer, size, file ), location = %d\n", location );
        fputs( d_buffer, stdout );
    }
    if( d_buffer2 ){
        fgets( d_buffer2, size2, file );
        /*fgetc( file );*/
        location = ftell( file );
        printf( "after fgets( d_buffer2, size2, file ), location = %d\n", location );
        fputs( d_buffer2, stdout );
    }
    
    fseek( file, 0, SEEK_SET );
    location = ftell( file );
    printf( "after fseek( file, 0, SEEK_SET ), location = %d\n", location );
    char buffer3[] = "I am a worker.";
    int size3 = sizeof(buffer3) / sizeof(*buffer3);
    printf( "size3 = %d\n", size3 );
    printf( "add the content to the beginning of file:\n" );
    fputs( buffer3, file );
    location = ftell( file );
    printf( "after fputs( buffer3, file ), location = %d\n", location );
    /*
    printf( "print content of data_2.txt added:\n" );
    fseek( file, 0, SEEK_SET );
    location = ftell( file );
    printf( "after fseek( file, 0, SEEK_SET ), location = %d\n", location );
    char *d_buffer3;
    */
    /*char *d_buffer4;*/
    /*
    d_buffer3 = (char *)malloc( sizeof(char) * size3 );
    if( d_buffer3 ){
        fgets( d_buffer3, size3, file );
        location = ftell( file ); 
        printf( "1:after fgets( d_buffer3, size3, file ),"
        " location = %d\n", location );
        fputs( d_buffer3, stdout );
    }
    */
    /*
    d_buffer4 = (char *)malloc( sizeof(char) * (strlen( buffer4 ) + 1) );
    if( d_buffer4 ){
        fread( d_buffer4, size4, 1, file );
        printf( "2:%s", d_buffer4 );
    }
    */
    /*
    free( d_buffer );
    d_buffer = (char *)malloc( sizeof(char) * size );
    if( d_buffer ){
        fgets( d_buffer, size, file );
        location = ftell( file ); 
        printf( "3:after fgets( d_buffer, size, file ),"
        " location = %d\n", location );
        fputs( d_buffer, stdout );
    }
    free( d_buffer2 );
    d_buffer2 = (char *)malloc( sizeof(char) * size2 );
    if( d_buffer2 ){
        fgets( d_buffer2, size2, file );
        location = ftell( file ); 
        printf( "4:after fgets( d_buffer2, size2, file );,"
        " location = %d\n", location );
        fputs( d_buffer2, stdout );
    }
    */
    free( d_buffer );
    free( d_buffer2 );
    /*
    free( d_buffer3 );
    */
    /*
    free( d_buffer4 );
    */
    fclose( file );
    
    return EXIT_SUCCESS;
}
输出:

data_2.txt的文本内容如下:

12. 为什么需要freopen函数?
解析:
freopen函数用于打开(或重新打开)一个特定的文件流。这个函数首先试图关闭这个流,然后用指定的文件和模式重新打开这个流。如果打开失败,函数返回一个NULL值。如果打开成功,函数就返回它的第三个参数值。这个函数可以简化关闭一个流和重新打开一个流需要进行的操作。 

13. 对于绝大多数程序,有必要考虑fgetc(stdin)或getchar那个更好吗?
解析:
fgetc可用于所有的文件输入流,getchar只能用于标准输入流。fgetc是通过函数实现的,而getchar是通过宏实现的。如果是用于从标准输入流读取字符,建议采用getchar;否则,使用fgetc函数。 

14. 在你的系统上,下面的语句将打印什么内容?
    printf( "%d\n", 3.14 ); 
#include <stdio.h>
#include <stdlib.h>

int main( void ){
    printf( "%d\n", 3.14 );
    
    return EXIT_SUCCESS;
}
输出:

15. 请解释使用%-6.10s格式代码将打印出什么形式的字符串。 
#include <stdio.h>
#include <stdlib.h>

int main( void ){
    char buffer[] = "abcdefghilklmnopqrstuvwxyz";
    printf( "%-6.10s", buffer );
     
    return EXIT_SUCCESS;
}
输出:

16. 当一个特定的值用格式代码%.3f打印时,其结果是1.405。但这个值用格式代码%.2f打印时,其结果是1.40。似乎出现了问题,请解释器原因。
解析:
如果实际值是1.4049,格式代码%.3f将导致缀尾的4四舍五入至5,但使用格式代码%.2f,缀尾的0并没有进行四舍五入至1,因为它最后被截掉的第1个数字是4. 
#include <stdio.h>
#include <stdlib.h>

int main( void ){
    float f = 1.4049;
    printf( "%.3f, %.2f", f, f );
     
    return EXIT_SUCCESS;
}
输出:

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_40186813

你的能量无可限量。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值