scanf( )、gets( )、fgets( )、getchar( )常用函数用法总结

本文详细解析了C语言中的输入函数,包括scanf(), gets(), fgets(), getchar()的特点和使用场景,对比了它们在键盘和文件输入时的行为差异,以及如何避免常见陷阱。

scanf( )

字符串输入

特点:

  1. 键盘输入
  2. 回车代表输入结束
  3. 遇到空格结束读取
  4. 回车符不保存
  5. 若 (字符串长度<最大字节数) 则自动添加空字符在字符串结尾,否则不添加。

示例:

#include <stdio.h>

#define MAX 8

void pLoop(char *, char *);

int main(void)
{
	char buf[MAX]={8,8,8,8,8,8,8,8};

	scanf("%s",buf);
	pLoop("%c ",buf);

	return 0;
}
void pLoop(char *mode, char *arr)
{
	int i;

	printf("character: ");
	for(i=0;i<MAX;i++)
	{
		printf(mode,arr[i]);
	}
	printf("(ASCII: ");
	for(i=0;i<MAX;i++)
	{
		printf("%d ",arr[i]);
	}
	printf(")\n");
}
/*运行*/12345】
character: 1 2 3 4 5  (ASCII: 49 50 51 52 53 0 8 8 )

可以看到自动添加了空字符0在字符串结尾
再看一条:

/*运行*/12345abc】
character: 1 2 3 4 5 a b c (ASCII: 49 50 51 52 53 97 98 99 )

长度刚刚好为最大字节数的时候,空字符就没有了,如果输入再多一些,就溢出了。
所以说,只有当(字符串长度<最大字节数)才自动添加空字符在字符串结尾
键盘输入的回车符自始至终都木有见着,就是舍弃掉了。

输入一串字符测试一下:

#include <stdio.h>

#define MAX 10

void pLoop(char *, char *);

int main(void)
{
	char buf_1[MAX]={0};
	char buf_2[MAX]={0};
	char buf_3[MAX]={0};
	char buf_4[MAX]={0};

	scanf("%s",buf_1);
	pLoop("%c ",buf_1);
	
	scanf("%s",buf_2);
	pLoop("%c ",buf_2);
	
	scanf("%s",buf_3);
	pLoop("%c ",buf_3);
	
	scanf("%s",buf_4);
	pLoop("%c ",buf_4);

	return 0;
}

void pLoop(char *mode, char *arr)
{
	int i;

	printf("character: ");
	for(i=0;i<MAX;i++)
	{
		printf(mode,arr[i]);
	}
	printf("(ASCII:");
	for(i=0;i<MAX;i++)
	{
		printf("%d ",arr[i]);
	}
	printf(")");
	printf("\n");
}
/*运行*/1121a b c】  //输入
character: 1 1 2 1 a      (ASCII:49 49 50 49 97 0 0 0 0 0 )
character: b          (ASCII:98 0 0 0 0 0 0 0 0 0 )
character: c          (ASCII:99 0 0 0 0 0 0 0 0 0 )
【xixi】
character: x i x i       (ASCII:120 105 120 105 0 0 0 0 0 0 )

从程序上可以看到scanf函数碰到空格就自动结束输入了,并且下一个scanf函数直接读取输入缓存区的数据,直到全部读取完毕,才能再次输入
基于以上特点,它只适合单词输入,不适合英文语句输入
如何避免这种影响下次输入的情况呢,有一个小方法:

	scanf("%s",buf_1);
	pLoop("%c ",buf_1);
	while(getchar()!='\n')
		continue;

	scanf("%s",buf_2);
	pLoop("%c ",buf_2);
	while(getchar()!='\n')
		continue;

	scanf("%s",buf_3);
	pLoop("%c ",buf_3);
	while(getchar()!='\n')
		continue;

	scanf("%s",buf_4);
	pLoop("%c ",buf_4);
	while(getchar()!='\n')
		continue;
/*运行*/1121a b c】  //输入
character: 1 1 2 1 a      (ASCII:49 49 50 49 97 0 0 0 0 0 )
【b b b】
character: b          (ASCII:98 0 0 0 0 0 0 0 0 0 )
【c c d】
character: c          (ASCII:99 0 0 0 0 0 0 0 0 0 )
【xixi】
character: x i x i       (ASCII:120 105 120 105 0 0 0 0 0 0 )

只要在下一次输入前加上

	while(getchar()!='\n')
		continue; //可以只保留分号

就可以清除掉未读取完的数据咯,记住这个方法,以后会有大用。

整型值输入

#include <stdio.h>

#define MAX 10

void pLoop(char *, int *);

int main(void)
{
	int buf_1[MAX]={0};
	int buf_2[MAX]={0};
	int buf_3[MAX]={0};
	int buf_4[MAX]={0};

	scanf("%d",buf_1);
	pLoop("%d ",buf_1);

	scanf("%d",buf_2);
	pLoop("%d ",buf_2);

	scanf("%d",buf_3);
	pLoop("%d ",buf_3);

	scanf("%d",buf_4);
	pLoop("%d ",buf_4);

	return 0;
}

void pLoop(char *mode, int *arr)
{
	int i;

	for(i=0;i<MAX;i++)
	{
		printf(mode,arr[i]);
	}
	printf("\n");
	
}
/*运行*/1121a 2242 31121 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0

咦,一下子就运行完毕了,并且后面的数据都没有输出,这是肿么肥事。。。
再次尝试,去掉字符‘a’

/*运行*/1121 2242 31121 0 0 0 0 0 0 0 0 0 
2242 0 0 0 0 0 0 0 0 0 
3 0 0 0 0 0 0 0 0 0 
【a】
0 0 0 0 0 0 0 0 0 0

