上一节讲了常量及常量数据类型的表示方法,阐明了字符型常量与整型常量的关系。本节主要讲各种数据类型的输入与输出。
我们知道格式化输入与输出函数的格式如下:
scanf(格式控制字符串,地址1,地址2,地址3...);
printf(格式控制字符串,表达式1,表达式2,....);
scanf函数功能是把数据从键盘上输入到“地址1”、“地址2”等对应的内存空间中,变量的地址可通过 & 运算符获得。函数返回一个整数,表示输入的数据个数。printf函数是把“表达式1”、“表达式2”等表达式的值计算完成后,显示在屏幕上。待输出的表达式计算的顺序从右至左进行。
在输入与输出时,函数scanf与printf中的格式控制字符串中以 % 开始的格式符个数必须与地址的项数或表达式的项数相同,格式符代表的类型必须与对应的地址项或表达式的类型一致,否则输入和输出结果可能不正确。
我们先来看整数的输入与输出。由于整数分为短整型(short)、整型(int)、长整型(long)和长长整型(long long),又加上整数还分有符号数和无符号数,因此,整数的格式符要复杂一些。除了前面学习的%d外,不同类型的整数格式符如表:
整数类型 | 字节数 | 格式符 |
int | 2/4 | %d |
unsigned int 或 unsigned | 4 | %u |
short int或short | 2 | %hd |
unsigned short int 或unsigned short | 2 | %hu |
long int 或 long | 4 | %ld |
unsigned long int 或 unsigned long | 4 | %lu |
long long int 或 long long | 8 | %lld |
unsigned long long int 或unsigned long long | 8 | %llu |
从表中可以看出每种数据类型需要字节数,其中int类型的字节数由不同C语言版本决定。%d代表整型,%u代表无符号整型。字母h表示“短”,字母l表示“长”,双字母ll表示“长长”的。根据不同的类型在%d或%u加中相应字母就可以了。
如果要按八进制输入和输出,则用字母o代替字母d或字母u即可,八进制不分有符号和无符号数,如%ho按短整型八进制输出。如果要按十六进制输入和输出,则用字母x代替字母d或字母u,如%hx表示按八进制短整型输出。
例1:整数输出
# include <stdio.h>
int main(void)
{
printf("%d, %o, %x\n", 10, 10, 10);
printf("%d, %d, %d\n", 10, 010, 0x10);
printf("%d, %x\n", 012, 012);
return 0;
}
程序执行后的结果是:
10, 12, a
10, 8, 16
10, a
第一行分别按十进制、八进制和十六进制输出十进制10,注意到显示的八进制12前没有前缀0,十六进制a也没有前缀0x;第二行全部按十进制分别输出十进制10,八进制010和十六进制0x10,对应的值是10、8和16;第三行是按十进制和十六进制输出八进制012,对应的值分别是10、a。十六进制输出是了解整数的二进制的好方法,把输出的每个十六进制位按1个位转换成4个二制位的方法,可以快速得到整数的二进制表示。以下为十六进制位与二进制转换表:
十六进制 | 二进制 | 十六进制 | 二进制 |
0 | 0000 | 8 | 1000 |
1 | 0001 | 9 | 1001 |
2 | 0010 | A | 1010 |
3 | 0011 | B | 1011 |
4 | 0100 | C | 1100 |
5 | 0101 | D | 1101 |
6 | 0110 | E | 1110 |
7 | 0111 | F | 1111 |
例2:通过十六进制输出以得到整数的二进制。
#include <stdio.h>
int main( )
{
short int a=-65;
short int b=-32768;
printf("%hd=%hx=%hu\n",a,a,a);
printf("%hd=%hx=%hu\n",-1,-1,-1);
printf("%hd=%hx=%hu\n",b,b,b);
return 0;
}
程序的执行结果为:
-65=ffbf=65471
-1=ffff=65535
-32768=8000=32768
我们验证了-1与无符号整数65535是相等的,-32768与无符号整数32768相等。通过查表,我们可以把十六进制展开成二进制。十六进制f对应二进制1111、b对应1011、8对应1000、0对应0000。所以
-65=ffbf = 65471 = 1111 1111 1011 1111
-1=ffff = 65535 = 1111 1111 1111 1111
-32768=8000 = 32768 = 1000 0000 0000 0000
可见一个短整型负数的补码等于无符号整数65536加上此负数。
例3:整数输入与输出
# include <stdio.h>
int main(void)
{
int a, b;
printf("input a, b:");
scanf("%o%d" , &a, &b);
printf("%d-]\n", a, b); /*]指定变量b的输出宽度为5 */
printf("%x-%-5d-\n", a, b);
return 0;
}
程序的输出结果为:
input a, b:17 17
15- 17
f-17 -
前面第一个输入的17对应的是%o,所以是按八进制输入的,所以a的值为八进制数17,或十进制数15。b的值为十进制17。所以第二行显示“15- 17”。两个数中间有多个空格是由格式符“]”的5决定的,表示该项按5格输出,不足5格向右对齐,在左边补空格,这里补了3个空格。第三行显示的是16进制,在17和后面的“-”之间有3个空格,这是由“%-5d”格式符决定的,表示在输出时按5格输出整数,整数向左对齐,不足5格的在右边补空格。即%d的格式可以写成:
%nd 或 %-nd
其中n是常整数,如刚才的5。前者按n格显示整数,且显示时向右对齐,整数位不足n时,左边补空格,整数位数超过n时按原数位输出;后者在n之前多了一个负号,表示整数显示时向右对齐,如果整数位不足,则在左边补空格,整数超过n时按原数位输出。
浮点型数据的输入与输出稍微简单些,对应的格式符如下表:
数据类型 | 长度 | 格式符 |
float | 4 | %f -小数形式 |
double | 8 | %lf -小数形式 |
long double | 8/10/12/16 | %Lf |
long double是长双精度浮点类型,不同的C编译器有不同的长度。double与long double的格式符区别仅是大写字母L和小写字线l。如果要用科学计数法输入或输出,只需要把f改成e即可,即%e、%le或%Le。
以%f输出浮点型数据时,保留6位小数。可以指定小数输出的对齐方式,宽度和小数位数,格式为:
%n.mf 或 %-n.mf
其中,n和m是常整数,n表示浮点数据输出总宽度(占字符数),m表示输出的小数位数,如果原小数位数比m多,则四舍五入,乘余输出的整数位数为n-m-1位。如果原整数位数大于n-m-1,按原整数位输出。不带负号时,表示数据按右对齐,数据小于总宽度,在左边补空格。带负号时,向左对齐,总位数不够时,在右边补空格。如果只想控制小数位数,可以省略n值,如果想按整数输出,则把m设为0。
例4:浮点数的输出
# include <stdio.h>
int main(void)
{
double d = 3.1415926;
printf("%f, %e\n", d, d);
printf("%5.3f,%-5.2f,%.2f\n", d, d, d);
return 0;
}
程序运行后显示;
3.141593, 3.141593e 000
3.142,3.14 ,3.14
输出的第一行第一个数小数点只显示6位,小数第6位是第7位四舍五入的结果,第二个数按科学计数法输出。第二行第一个数保留3位小数点,第3位是第4位四舍五入的结果,第二个数输出两位小数,向右对齐,不足四位在左边补了一个空格,第三个数保留两位小数,不考虑整数部分。
例5:浮点数的输入与输出
#include <stdio.h>
int main(void)
{
float f;
double d;
printf("input f, d:");
scanf("%f%lf", &f, &d);
printf("f = %f\n d = %f \n", f, d);
d = 1234567890123.12;
printf("d = %f \n", d);
return 0;
}
程序输入输出结果是:
input f, d:
1234567890123.123456(回车)
1234567890123.123456(回车)
f = 1234567954432.000000
d = 1234567890123.123500
d = 1234567890123.120100
从显示结果可以看出单精度浮点数f只获得了7位有效精度,即1234567xxxxxx.xxxxxx,其余位都不是精确数据,双精度浮点数d获得了16位有效精度,即1234567890123.123XXX。最后给d赋一个具有15位的小数1234567890123.12,精度能够保持,但是在末位多出了三位不精确数据,即“100”。
最后我们一起看一下字符数据的输入与输出,除了格式化输入输出函数scanf与printf外,还可以使用专门字符输入getchar与输出putchar。
当使用格式化输入与输出函数,无论是有符号还是无符号字符,都使用%c进行输入与输出。如:
char ch;
scanf("%c",&ch);
printf("%c",ch);
当然可以在%与c之间指明宽度或对齐方式,相关解释与整型一致,这里不再赘述。
getchar函数不需要参数,函数返回一个字符,其实是一个短整型数(short int)而不是一个字符类型数据,是为了有关兼容性考虑的设计。putchar函数只需要一个实参,即显示的字符,没有返回值。如:
char ch;
ch=getchar( );
putchar(ch);
由于getchar是从键盘缓冲区中取字符,因此也可能取到如回车符、空格或制表符之类的分隔符。因此在输入字符时要特别注意。
例6:字符型数据输入输出
#include <stdio.h>
int main(void)
{
char ch1, ch2,ch3;
ch1=getchar();
ch2=getchar();
putchar(ch1);
putchar(ch2);
ch3=getchar();
putchar(ch3);
return 0;
}
程序运行后,如果输入ab两个字符再回车,结果是ch1得到a、ch2得到了b、ch3得到了回车。所以只输出了ab程序就结束了。计算机不会等待执行第三个getchar继续输入ch3。解决方法是连续输入abc三个字符再回车,ch1、ch2、ch3分别得到了a、b和c,结果显示abc。
例7:整数与字符混合输入
#include <stdio.h>
int main(void)
{
int x,y;
char ch1;
scanf("%d%c%d",&x,&ch1,&y);
printf("x=%d,ch1=%c,y=%d\n",x,ch1,y);
return 0;
}
程序执行后正确的输入应该是输入第一个数10后不能有空格直接输入c再输入20。否则得不到正确的结果。
10c20
x=10,ch1=c,y=20
第二次执行输入后的情况是:
10 c 20
x=10,ch1= ,y=8
可见,需要输入单个字符时,要注意字符数据输入的特点,否则会影响其它变量取得数据。
本节讲了整型数据、浮点型数据和字符数据输入和输出对应的格式符及方法,提出了通过%x输出以观察变量的二进制的方法和字符输入中容易出现的问题。本节就讲到这里,下一节再见。