C03-input-output-if-for

本文最后更新于:1 小时前

C 输入 & 输出

输出函数

puts():只能输出字符串,并且输出结束后会自动换行。
putchar():只能输出单个字符。
printf():可以输出各种类型的数据。

输入函数

scanf():和 printf() 类似,scanf() 可以输入多种类型的数据。
getchar()、getche()、getch():这三个函数都用于输入单个字符。
gets():获取一行数据,并作为字符串处理。

getchar() & putchar() 函数

int getchar(void) 函数从屏幕读取下一个可用的字符,并把它返回为一个整数。这个函数在同一个时间内只会读取一个单一的字符。在循环内使用这个方法,可以从屏幕上读取多个字符。

int putchar(int c) 函数把字符输出到屏幕上,并返回相同的字符。这个函数在同一个时间内只会输出一个单一的字符。在循环内使用这个方法,可以在屏幕上输出多个字符。

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>

int main( )
{
int c;

printf( "Enter a value :");
c = getchar( );

printf( "\nYou entered: ");
putchar( c );
printf( "\n");
return 0;
}

当输入一个文本并按下回车键时,程序会继续并只会读取一个单一的字符,显示如下:

1
2
3
4
$./a.out
Enter a value :hello

You entered: h

其他输入单个字符的函数:

(1)getche()
getche() 没有缓冲区,输入一个字符后会立即读取,不用等待用户按下回车键,这是它和 scanf()、getchar() 的最大区别。

注意,getche() 位于 conio.h 头文件中,而这个头文件是 Windows 特有的,Linux 和 Mac OS 下没有包含该头文件。换句话说,getche() 并不是标准函数,默认只能在 Windows 下使用,不能在 Linux 和 Mac OS 下使用。

(2)getch()
getch() 也没有缓冲区,输入一个字符后会立即读取,不用按下回车键,这一点和 getche() 相同。getch() 的特别之处是它没有回显,看不到输入的字符。所谓回显,就是在控制台上显示出用户输入的字符;没有回显,就不会显示用户输入的字符,就好像根本没有输入一样。(在某些特殊情况下,不希望有回显,比如输入密码时)

示例

1
2
3
4
5
6
7
8
#include <stdio.h>
#include <conio.h>
int main()
{
char c = getch();
printf("c: %c\n", c);
return 0;
}

输入一个字符后,getch() 会立即读取完毕,接着继续执行 printf() 将字符输出。但是由于 getch() 没有回显,看不到输入的字符,所以控制台上最终显示的内容为c: 所输入的字符(如:a)。

注意,和 getche() 一样,getch() 也位于 conio.h 头文件中,也不是标准函数,默认只能在 Windows 下使用,不能在 Linux 和 Mac OS 下使用。

三个输入字符函数对比:

函数 缓冲区 头文件 回显 适用平台
getchar() 有 stdio.h 有 Windows、Linux、Mac OS 等所有平台
getche() 无 conio.h 有 Windows
getch() 无 conio.h 无 Windows

gets() & puts() 函数

char *gets(char *s) 函数从 stdin(标准输入) 读取一行到 s 所指向的缓冲区,直到一个终止符或 EOF。

int puts(const char *s) 函数把字符串 s 和一个尾随的换行符写入到 stdout(标准输出)。

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>

int main( )
{
char str[100];

printf( "Enter a value :");
gets( str );

printf( "\nYou entered: ");
puts( str );
return 0;
}

当上面的代码被编译和执行时,它会等待用户输入一些文本,当输入一个文本并按下回车键时,程序会继续并读取一整行直到该行结束,显示如下:

1
2
3
4
$./a.out
Enter a value :hello

You entered: hello

注意:gets函数由于没有指定输入字符大小,所以会无限读取,一旦输入的字符大于数组长度,就会发生内存越界,从而造成程序崩溃或其他数据的错误。

gets() 是有缓冲区的,每次按下回车键,就代表当前输入结束了,gets() 开始从缓冲区中读取内容,这一点和 scanf() 是一样的。gets() 和 scanf() 的主要区别是:

