C语言标准输入输出、相关函数

C语言标准输入输出、相关函数

格式化输入输出函数:

printf()函数:

格式字符串

在Turbo C中格式字符串的一般形式为:
[标志][输出最小宽度][.精度][长度]类型。
其中方括号[]中的项为可选项。

1) 类型
类型字符用以表示输出数据的类型,其格式符和意义如下表所示:

1

2) 标志
标志字符为 -、+、# 和空格四种,其意义下表所示:

1

3) 输出最小宽度
用十进制整数来表示输出的最少位数。若实际位数多于定义的宽度,则按实际位数输出,若实际位数少于定义的宽度则补以空格或0。

4) 精度
精度格式符以“.”开头,后跟十进制整数。本项的意义是:如果输出数字,则表示小数的位数;如果输出的是字符,则表示输出字符的个数;若实际位数大于所定义的精度数,则截去超过的部分。

5) 长度
长度格式符为h、l两种,h表示按短整型量输出,l表示按长整型量输出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
int main(void){
int a=15;
long float b=123.1234567;
double c=12345678.1234567;
char d='p';

printf("a=%d\n", a);
printf("a(%%d)=%d, a(%%5d)=%5d, a(%%o)=%o, a(%%x)=%x\n\n",a,a,a,a); // %% 可以输出 %

printf("a=%f\n", b);
printf("b(%%f)=%f, b(%%lf)=%lf, b(%%5.4lf)=%5.4lf, b(%%e)=%e\n\n",b,b,b,b);

printf("c=%f\n", c);
printf("c(%%lf)=%lf, c(%%f)=%f, c(%%8.4lf)=%8.4lf\n\n",c,c,c);

printf("d=%c\n", d);
printf("d(%%c)=%c, d(%%8c)=%8c\n",d,d);
return 0;
}

1

使用printf函数时还要注意一个问题,那就是输出表列中的求值顺序。不同的编译系统不一定相同,可以从左到右,也可从右到左。

1
2
3
4
5
6
7
#include <stdio.h>
int main(void){
int i=8;
printf("The raw value: i=%d\n", i);
printf("++i=%d \n++i=%d \n--i=%d \n--i=%d\n",++i,++i,--i,--i);
return 0;
}
1
2
3
4
5
The raw value: i=8
++i=8
++i=7
--i=6
--i=7
1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
int main(void){
int i=8;
printf("The raw value: i=%d\n", i);
printf("++i=%d\n", ++i);
printf("++i=%d\n", ++i);
printf("--i=%d\n", --i);
printf("--i=%d\n", --i);
return 0;
}
1
2
3
4
5
The raw value: i=8
++i=9
++i=10
--i=9
--i=8

scanf()函数:

格式字符串

格式字符串的一般形式为:
%[*][输入数据宽度][长度]类型
其中有方括号[]的项为任选项。各项的意义如下。

1) 类型
表示输入数据的类型,其格式符和意义如下表所示。

1

2) “”符
用以表示该输入项,读入后不赋予相应的变量,即跳过该输入值。如:
纯文本复制
`scanf(“%d %
d %d”,&a,&b);`
当输入为:1 2 3时,把1赋予a,2被跳过,3赋予b。

3) 宽度
用十进制整数指定输入的宽度(即字符数)。例如:
scanf("%5d",&a);
输入12345678只把12345赋予变量a,其余部分被截去。又如:
scanf("%4d%4d",&a,&b);
输入12345678将把1234赋予a,而把5678赋予b。

4) 长度
长度格式符为l和h,l表示输入长整型数据(如%ld)和双精度浮点数(如%lf)。h表示输入短整型数据。

使用scanf函数还必须注意以下几点:

  1. scanf函数中没有精度控制,如:scanf(“%5.2f”,&a);是非法的。不能企图用此语句输入小数为2位的实数。
  2. scanf中要求给出变量地址,如给出变量名则会出错。如 scanf(“%d”,a);是非法的,应改为scnaf(“%d”,&a);才是合法的。
  3. 在输入多个数值数据时,若格式控制串中没有非格式字符作输入数据之间的间隔则可用空格,TAB或回车作间隔。C编译在碰到空格,TAB,回车或非法数据(如对“%d”输入“12A”时,A即为非法数据)时即认为该数据结束。
  4. 在输入字符数据时,若格式控制串中无非格式字符,则认为所有输入的字符均为有效字符。

例如:
scanf("%c%c%c",&a,&b,&c);
输入 d、e、f 则把’d’赋予a,’ ‘ 赋予b,’e’赋予c。只有当输入为 def 时,才能把’d’赋于a,’e’赋予b,’f’赋予c。

如果在格式控制中加入空格作为间隔,如:
scanf ("%c %c %c",&a,&b,&c);
则输入时各数据之间可加空格。

