从程序流程的角度来看,程序可以分为三种基本结构, 即顺序结构、分支结构、循环结构。 这三种基本结构可以组成所有的各种复杂程序。C语言提供了多种语句来实现这些
程序结构。 本章介绍这些基本语句及其在顺序结构中的应用,使读者对C程序有一个初步的认识。
C程序的执行部分是由语句组成的。 程序的功能也是由执行语句实现的。
C 语句可分为以下五类:
1) 表达式语句
2) 函数调用语句
3) 控制语句
4) 复合语句
5) 空语句
1. 表达式语句
表达式语句由表达式加上分号“;”组成。
其一般形式为:
表达式;
执行表达式语句就是计算表达式的值。
例如:
x=y+z; 赋值语句;
y+z; 加法运算语句,但计算结果不能保留,无实际意义;
i++; 自增 1 语句,i 值增 1。
2. 函数调用语句
由函数名、实际参数加上分号“;”组成。
其一般形式为:
函数名(实际参数表);
执行函数语句就是调用函数体并把实际参数赋予函数定义中的形式参数,然后执行被调函数体中的语句,求取函数值 (在后面函数中再详细介绍) 。
例如:
printf(“C Program”);调用库函数,输出字符串。
3. 控制语句
控制语句用于控制程序的流程, 以实现程序的各种结构方式。它们由特定的语句定义符组成。
C语言有九种控制语句。 可分成以下三类:
1) 条件判断语句:if 语句、switch 语句;
2) 循环执行语句:do while 语句、while 语句、for 语句;
3) 转向语句:break 语句、goto 语句、continue 语句、return 语句。
4. 复合语句
把多个语句用括号{}括起来组成的一个语句称复合语句。在程序中应把复合语句看成是单条语句,而不是多条语句。
例如:
{ x=y+z; a=b+c; printf(“%d%d”,x,a); }
是一条复合语句。
复合语句内的各条语句都必须以分号“;”结尾,在括号“}”外不能加分号。
5. 空语句
只有分号“;”组成的语句称为空语句。空语句是什么也不执行的语句。在程序中空语句可用来作空循环体。
例如
while(getchar()!='\n') ;
本语句的功能是,只要从键盘输入的字符不是回车则重新输入。这里的循环体为空语句。
赋值语句
赋值语句是由赋值表达式再加上分号构成的表达式语句。其一般形式为:
变量=表达式;
赋值语句的功能和特点都与赋值表达式相同。 它是程序中使用最多的语句之一。
在赋值语句的使用中需要注意以下几点:
1. 由于在赋值符“=”右边的表达式也可以又是一个赋值表达式,因此,下述形式
变量=(变量=表达式);
是成立的,从而形成嵌套的情形。
其展开之后的一般形式为:
变量=变量=…=表达式;
例如:
a=b=c=d=e=5;
按照赋值运算符的右接合性,因此实际上等效于:
e=5;
d=e;
c=d;
b=c;
a=b;
2. 注意在变量说明中给变量赋初值和赋值语句的区别
给变量赋初值是变量说明的一部分,赋初值后的变量与其后的其它同类变量之间仍必须用逗号间隔,而赋值语句则必须用分号结尾。
例如:
int a=5,b,c;
3. 在变量说明中,不允许连续给多个变量赋初值。
如下述说明是错误的:
int a=b=c=5
必须写为
int a=5,b=5,c=5;
而赋值语句允许连续赋值。
4. 注意赋值表达式和赋值语句的区别。
赋值表达式是一种表达式,它可以出现在任何允许表达式出现的地方,而赋值语句则不能。
下述语句是合法的:
if((x=y+5)>0) z=x;
语句的功能是,若表达式 x=y+5 大于 0 则 z=x。
下述语句是非法的:
if((x=y+5;)>0) z=x;
因为 x=y+5;是语句,不能出现在表达式中。
格式输入与输出
printf 函数(格式输出函数)
printf 函数称为格式输出函数,其关键字最末一个字母 f 即为“格式”(format)之意。其功能是按用户指定的格式,把指定的数据显示到显示器屏幕上。
在前面的例题中我们已多次使用过这个函数。
1. printf 函数调用的一般形式
printf 函数是一个标准库函数,它的函数原型在头文件“stdio.h”中。但作为一个特例,不要求在使用 printf 函数之前必须包含 stdio.h 文件。
printf 函数调用的一般形式为:
printf(“格式控制字符串”,输出表列)
int printf(const char *format, ...)
其中格式控制字符串用于指定输出格式。format — 这是字符串,包含了要被写入到标准输出 stdout 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是 %[flags][width][.precision][length]specifier,具体讲解如下:
格式字符 | 意义 |
---|---|
d | 以十进制形式输出带符号整数(正数不输出符号) |
o | 以八进制形式输出无符号整数(不输出前缀0) |
x,X | 以十六进制形式输出无符号整数(不输出前缀Ox) |
u | 以十进制形式输出无符号整数 |
f | 以小数形式输出单、双精度实数 |
e,E | 以指数形式输出单、双精度实数 |
g,G | 以%f或%e中较短的输出宽度输出单、双精度实数 |
c | 输出单个字符 |
s | 输出字符串 |
p | 输出指针地址 |
lu | 32位无符号整数 |
llu | 64位无符号整数 |
flags(标识) | 描述 |
---|---|
– | 在给定的字段宽度内左对齐,默认是右对齐(参见 width 子说明符)。 |
+ | 强制在结果之前显示加号或减号(+ 或 -),即正数前面会显示 + 号。默认情况下,只有负数前面会显示一个 – 号。 |
空格 | 如果没有写入任何符号,则在该值前面插入一个空格。 |
# | 与 o、x 或 X 说明符一起使用时,非零值前面会分别显示 0、0x 或 0X。 与 e、E 和 f 一起使用时,会强制输出包含一个小数点,即使后边没有数字时也会显示小数点。默认情况下,如果后边没有数字时候,不会显示显示小数点。 与 g 或 G 一起使用时,结果与使用 e 或 E 时相同,但是尾部的零不会被移除。 |
0 | 在指定填充 padding 的数字左边放置零(0),而不是空格(参见 width 子说明符)。 |
width(宽度) | 描述 |
---|---|
(number) | 要输出的字符的最小数目。如果输出的值短于该数,结果会用空格填充。如果输出的值长于该数,结果不会被截断。 |
* | 宽度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格式化的参数之前。 |
.precision(精度) | 描述 |
---|---|
.number | 对于整数说明符(d、i、o、u、x、X):precision 指定了要写入的数字的最小位数。如果写入的值短于该数,结果会用前导零来填充。如果写入的值长于该数,结果不会被截断。精度为 0 意味着不写入任何字符。 对于 e、E 和 f 说明符:要在小数点后输出的小数位数。 对于 g 和 G 说明符:要输出的最大有效位数。 对于 s: 要输出的最大字符数。默认情况下,所有字符都会被输出,直到遇到末尾的空字符。 对于 c 类型:没有任何影响。 当未指定任何精度时,默认为 1。如果指定时不带有一个显式值,则假定为 0。 |
.* | 精度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格式化的参数之前。 |
length(长度) | 描述 |
---|---|
h | 参数被解释为短整型或无符号短整型(仅适用于整数说明符:i、d、o、u、x 和 X)。 |
l | 参数被解释为长整型或无符号长整型,适用于整数说明符(i、d、o、u、x 和 X)及说明符 c(表示一个宽字符)和 s(表示宽字符字符串)。 |
L | 参数被解释为长双精度型(仅适用于浮点数说明符:e、E、f、g 和 G)。 |
- 附加参数 — 根据不同的 format 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 format 参数中指定的每个 % 标签。参数的个数应与 % 标签的个数相同。
规定符
- %d 十进制有符号整数
- %u 十进制无符号整数
- %f 浮点数
- %s 字符串
- %c 单个字符
- %p 指针的值
- %e 指数形式的浮点数
- %x, %X 无符号以十六进制表示的整数
- %o 无符号以八进制表示的整数
- %g 把输出的值按照 %e 或者 %f 类型中输出长度较小的方式输出
- %p 输出地址符
- %lu 32位无符号整数
- %llu 64位无符号整数
返回值
如果成功,则返回写入的字符总数,否则返回一个负数。
格式控制串可由格式字符串和非格式字符串两种组成。格式字符串是以%开头的字符串,在%后面跟有各种格式字符,以说明输出数据的类型、形式、长度、小数位数等。如:
- “%d”表示按十进制整型输出;
- “%f”表示按浮点型输出;
- “%c”表示按字符型输出等。
非格式字符串在输出时原样照印,在显示中起提示作用。输出表列中给出了各个输出项,要求格式字符串和各输出项在数量和类型上应该一一对应。
例一,
main() { int a=88,b=89; float c,d; c=a; d=b; printf("%d %d\n",a,b); printf("%f,%f\n",c,d); printf("%c,%c\n",a,b); printf("a=%d,b=%d",a,b); }
本例中三次次输出了 a,b 的值,但由于格式控制串不同,输出的结果也不相同。第七行的输出语句格式控制串中,两格式串%d 之间加了一个空格(非格式字符),所以输出的 a,b 值
之间有一个空格。第八行的 printf 语句格式控制串中加入的是非格式字符逗号, 因此输出的 c,d 值之间加了一个逗号。第九行的格式串要求按字符型输出 a,b 值(88,89 在ASCII码对应的应该是X,Y)。第十行中为了提示输出结果又增加了非格式字符串。
例二:
#include <stdio.h> int main () { int ch; for( ch = 75 ; ch <= 100; ch++ ) { printf("ASCII value = %d, char = %c\n", ch , ch ); } return(0); }
#include<stdio.h> main() { printf("The color: %s\n", "blue"); printf("First number: %d\n", 12345); printf("Second number: %04d\n", 25); printf("Third number: %i\n", 1234); printf("Float number: %3.2f\n", 3.14159); printf("Hexadecimal: %x\n", 255); printf("Octal: %o\n", 255); printf("Unsigned value: %u\n", 150); printf("Just print the percentage sign %%\n", 10); }
- %d (print as a decimal integer)
- %6d (print as a decimal integer with a width of at least 6 wide)
- %f (print as a floating point)
- %4f (print as a floating point with a width of at least 4 wide)
- %.4f (print as a floating point with a precision of four characters after the decimal point)
- %3.2f (print as a floating point at least 3 wide and a precision of 2)
例四
#include
main()
{
printf(“:%s:\n”, “Hello, world!”);
printf(“:%15s:\n”, “Hello, world!”);
printf(“:%.10s:\n”, “Hello, world!”);
printf(“:%-10s:\n”, “Hello, world!”);
printf(“:%-15s:\n”, “Hello, world!”);
printf(“:%.15s:\n”, “Hello, world!”);
printf(“:%15.10s:\n”, “Hello, world!”);
printf(“:%-15.10s:\n”, “Hello, world!”);
}
{/code]
- The printf(“:%s:\n”, “Hello, world!”); statement prints the string (nothing special happens.)
- The printf(“:%15s:\n”, “Hello, world!”); statement prints the string, but print 15 characters. If the string is smaller the “empty” positions will be filled with “whitespace.”
- The printf(“:%.10s:\n”, “Hello, world!”); statement prints the string, but print only 10 characters of the string.
- The printf(“:%-10s:\n”, “Hello, world!”); statement prints the string, but prints at least 10 characters. If the string is smaller “whitespace” is added at the end. (See next example.)
- The printf(“:%-15s:\n”, “Hello, world!”); statement prints the string, but prints at least 15 characters. The string in this case is shorter than the defined 15 character, thus “whitespace” is added at the end (defined by the minus sign.)
- The printf(“:%.15s:\n”, “Hello, world!”); statement prints the string, but print only 15 characters of the string. In this case the string is shorter than 15, thus the whole string is printed.
- The printf(“:%15.10s:\n”, “Hello, world!”); statement prints the string, but print 15 characters.
If the string is smaller the “empty” positions will be filled with “whitespace.” But it will only print a maximum of 10 characters, thus only part of new string (old string plus the whitespace positions) is printed. - The printf(“:%-15.10s:\n”, “Hello, world!”); statement prints the string, but it does the exact same thing as the previous statement, accept the “whitespace” is added at the end.
scanf 函数(格式输入函数)
scanf 函数称为格式输入函数,即按用户指定的格式从键盘上把数据输入到指定的变量之中。C 库函数 int scanf(const char *format, …) 从标准输入 stdin 读取格式化输入。
scanf 函数的一般形式
scanf 函数是一个标准库函数,它的函数原型在头文件“stdio.h”中,与 printf 函数相同,C语言也允许在使用 scanf 函数之前不必包含 stdio.h 文件。
scanf 函数的一般形式为:
scanf(“格式控制字符串”,地址表列);
其中,格式控制字符串的作用与 printf 函数相同,但不能显示非格式字符串,也就是不能显示提示字符串。地址表列中给出各变量的地址。地址是由地址运算符“&”后跟变量名组成的。
例如:
&a, &b
分别表示变量 a 和变量 b 的地址。
这个地址就是编译系统在内存中给 a,b 变量分配的地址。在C语言中,使用了地址这个概念,这是与其它语言不同的。 应该把变量的值和变量的地址这两个不同的概念区别开来。
变量的地址是 C 编译系统分配的,用户不必关心具体的地址是多少。
变量的地址和变量值的关系如下:
在赋值表达式中给变量赋值,如:
a=567
则,a 为变量名,567 是变量的值,&a 是变量 a 的地址。
但在赋值号左边是变量名,不能写地址,而 scanf 函数在本质上也是给变量赋值,但要求写变量的地址,如&a。 这两者在形式上是不同的。&是一个取地址运算符,&a 是一个表达式,其功能是求变量的地址。
例五
main(){ int a,b,c; printf("input a,b,c\n"); scanf("%d%d%d",&a,&b,&c); printf("a=%d,b=%d,c=%d",a,b,c); }
在本例中,由于 scanf 函数本身不能显示提示串,故先用 printf 语句在屏幕上输出提示,请用户输入 a、b、c 的值。执行 scanf 语句,则退出 TC 屏幕进入用户屏幕等待用户输入。用户输入 10 20 30 后按下回车键,此时,系统又将返回 TC 屏幕。在 scanf 语句的格式串中由于没有非格式字符在“%d%d%d”之间作输入时的间隔,因此在输入时要用一个以上的空格或回车键作为每两个输入数之间的间隔。如:
10 20 30
或
10
20
30
格式字符串
格式字符串的一般形式为:
%[*][输入数据宽度][长度]类型
其中有方括号[]的项为任选项。各项的意义如下。
1) 类型
表示输入数据的类型,其格式符和意义如下表所示。
scanf 类型说明符:
类型 | 合格的输入 | 参数的类型 |
---|---|---|
%c | 单个字符:读取下一个字符。如果指定了一个不为 1 的宽度 width,函数会读取 width 个字符,并通过参数传递,把它们存储在数组中连续位置。在末尾不会追加空字符。 | char * |
%d | 十进制整数:数字前面的 + 或 – 号是可选的。 | int * |
%e、%E、%f、%F、%g、%G | 浮点数:包含了一个小数点、一个可选的前置符号 + 或 -、一个可选的后置字符 e 或 E,以及一个十进制数字。两个有效的实例 -732.103 和 7.12e4 | float * |
%i | 读入十进制,八进制,十六进制整数 。 | int * |
%o | 八进制整数。 | int * |
%s | 字符串。这将读取连续字符,直到遇到一个空格字符(空格字符可以是空白、换行和制表符)。 | char * |
%u | 无符号的十进制整数。 | unsigned int * |
%x、%X | 十六进制整数。 | int * |
%p | 读入一个指针 。 | |
%[] | 扫描字符集合 。 | |
%% | 读 % 符号。 |
- 附加参数 — 根据不同的 format 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 format 参数中指定的每个 % 标签。参数的个数应与 % 标签的个数相同。
2) “*”符
用以表示该输入项,读入后不赋予相应的变量,即跳过该输入值。如:
3) 宽度
用十进制整数指定输入的宽度(即字符数)。例如:
scanf("%5d",&a);
4) 长度
长度格式符为l和h,l表示输入长整型数据(如%ld)和双精度浮点数(如%lf)。h表示输入短整型数据。
使用scanf函数还必须注意以下几点:
- scanf函数中没有精度控制,如:scanf(“%5.2f”,&a);是非法的。不能企图用此语句输入小数为2位的实数。
- scanf中要求给出变量地址,如给出变量名则会出错。如 scanf(“%d”,a);是非法的,应改为scnaf(“%d”,&a);才是合法的。
- 在输入多个数值数据时,若格式控制串中没有非格式字符作输入数据之间的间隔则可用空格,TAB或回车作间隔。C编译在碰到空格,TAB,回车或非法数据(如对“%d”输入“12A”时,A即为非法数据)时即认为该数据结束。
- 在输入字符数据时,若格式控制串中无非格式字符,则认为所有输入的字符均为有效字符。
例六
main(){ int a,b,c,g; char e,d,f; printf("input three chars\n"); scanf("%c%c%c",&e,&d,&f); printf("e=%c,d=%c,f=%c\n",e,d,f); printf("input a,b,c\n"); scanf("%d %*d %d",&a,&b); printf("a=%d,b=%d\n",a,b); printf("input a number bigger than 5\n"); scanf("%5d",&g); printf("g=%d\n",g); }
例七
#include <stdio.h> int main(void){ char a,b,c; printf("input character a,b,c\n"); scanf("%2c %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; }
注意事项
- scanf的双引号内永远不要加“非输入控制符”。除了“输入控制符”之外,什么都不要加,否则就是自找麻烦,而且对于用户而言,肯定是输入越简单越好。在scanf中,所有的“非输入控制符”都必须要原样输入;
- 参数的个数一定要对应。无论在顺序上,还是在个数上,一定要一一对应;
- 输入的数据类型一定要与所需要的数据类型一致,对于输入的数据类型是用户输入的,所以在写程序时要考虑容错处理;
- 在使用scanf之前使用printf提示输入,可以大大提高代码的质量。