scanf() 读取字符串时以空格为分隔,遇到空格就认为当前字符串结束了,所以无法读取含有空格的字符串。
gets() 认为空格也是字符串的一部分,只有遇到回车键时才认为字符串输入结束,所以,不管输入了多少个空格,只要不按下回车键,对 gets() 来说就是一个完整的字符串。

也就是说,gets() 能读取含有空格的字符串,而 scanf() 不能。

另外在linux系统下不支持 gets 与 puts, 需要用 fgets 和 fputs。

gets()与fgets()
gets()
gets函数原型:chargets(charbuffer);//读取字符到数组:gets(str);str为数组名。

gets函数功能:从键盘上输入字符,直至接受到换行符或EOF时停止,并将读取的结果存放在buffer指针所指向的字符数组中。

读取的换行符被转换为null值,做为字符数组的最后一个字符,来结束字符串。

注意:gets函数由于没有指定输入字符大小,所以会无限读取,一旦输入的字符大于数组长度,就会发生内存越界,从而造成程序崩溃或其他数据的错误。

fgets()
fgets函数原型:char *fgets(char *s, int n, FILE *stream);//我们平时可以这么使用:fgets(str, sizeof(str), stdin);

其中str为数组首地址,sizeof(str)为数组大小,stdin表示我们从键盘输入数据。

fgets函数功能:从文件指针stream中读取字符,存到以s为起始地址的空间里,直到读完N-1个字符,或者读完一行。

注意:调用fgets函数时,最多只能读入n-1个字符。读入结束后,系统将自动在最后加’\0’,并以str作为函数值返回。

scanf() 和 printf() 函数

格式控制符:
格式控制符 说明
%c 输出一个单一的字符
%hd、%d、%ld 以十进制、有符号的形式输出 short、int、long 类型的整数
%hu、%u、%lu 以十进制、无符号的形式输出 short、int、long 类型的整数
%ho、%o、%lo 以八进制、不带前缀、无符号的形式输出 short、int、long 类型的整数
%#ho、%#o、%#lo 以八进制、带前缀、无符号的形式输出 short、int、long 类型的整数
%hx、%x、%lx
%hX、%X、%lX 以十六进制、不带前缀、无符号的形式输出 short、int、long 类型的整数。如果 x 小写,那么输出的十六进制数字也小写;如果 X 大写,那么输出的十六进制数字也大写。
%#hx、%#x、%#lx
%#hX、%#X、%#lX 以十六进制、带前缀、无符号的形式输出 short、int、long 类型的整数。如果 x 小写,那么输出的十六进制数字和前缀都小写;如果 X 大写,那么输出的十六进制数字和前缀都大写。
%f、%lf 以十进制的形式输出 float、double 类型的小数
%e、%le
%E、%lE 以指数的形式输出 float、double 类型的小数。如果 e 小写,那么输出结果中的 e 也小写;如果 E 大写,那么输出结果中的 E 也大写。
%g、%lg
%G、%lG 以十进制和指数中较短的形式输出 float、double 类型的小数,并且小数部分的最后不会添加多余的 0。如果 g 小写,那么当以指数形式输出时 e 也小写;如果 G 大写,那么当以指数形式输出时 E 也大写。
%s 输出一个字符串

printf() 格式控制符的完整形式如下:
%[flag][width][.precision]type

  1. type 表示输出类型,比如 %d、%f、%c、%lf,type 就分别对应 d、f、c、lf;再如,%-9d中 type 对应 d。

type 这一项必须有,这意味着输出时必须要知道是什么类型。

  1. width 表示最小输出宽度,也就是至少占用几个字符的位置;例如,%-9d中 width 对应 9,表示输出结果最少占用 9 个字符的宽度。

当输出结果的宽度不足 width 时,以空格补齐(如果没有指定对齐方式,默认会在左边补齐空格);当输出结果的宽度超过 width 时,width 不再起作用,按照数据本身的宽度来输出。

  1. .precision 表示输出精度,也就是小数的位数。
    当小数部分的位数大于 precision 时,会按照四舍五入的原则丢掉多余的数字;
    当小数部分的位数小于 precision 时,会在后面补 0。