1
2
3
4
5
6
7
8
#include <stdio.h>
int main(void){
char a,b;
printf("input character a,b\n");
scanf("%c%c",&a,&b);
printf("%c%c\n",a,b);
return 0;
}

由于scanf函数”%c%c”中没有空格,输入M N,结果输出只有M。而输入改为MN时则可输出MN两字符。

1
2
3
4
5
6
7
8
#include <stdio.h>
int main(void){
char a,b;
printf("input character a,b\n");
scanf("%c %c",&a,&b);
printf("\n%c%c\n",a,b);
return 0;
}

本例表示scanf格式控制串”%c %c”之间有空格时,输入的数据之间可以有空格间隔。

5) 如果格式控制串中有非格式字符则输入时也要输入该非格式字符。

例如:
scanf("%d,%d,%d",&a,&b,&c);
其中用非格式符“ , ”作间隔符,故输入时应为:5,6,7。又如:
scanf("a=%d,b=%d,c=%d",&a,&b,&c);
则输入应为:a=5,b=6,c=7。

6) 如输入的数据与输出的类型不一致时,虽然编译能够通过,但结果将不正确。

1
2
3
4
5
6
7
8
#include <stdio.h>
int main(void){
int a;
printf("input a number\n");
scanf("%d",&a);
printf("%ld",a);
return 0;
}

由于输入数据类型为整型,而输出语句的格式串中说明为长整型,因此输出结果和输入数据不符。如改动程序如下:

1
2
3
4
5
6
7
8
#include <stdio.h>
int main(void){
long a;
printf("input a long integer\n");
scanf("%ld",&a);
printf("%ld",a);
return 0;
}
1
2
3
4
运行结果为:
input a long integer
1234567890
1234567890

当输入数据改为长整型后,输入输出数据相等。

1
2
3
4
5
6
7
8
#include <stdio.h>
int main(void){
char a,b,c;
printf("input character a,b,c\n");
scanf("%c %c %c",&a,&b,&c);
printf("%d,%d,%d\n%c,%c,%c\n",a,b,c,a-32,b-32,c-32);
return 0;
}

输入三个小写字母,输出其ASCII码和对应的大写字母。

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
int main(void){
int a;
long b;
float f;
double d;
char c;
printf("\nint:%d\nlong:%d\nfloat:%d\ndouble:%d\nchar:%d\n",sizeof(a),sizeof(b),sizeof(f),sizeof(d),sizeof(c));
return 0;
}

输出各种数据类型的字节长度。

非格式化的输入输出函数:

puts()函数:

puts()函数用于将一字符串放到标准输出流(stdout)中,并在最后增加换行符 ‘\n’,其函数原型如下:
int puts(char *string);

【参数】string为要输出的字符串。

【返回值】输出成功返回非0值,否则返回0。

puts()从string的开头往stdout中输出字符,直到遇见结束标志 ‘\0’,’\0’不会被输出到stdout。

一个简单的例子,直接将字符串输出

1
2
3
4
5
6
7
#include<stdio.h>
int main(void)
{
char str[100] = "The string come from puts";
puts(str);
return 0;
}

程序中puts()函数的作用与语句“printf(“%s\n”,s);的作用相同,可以认为puts()是printf()函数的简化版。

gets()函数

不要用gets()了

gets()函数用于从缓冲区中读取字符串,其原型如下:
char *gets(char *string);

gets()函数从流中读取字符串,直到出现换行符或读到文件尾为止,最后加上NULL作为字符串结束。所读取的字符串暂存在给定的参数string中。

【返回值】若成功则返回string的指针,否则返回NULL。

注意:由于gets()不检查字符串string的大小,必须遇到换行符或文件结尾才会结束输入,因此容易造成缓存溢出的安全性问题,导致程序崩溃,可以使用fgets()代替

如果你在GCC中使用gets(),编译无法通过,会提示:
the ‘gets’ function is dangerous and shout not be used.

putchar()函数

函数putchar()用于将给定的字符输出到控制台,其原型如下:
int putchar (int ch);

【参数】ch为要输出的字符。

【返回值】输出成功,返回该字符的ASCII码值,否则返回EOF。

说明:putchar()非真正函数,而是putc(ch, stdout)宏定义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
int main(void)
{
char a,b,c;
a='T',b='M',c='D';
putchar(a); /*输出字符*/
putchar(b);
putchar(c);
putchar('\n'); /*换行*/
putchar(a);
putchar('\n');
putchar(b);
putchar('\n');
putchar(c);
putchar('\n');
return 0;
}

getchar()、getche()、getch() 函数,它们都用来从控制台获取字符,getchar() 会等待用户按下回车键才开始读取,而 getche()、getch() 会立即读取。这是因为 getchar() 带有缓冲区,用户输入的数据会暂时保存到缓冲区,直到按下回车键才开始读取;而 getche()、getch() 不带缓冲区,只能立即读取。

