【C语言】一文搞懂c语言输入输出问题

1.字符输出函数putchar

putchar函数是字符输出函数,其功能是在终端(显示器)输出单个字符。

#include<stdio.h>
int main()
{
    putchar('A');
    putchar('\n');
    char X = 'a';
    putchar(X);
    return 0;
}

/*输出结果
A
a
*/

2.字符输入函数getchar

getchar函数的功能是接收用户从键盘上输入的一个字符。

#include<stdio.h>
int main()
{
    char X = getchar();
    putchar(X);
    return 0;
}
/*输入:abc
输出:
a
*/

3.格式化输出函数printf

printf函数叫做格式输出函数,其功能是按照用户指定的格式,把指定的数据输出到屏幕上。

printf("格式控制字符串",输出项);

格式控制字符串有两种:格式字符串和非格式字符串。
格式字符串是以%打头的字符串,在“%”后面跟不同格式字符,用来说明输出数据的类型、形式、长度、小数位数等。格式字符串的形式为:

% [输出最小宽度] [.精度] [长度] 类型

例如:%d格式符表示用十进制整形格式输出,%f表示用实型格式输出,%5.2f格式表示输出宽度为5(包括小数点),并包含2位小数。
非格式字符串在输出的时候原样打印,例如直接输出字符串printf(“HelloWorld!”),输出换行printf(“\n”);
常用格式控制符:
常用格式控制符

#include<stdio.h>
int main()
{
    int a = 10;
    float b = 5.5;
    char c = 'a';
    char s[6] = "hello";
    
    printf("%d\n",a);
    printf("%o\n",a);
    printf("%f\n",b);
    printf("%c\n",c);
    printf("%s\n",s);
    return 0;
}
/*输出
10
12
5.500000
a
hello
*/

4.格式化输入函数scanf

与printf()函数类似,scanf()函数称为格式输入函数,即按照格式字符串的格式,从键盘上把数据输入到指定的变量之中。

scanf("格式控制字符串",输入项地址列表);

地址表项中的地址给出各变量的地址,地址是由地址运算符“&”后跟变量名组成的。
格式控制符
scanf函数中格式字符串的构成与printf函数基本相同,但使用时有几点不同。
(1)格式说明符中,可以指定数据的宽度,但不能指定数据的精度。例:

float a;
scanf(%10f”,&a);  //正确
scanf(%10.2f,&a);  //错误

(2)输入long类型数据时必须使用%ld,输入double数据必须使用%lf或%le。
(3)附加格式说明符“*”使对应的输入数据不赋给相应的变量。

#include<stdio.h>
int main()
{
    //定义变量
    int a;
    float b;
    char c;
    char s[6];
    
    //从键盘输入参数
    scanf("%d",&a);
    scanf("%f",&b);
    getchar();     //用getchar()函数吃掉回车,清除回车带来的影响
    scanf("%c",&c);
    getchar();
    for(int i=0; i<6; i++){
        scanf("%c",&s[i]);
    }
    //或者:scanf("%s",s);
    
    printf("%d\n",a);
    printf("%o\n",a);
    printf("%f\n",b);
    printf("%c\n",c);
    printf("%s\n",s);
    return 0;
}

问题说明:
在上面代码中,输入字符c前为什么要使用getchar呢?

%d:会忽略缓冲区开头的空白符(空格、回车、制表符等)(无论有几个);
%c:直接读取缓冲区的第一个字符(无论这个字符是什么);

所以在使用 scanf(“%c”, &a) 的时候,要确保我们的缓冲区已经没有键入了,可以使用下面3个解决方法:

解决方案1:使用getchar()函数,清除缓冲区已有的字符,但这个方法只能清除一个;

解决方案2:利用函数fflush( )清除缓冲区,示例:fflush(stdin);

解决办法3:把上面代码中的语句scanf(“%f”,&b);和scanf(“%c”,&c);改写成scanf(“%f\n”,&b);和scanf(“%c\n”,&c);

在scanf()函数的格式控制符后面跟回车符’\n’,程序会不断地连续忽略空白符(也就是说缓冲区的空白符凭空被读取掉而又忽略走了),直到有非空白符出现在缓冲区。

5.字符串接输入数gets

gets()的功能是从键盘接收字符串。

#include<stdio.h>
int main()
{
    char s[100];
    gets(s);
    printf("%s",s);
    return 0;
}

/*输入
hello world

输出:hello world
*/

gets()函数的缺点gets不会检查输入的字符串长度,即可能超出字符串数组的长度造成内存溢出,这其实也是gets函数不安全的原因。

6.字符串输出函数puts

puts()的功能是输出一串字符串。

#include <stdio.h>
int main(void)
{
    char str[100] = "hello world";
    printf("%s\n", str);  
    puts(str);  //字符数组的地址,可写出printf("%s\n", &str[0]);  
    return 0;
}

/*输入:hello world
输出:
hello world
hello world
*/

优点:puts()比printf()函数方便得多,不需要指定字符串类型,而且末尾不用加换行符会自动换行,对于单独字符串的使用,确实方便很多。