另外,.precision 也可以用于整数和字符串,但是功能却是相反的:
用于整数时,.precision 表示最小输出宽度。与 width 不同的是,整数的宽度不足时会在左边补 0,而不是补空格。
用于字符串时,.precision 表示最大输出宽度,或者说截取字符串。当字符串的长度大于 precision 时,会截掉多余的字符;当字符串的长度小于 precision 时,.precision 就不再起作用。

  1. flag 是标志字符。例如,%#x中 flag 对应 #,%-9d中 flags 对应-。下表列出了 printf() 可以用的 flag:
    标志字符 含 义
  • -表示左对齐。如果没有,就按照默认的对齐方式,默认一般为右对齐。
  • 用于整数或者小数,表示输出符号(正负号)。如果没有,那么只有负数才会输出符号。
    空格 用于整数或者小数,输出值为正时冠以空格,为负时冠以负号。
    ‘#’
    对于八进制(%o)和十六进制(%x / %X)整数,# 表示在输出时添加前缀;八进制的前缀是 0,十六进制的前缀是 0x / 0X。
    对于小数(%f / %e / %g),# 表示强迫输出小数点。如果没有小数部分,默认是不输出小数点的,加上 # 以后,即使没有小数部分也会带上小数点。

scanf() 读取字符串时以空格为分隔,遇到空格就认为当前字符串结束了,所以无法读取含有空格的字符串

scanf() 格式控制符汇总
格式控制符 说明
%c 读取一个单一的字符
%hd、%d、%ld 读取一个十进制整数,并分别赋值给 short、int、long 类型
%ho、%o、%lo 读取一个八进制整数(可带前缀也可不带),并分别赋值给 short、int、long 类型
%hx、%x、%lx 读取一个十六进制整数(可带前缀也可不带),并分别赋值给 short、int、long 类型
%hu、%u、%lu 读取一个无符号整数,并分别赋值给 unsigned short、unsigned int、unsigned long 类型
%f、%lf 读取一个十进制形式的小数,并分别赋值给 float、double 类型
%e、%le 读取一个指数形式的小数,并分别赋值给 float、double 类型
%g、%lg 既可以读取一个十进制形式的小数,也可以读取一个指数形式的小数,并分别赋值给 float、double 类型
%s 读取一个字符串(以空白符为结束)

Windows、Unix、Mac不同操作系统的换行问题 回车符\r和换行符\n
一、概念:

换行符‘\n’和回车符‘\r’

(1)换行符就是另起一行 — ‘\n’ 10 换行(newline)

(2)回车符就是回到一行的开头 — ‘\r’ 13 回车(return)

所以我们平时编写文件的回车符应该确切来说叫做回车换行符

CR: 回车(Carriage Return) \rLF: 换行(Line Feed) \n

二、应用:

(1)在微软的MS-DOS和Windows中,使用“回车CR(‘\r’)”和“换行LF(‘\n’)”两个字符作为换行符;

(2)Windows系统里面,每行结尾是 回车+换行(CR+LF),即“\r\n”;

(3)Unix系统里,每行结尾只有 换行LF,即“\n”;

(4)Mac系统里,每行结尾是 回车CR 即’\r’。

Mac OS 9 以及之前的系统的换行符是 CR,从 Mac OS X (后来改名为“OS X”)开始的换行符是 LF即‘\n’,和Unix/Linux统一了。

三、影响:

(1)一个直接后果是,Unix/Mac系统下的文件在Windows里打开的话,所有文字会变成一行;

(2)而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个^M符号。

(3)Linux保存的文件在windows上用记事本看的话会出现黑点。

四、可以相互转换:

在linux下,命令unix2dos 是把linux文件格式转换成windows文件格式,命令dos2unix 是把windows格式转换成linux文件格式。

在不同平台间使用FTP软件传送文件时, 在ascii文本模式传输模式下, 一些FTP客户端程序会自动对换行格式进行转换. 经过这种传输的文件字节数可能会发生变化.

如果你不想ftp修改原文件, 可以使用bin模式(二进制模式)传输文本。

一个程序在windows上运行就生成CR/LF换行格式的文本文件,而在Linux上运行就生成LF格式换行的文本文件。

C判断 & 循环

switch 语句注意点:

