首页 > 代码库 > 《你必须知道的495个C语言问题》笔记--标准输入输出

《你必须知道的495个C语言问题》笔记--标准输入输出

getchar的返回值

这样的代码有什么问题:

char c;

while((c = getchar()) != EOF)....

getchar返回值变量必须是int型。因为EOF通常定义为-1,二十进制为255的字符会被符号扩展,和EOF比较时会相等,从而

过早第结束输入。


feof函数的使用

为什么这些代码最后一行复制了两遍?
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

#define MAXLINE 256

int main(void)
{
        char buf[MAXLINE];
        FILE* fp = fopen("1.txt","r");
        while(!feof(fp)){
                fgets(buf,MAXLINE,fp);
                printf("%s",buf);
        }
        return 0;
}
在c语言中只有输入例程试图读取并失败以后才能得到EOF,也就是说fgets读到最后一行内容,此时调用feof时,feof并
不能返回非零值(即检测不到EOF),while循环继续执行,fgets执行后,返回值为NULL,但是buf还是上次读取的内容,
所以此时printf再次打印了最后一行内容。等到再次执行feof时,此时feof函数检测到EOF,跳出while循环。
所以我们的可以修改成一下来避免上述的问题:
if(fgets(buf, MAXLINE, fp) != NULL){
printf("%s",buf);
}
其实feof函数都是在fgets失败以后才使用的,应为该函数出错还是出错还是达到文件结尾都返回NULL,为了
区分这两种情况,必须调用ferror或者feof函数。


有人说不能在printf中使用%lf,为什么printf中用%f输出double型,而scanf却用%lf呢?

printf的%f说明符既可以输出float型又可以输出double型。根据默认参数提升规则,float型会被提升为double型,因此
printf只会看到双精度数。
独有scanf,情况就完全不一样了,它接收指针,这里没有类似的类型提升,向float存储和向double存储大小不一样,因此
scanf区分%f和%lf。

对于size_t那样的类型定义,到底是long还是其他类型,应该使用什么样的prinf格式?

把那个值转换为一个已知长度够大的类型,然后使用与之对应的printf格式,例如输出某种类型的长度,可以使用:
printf("%lu", (unsigned long)sizeof(thetype));

怎样从特定格式的字符串中读取数据?

可以使用sscanf,例如123ABC5.678,可以用”%d%3s%f“读取。
#include <stdio.h>

int main(void)
{
        char str[] = "1234ABC5.678";
        int i;
        float f;
        char s[10];
        sscanf(str,"%d%3s%f",&i,s,&f);
        printf("%d,%s,%f\n",i,s,f);
        return 0;
}
运行结果:
1234,ABC,5.678000

用"%d\n"调用scanf的问题

下面的代码:
int n;
scanf("%d\n",&n);
printf("%d\n",n);
为什么要多输入一行才返回,为什么?
\n在scanf格式中不表示等待换行符,而是读取并放弃连续的空白字符。因此”%d\n“中的\n会让scanf读到非空白字符为止,
而它可能需要读到下一行才能找到这个非空白字符。应该去掉\n,仅适用%d即可。

scanf和gets一起用的副作用

int n;
char str[80];

scanf("%d",&n);
gets(str);
printf("%d,%s\n",n, str);
以上的代码,好像编译器跳过了gets的调用。

如果你向问题中的程序输入两行:
42
a string
scanf会读取42,但却不会读到紧接其后的换行符,换行符会保留在输入流中,然后被gets读取,后者会读取一个空行,二
第二行的字符串根本不会被读取。