7.字符写入函数putc和fputc

int putc(int char, FILE *stream) 把参数 char 指定的字符(一个无符号字符)写入到指定的流 stream 中,并把位置标识符往前移动。
int fputc(int char, FILE *stream) 把参数 char 指定的字符(一个无符号字符)写入到指定的流 stream 中,并把位置标识符往前移动。
可以看到,putc和fputc的定义几乎是一样的。
函数声明:

int getc(FILE *stream)

参数说明:

stream – 这是指向 FILE 对象的指针,该 FILE 对象标识了要在上面执行操作的流。

#include <stdio.h>

int main ()
{
   FILE *fp;
   int ch;

   fp = fopen("a.txt", "w+");
   for( ch = 97 ; ch <= 100; ch++ )
   {
      fputc(ch, fp);  //也可以用putc
   }
   fclose(fp);

   return(0);
}
//a.txt文件中被写入字符abcd

8.字符读取函数getc和fgetc

fgetc的功能是从指定的文件中读取一个字符。其用法与getc相似。
函数声明:

int putc(int char, FILE *stream)
int fputc(int char, FILE *stream)

参数说明:

char – 这是要被写入的字符。该字符以其对应的 int 值进行传递。 stream – 这是指向 FILE 对象的指针,该 FILE
对象标识了要被写入字符的流。

  #include <stdio.h>
    #include <stdlib.h>

    int main(void)
    {
        char ch;
        FILE *fp = fopen("a.txt","r+");
        ch = fgetc(fp);
        printf("%c",ch);
        return 0;
    }
//输出结果为a.txt文件的第一行的第一个字符。

9.字符串写入函数fputs

fputs() 函数用来向指定的文件写入一个字符串。
函数声明:

int fputs( char *str, FILE *fp );

参数说明:

str 为要写入的字符串,fp 为文件指针。

char *str = "Hello world";
FILE *fp = fopen("a.txt", "at+");
fputs(str, fp);

10.字符串读取函数fgets

与gets一样,fgets用于读取一个字符串。
函数声明:

char *fgets(char *s, int size, FILE *stream);

参数说明:

s 代表要保存到的内存空间的首地址,可以是字符数组名,也可以是指向字符数组的字符指针变量名。

size 代表的是读取字符串的长度。

stream 表示从何种流中读取,可以是标准输入流 stdin,也可以是文件流,即从某个文件中读取。

//读取键盘输入数据
#include <stdio.h>

int main(void)
{
    char str[20];  /*定义一个最大长度为19, 末尾是'\0'的字符数组来存储字符串*/
    printf("请输入一个字符串:");
    fgets(str, 7, stdin);  /*从输入流stdin即输入缓冲区中读取7个字符到字符数组str中*/
    printf("%s\n", str);
    return 0;
}
//读取a.txt文件的前6个字符
#include <stdio.h>

int main(void)
{
    char str[20];
    FILE *fp = fopen("a.txt", "r+");
    fgets(str, 7, fp);  /*从输入流stdin即输入缓冲区中读取7个字符到字符数组str中*/
    printf("%s\n", str);
    return 0;
}

11.一些问题

11.1 scanf(“%s”,s)与gets()的区别

get()函数只有一个结束标识符,即回车,意味着gets可以接收空格本身作为内容的一部分,而scanf()函数接收字符串时的结束标志有空格和回车,如果输入的字符串中含有空格,我们使用gets()函数来接收字符串。

#include <stdio.h>
int main(void)
{
    char str1[100];
    char str2[100];
    
    gets(str1);
    scanf("%s",str2);
    
    puts(str1);  
    puts(str2);
    return 0;
}
/*
输入:
hello world
hello world
输出:
hello world
hello
*/

11.2 gets和fgets的区别

char* gets(char* buffer);

对于 gets 函数,它的任务是从 stdin 流中读取字符串,直至接收到换行符或 EOF 时停止,并将读取的结果存放在 buffer 指针所指向的字符数组中。换行符不作为读取串的内容,读取的换行符被转换为 null(‘\0’) 值,并由此来结束字符串。
函数 gets 可以无限读取,不会判断上限,所以程序员应该确保 buffer 的空间足够大,以便在执行读操作时不发生溢出。也就是说,gets 函数并不检查缓冲区 buffer 的空间大小,事实上它也无法检查缓冲区的空间。

char *fgets(char *buf, int bufsize, FILE *stream);

相对于 gets 函数,fgets 函数最大的改进就是能够读取指定大小的数据,从而避免 gets 函数从 stdin 接收字符串而不检查它所复制的缓冲区空间大小导致的缓存溢出问题。当然,fgets 函数主要是为文件 I/O 而设计的(注意,不能用 fgets 函数读取二进制文件,因为 fgets 函数会把二进制文件当成文本文件来处理,这势必会产生乱码等不必要的麻烦)。
即给定参数 n,fgets 函数只能读取 n-1 个字符(包括换行符),每次调用时,fgets 函数都会把缓冲区的最后一个字符设为 null(‘\0’)。

总结

在这里插入图片描述

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值