switch 语句中的 expression 是一个常量表达式,必须是一个整型或枚举类型。

在一个 switch 中可以有任意数量的 case 语句。每个 case 后跟一个要比较的值和一个冒号。

case 后要比较的值 必须与 switch 中的变量具有相同的数据类型,且必须是一个常量或字面量。

当被测试的变量等于 case 中的常量时,case 后跟的语句将被执行,即会执行该分支以及后面所有分支的语句,直到遇到 break 语句为止。当遇到 break 语句时,switch 终止,控制流将跳转到 switch 语句后的下一行,也就是说,整个 switch 执行结束了,接着会执行整个 switch 后面的代码。

不是每一个 case 都需要包含 break。如果 case 语句不包含 break,控制流将会 继续 后续的 case,直到遇到 break 为止。

一个 switch 语句可以有一个可选的 default case,出现在 switch 的结尾。default case 可用于在上面所有 case 都不为真时执行一个任务。当没有 default 时,如果所有 case 都匹配失败,那么就什么都不执行。由于 default 是最后一个分支,匹配后不会再执行其他分支,所以default中的 break 语句不是必需的。

循环类型

循环类型 描述
while 循环 当给定条件为真时,重复语句或语句组。它会在执行循环主体之前测试条件。
for 循环 多次执行一个语句序列,简化管理循环变量的代码。
do…while 循环 除了它是在循环主体结尾测试条件外,其他与 while 语句类似。
嵌套循环 您可以在 while、for 或 do..while 循环内使用一个或多个循环。

C语言for循环中的三个表达式
for 循环中的“表达式1(初始化条件)”、“表达式2(循环条件)”和“表达式3(自增或自减)”都是可选项,都可以省略(但分号;必须保留)。

  1. 省略了“表达式2(循环条件)”,如果不做其它处理就会成为死循环。
  2. 省略了“表达式3(自增或自减)”,就不会修改“表达式2(循环条件)”中的变量,这时可在循环体中加入修改变量的语句。
  3. 省略了“表达式1(初始化语句)”和“表达式3(自增或自减)” 例如:
1
2
3
4
for( ; i<=100 ; ){
sum=sum+i;
i++;
}

相当于:

1
2
3
4
while(i<=100){
sum=sum+i;
i++;
}
  1. 3个表达式可以同时省略。例如:
    for( ; ; ) 语句 相当于: while(1) 语句
  2. “表达式1”可以是初始化语句,也可以是其他语句。例如:
    for( sum=0; i<=100; i++ ) sum=sum+i;
  3. “表达式2”一般是关系表达式或逻辑表达式,但也可是数值或字符,只要其值非零,就执行循环体。例如:
    for( i=0; (c=getchar())!='\n'; i+=c );

do…while 循环

不像 for 和 while 循环,它们是在循环头部测试循环条件。在 C 语言中,do…while 循环是在循环的尾部检查它的条件。
do…while 循环与 while 循环类似,但是 do…while 循环会确保至少执行一次循环。

循环控制语句

控制语句 描述
break 语句 终止循环或 switch 语句,程序流将继续执行紧接着循环或 switch 的下一条语句。
continue 语句 告诉一个循环体立刻停止本次循环迭代,重新开始下次循环迭代。
goto 语句 将控制转移到被标记的语句。但是不建议在程序中使用 goto 语句。

C 语言中 break 语句有以下两种用法:
当 break 语句出现在一个循环内时,循环会立即终止,且程序流将继续执行紧接着循环的下一条语句。
它也可用于终止 switch 语句中的一个 case。
另外如果使用的是嵌套循环(即一个循环内嵌套另一个循环),break 语句会停止执行最内层的循环,然后开始执行该块之后的下一行代码,即在多层循环中,一个 break 语句只向外跳一层。

continue 语句的作用是跳过循环体中剩余的语句而强制进入下一次循环。
对于 for 循环,continue 语句执行后自增语句仍然会执行。对于 while 和 do…while 循环,continue 语句重新执行条件判断语句。

C 语言中的 goto 语句允许把控制无条件转移到同一函数内的被标记的语句。但不建议使用 goto 语句。因为它使得程序的控制流难以跟踪,使程序难以理解和难以修改。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!