这一次正常识别到后续的数值了,再次输入‘a’发现没有输出来。
明白了整型数据输入碰到字符型数据会一直卡住,后续的输入全部都失效了。

浮点型输入

暂无,后续再补充。

gets( )

安全性低,不建议使用。

字符串输入

字符串输入的常用函数,形参为字符串的地址。

#include <stdio.h>                                                                     

#define MAX 10

int main(void)
{
    char str[MAX] = {0};
    gets(str);
    puts(str);
 
    return 0;
}
/*运行*/12345ssdlhhhdbdddxss】
12345ssdlhhhdbdddxss

gets函数不限制输入的字符串长度,只要缓冲区够大就可以。这样子其实是很危险的,不限制长度,缓冲区也有上限啊,难怪编译的时候告警了
temp.c:(.text+0x32): 警告: the `gets’ function is dangerous and should not be used.(“gets”函数很危险,不应使用。)
建议使用fgets( ),虽然麻烦了一点,但是安全性高。

看上面的运行结果,我只分配了10个字节,它居然输出了这么多,我感觉已经内存溢出了。。。

fgets( )

字符串输入

fgets(目标地址,最大长度,输入);
遇到回车或最大长度-1结束输入,添加空字符结尾。

#include <stdio.h>

#define MAX 10
int main(void)
{
    char str[MAX] = {0};
    fgets(str,MAX,stdin);
    fputs(str,stdout);
    printf("\n");

    return 0;
}
/*运行*/12345ssdlhhhdbdddxss】
12345ssdl

到第9个字符就结束了,MAX-1=9。
再运行一次:

/*运行*/1234512345
<>

分析一下刚刚的2种情况:
第一种长度超过缓存区的情况
输入:12345ssdlhhhdbdddxss\n
输出:12345ssdl\0
第二种长度未超缓存区的情况
输入:12345\n
输出:12345\n\0
总之,回车符可以不要,空字符是一定要留在末尾的。
和之前的gets( )一对比,谁更赞一目了然了。。。

文件输入

/*test_file.c*/
#include <stdio.h>

#define MAX 10

int main(void)
{
    char str[MAX] = {0};
    FILE *fp;

    fp = fopen("/home/yu/test_file.txt","a+");
    if(fp == NULL)
    {
            return -1;
    }
    fseek(fp,0L,SEEK_SET);
    fgets(str,MAX,fp);
    fputs(str,stdout);
    printf("\n");

    return 0;
}
/*test_file.txt*/
12345ssdlhhhdbdddxss
/*运行*/
12345ssdl

getchar( )

字符输入

先输入一些字符,然后输出一下,看看它有什么特点

#include <stdio.h>

#define MAX 10

void pLoop(char *, int *); 

int main(void)
{
        char str_1[MAX] = {0};
        char str_2[MAX] = {0};
        char str_3[MAX] = {0};
        char str_4[MAX] = {0};
        char str_5[MAX] = {0};
        char str_6[MAX] = {0};

        str_1[0] = getchar();
        str_2[0] = getchar();
        str_3[0] = getchar();
        str_4[0] = getchar();
        str_5[0] = getchar();
        str_6[0] = getchar();
        printf("%c\n",str_1[0]);
        printf("%c\n",str_2[0]);
        printf("%c\n",str_3[0]);
        printf("%c\n",str_4[0]);
        printf("%c\n",str_5[0]);
        printf("%c\n",str_6[0]);
        
        return 0;
}
/*运行*/1a 3】
【%21
a
<>
3
<>
<>
%

和scanf()有点相似,都是会读取缓存区中的数据的,大多数字符都可以读取,遇到空格不会跳过,遇到回车符结束,并且下次还会读取回车符。

从上面运行的结果中我发现了一个问题,怎么3和%之间有2个空行呢,改进一下代码看看情况。

        printf("%c",str_1[0]);
        printf("(%#x)\n",str_1[0]);
        printf("%c",str_2[0]);
        printf("(%#x)\n",str_2[0]);
        printf("%c",str_3[0]);
        printf("(%#x)\n",str_3[0]);
        printf("%c",str_4[0]);
        printf("(%#x)\n",str_4[0]);
        printf("%c",str_5[0]);
        printf("(%#x)\n",str_5[0]);
        printf("%c",str_6[0]);
        printf("(%#x)\n",str_6[0]);
/*输出*/1a 3】
【%21(0x31)
a(0x61)
 (0x20)
3(0x33)
<>
(0xa)
%(0x25)

查询了一下ASCII码表,发现0xa是换行符,仔细思考了一下,就是printf()输出了2次换行导致的,

printf("%c\n",str_5[0]);

相当于

printf("\r\n");

总结

输入

scanf( )
键盘输入,各种类型数据输入,遇回车则换行并结束输入,不保留回车符。int数据遇空格下一个函数读取,遇非数字型字符则卡住;char数据遇空格则下一个函数读取。可指定输入格式。
gets( )
键盘输入,字符串输入,遇回车则换行并结束输入,不保留回车符。
fgets( )
键盘、文件输入,遇回车符或MAX-1字节结束输入,会保留回车符。
getchar( )
键盘输入,字符输入,遇回车则换行并结束输入,保留回车符。

输出

printf( )
屏幕输出,变量、数组、结构体等数据输出,不自动换行。
puts( )
屏幕输出,字符串输出,自动换行。
fputs( )
屏幕、文件输出,字符串输出,不自动换行。
putchar( )
屏幕输出,字符输出,不自动换行。

输入scanf( )gets( )fgets( )getchar( )
输入方式键盘键盘键盘、文件键盘
存储类型整型、浮点型、字符型字符串字符串字符
存储回车符
结束方式回车回车回车回车
输出printf( )puts( )fputs( )putchar( )
输出方式屏幕屏幕屏幕、文件屏幕
自动换行

持续改进更新中。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值