getchar()函数

getchar() 函数的特点是:如果缓冲区中没有内容,那么等待用户输入;如果有内容,哪怕一个字符,也会直接从缓冲区中读取数据,不会等待用户输入。

第一次调用 getchar() 时,会等待用户输入,用户输入的所有字符都被放到标准输入(stdin)缓冲区,直到用户按下回车键为止(回车符也被放入缓冲区)。用户按下回车键,getchar() 函数才开始从缓冲区中读取数据,每次读取一个字符。

借助 getchar() 函数将 \n 从缓冲区中清除:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a=0, b=0;
scanf("a=%d", &a);
getchar();
scanf("b=%d", &b);
printf("a=%d, b=%d\n", a, b);

system("pause");
return 0;
}
1
2
3
4
运行结果:
a=100↙
b=100↙
a=100, b=100

执行完第一个 scanf() 后,缓冲区中剩下换行符 \n,我们使用 getchar() 将其读出(并不使用),执行到第二个 scanf() 时,由于缓冲区中没有内容,所以会等待用户输入。

getch()函数

getch 和 getchar 的作用类似,都是从键盘读取一个字符,但是:
getch 不带回显,也就是说,你输入的字符不会在屏幕上显示出来。
getch 没有缓冲区,也就是说,输入一个字符就立即读取。

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#include <conio.h>
int main(){
char c1, c2;
c1 = getch();
printf("%c\n", c1);
c2 = getch();
printf("%c\n", c2);
return 0;
}
1
2
3
4
5
6
先输入 'a',再输入 'b',运行结果为:
a
b

输入一个字符,getch 会立即获取,不会给你多输入一个字符的机会。并且输入的字符只由 printf 语句显示一次,getch 不会显示。
注意要包含头文件conio.h,getch 和 getche 都在该头文件中声明。

getche()函数

getche()和getch()很相似,也没有缓冲区,区别在于:getch()无回显,getche()有回显。

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#include <conio.h>
int main(){
char c1, c2;
c1 = getche();
printf("%c\n", c1);
c2 = getche();
printf("%c\n", c2);
return 0;
}
1
2
3
先输入 'a',再输入 'b',运行结果为:
aa
bb

fgets()函数:

fgets()函数用于从文件流中读取一行或指定个数的字符,其原型为:
char * fgets(char * string, int size, FILE * stream);

参数说明:

  • string为一个字符数组,用来保存读取到的字符。
  • size为要读取的字符的个数。如果该行字符数大于size-1,则读到 size-1 个字符时结束,并在最后补充’ \0’;如果该行字符数小于等于 size-1,则读取所有字符,并在最后补充 ‘\0’。即,每次最多读取 size-1 个字符。
  • stream为文件流指针。

【返回值】读取成功,返回读取到的字符串,即string;失败或读到文件结尾返回NULL。因此我们不能直接通过fgets()的返回值来判断函数是否是出错而终止的,应该借助feof()函数或者ferror()函数来判断。

注意:fgets()与gets()不一样,不仅仅是因为gets()函数只有一个参数 FILE *stream,更重要的是,fgets()可以指定最大读取的字符串的个数,杜绝了gets()使用不当造成缓存溢出的问题。

从myfile.txt文件中读取最多99个字符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
int main()
{
FILE * pFile;
char mystring [100];
pFile = fopen ("myfile.txt" , "r");
if (pFile == NULL)
perror ("Error opening file");
else {
if ( fgets (mystring , 100 , pFile) != NULL )
puts (mystring);
fclose (pFile);
}
return 0;
}

又如,使用fputs()写一个文件,然后fgets()读取文件内容并显示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
#include<stdlib.h>
#include<io.h>
#include<conio.h>
int main(void)
{
char msg[] = "This is a test!\n secend line\n";
char msgget[100];
int i = 0;
FILE* fstream;
fstream = fopen("test.txt","w+"); /*打开文件*/
if(fstream==NULL)
{
printf("Open file failed!\n");
exit(1);
}
fputs(msg, fstream); /*写入文件*/
fflush(fstream);
close(fileno(fstream));
fstream=fopen("test.txt","r");
i = 0;
fgets(msgget,3,fstream) ;
fputs(msgget, stdout);
printf("\n");
fgets(msgget,100,fstream) ;/*从流中读取一行或者指定个数字符*/
fputs(msgget, stdout); /*送一个字符串到流中*/
return 0;
}
1
2
3
运行结果:
Th
is is a test!

程序首先创建一个空文件,并利用fputs()函数写 入两行字符串,刷新关闭。然后重新以只读的方式打开该文件, 使用fgets()函数连续两次读取该文件,第一次读取3-1个字符,第 二次读取一行。最终结果都显示出来。

Donate? comment?