目录
介绍
人都有耳朵和嘴巴,能说话和听话逻辑化讲一下就是理解别人的意思和表达自己的意思。所以作为人要和计算机交流的话要说计算机语言也因此计算机语言应该具有交流的能力即耳朵和嘴巴。本篇文章将介绍C语言的耳朵和嘴巴分别是scanf作为它的耳朵吸收别人说的话,printf作为嘴巴把程序执行的最后结果说出来。(形象化的表达一下)
1 printf (让程序会说话)
1.1 printf的定义
printf的详写是print format翻译成中文的话就是格式化输出。因此可以得到printf的作用是将内容格式化输出到屏幕上。printf()函数是<stdio.h>这个头文件中定义的所以要想使用这个函数必须在程序的顶部引入stdio这个头文件。下面举个例子:
#include<stdio.h>
int main() {
printf("happy ");
printf("happy\n");
printf("h\na\np\np\ny\n");
return 0;
}
说明:1、printf打印在屏幕上的内容是不会自动换行的,要换行需要加上\n,另外\n不一定要加在末尾 也可以加在输出的内容中间。2、printf()打印输出文本时为了输出得到的内容更美观可以在文本结束后加上几个空格。
1.2 占位符
占位符的意思是占位符这个位置可以由其他指定的值进行填充。printf()可以有两个参数,第一个参数表示格式化输出文本,第二个参数为要替换占位符的值。可以在格式化输出的语句中引入占位符,用指定的值来替换占位符。
占位符的开头是%,第二个字符决定占位符所表示的类型。
举个例子:
#include<stdio.h>
int main() {
int num = 3;
printf("num = %d", num);
return 0;
}
num=%d是一个输出文本,文本中的%d就是一个可以将整数替换进去的占位符,这个占位符可以由num的值填充。
常用的占位符有%d和%s。其中%s表示替换进去的是一个字符串。
#include<stdio.h>
int main() {
printf("%s are beautiful! ", "you");
return 0;
}
注意:%s带入字符串时替换的字符串需要加上双引号。
情况一:输出文本里使用多个占位符
输出的文本中可以包含多个不同或相同的占位符,输出文本中的占位符与printf中的参数是一一对应的,如果输出文本中含有n个占位符那么printf中的参数就应该有n+1个,如果参数少于占位符数量,剩余的占位符将会被填充为内存中的任意值。
#include<stdio.h>
int main() {
int a = 0;
int b = 1;
int c = 2;
printf("a=%d,b=%d,c=%d,d=%d", a, b, c);
return 0;
}
情况二:误认为char可以表示字符串
#include<stdio.h>
int main() {
char s = "you";
printf("%c are beautiful! ", s);
return 0;
}
我们会发现什么也没有输出,原因是 char类型只能是表示单个的字符,C语言中没有专门表示字符串的数据类型,直接将字符串用双引号引起来就行了。如果想要专门来表示一个字符串可以用C语言中的自定义数据类型--数组,这个在这里就不多阐述了。
情况三:占位符和替换的内容不一致会出现什么结果,请看下面两段代码。
#include<stdio.h>
int main() {
char s = 'you';
printf("%s are beautiful! ", s);
return 0;
}
#include<stdio.h>
int main() {
char s = 'you';
printf("%d are beautiful! ", s);
return 0;
}
说明:第一段代码出现错误的原因是由于要打印的类型和占位符所表示的类型不一样,如果要打印一个字符需要用%c来表示,%s只会寻找字符串,找不到printf()中的参数中包含字符串自然会打印空白行。
而第二段代码为什么会在占位符的地方打印117呢?原因是:变量s的值只有一个‘u’,u对应的值是117,计算机中的所有字符都是以ASCII表中的值存储的,所以如果用%d来做占位符只能是输出字符的ASCII码值,反之如果给字符变量赋值时char=117则打印出来的结果只能是‘u’。另外一点就是如果给一个字符串赋给一个字符变量,字符变量将被初始化成字符串的最后一个字符。对比一下:
#include<stdio.h>
int main() {
char s = 'yot'; //将最后一个字符换成t
printf("%d are beautiful! ", s);
return 0;
}
1.3 占位符的种类
printf()的占位符有很多种类,下面一一列举了常用的占位符,不需要记住,用的时候查找相应的占位符即可。
%a: 十六进制浮点数,字母输出为小写。
%A: 十六进制浮点数,字母输出为大写。
%c: 字符。
%d: 十进制整数。
%e: 使用科学计数法的浮点数,指数部分的e为小写。
%E: 使用科学计数法的浮点数,指数部分的E为大写。
%i: 整数,基本等同于%d。
%f: 小数(包含 float 类型和 double类型) 。
%g: 6个有效数字的浮点数。整数部分一旦超过6位,就会自动转为科学计数法,指数部分的e为小写。
%G: 等同于%g,唯一的区别是指数部分的E为大写。
%hd: 十进制 short int型。
%ho: 八进制 short int型。
%hx: 十六进制 short int类型。
%hu: unsigned short int型。
%ld: 十进制 long int类型。
%lo: 八进制 long int类型。
%lx: 十六进制 long int类型。
%lu: unsigned long int。
%lld: 十进制 long long int类型。
%llo: 八进制 long long int类型。
%llx: 十六进制 long long int型。
%llu: unsigned long long int型。
%Le: 科学计数法表示的long double类型浮点。
%Lf: long double类型浮点。
%n: 已输出的字符串数量。该占位符本身不输出,只将值存储在指定变量之中。
%0: 八进制整数。
%p: 指针。
%s: 字符串。
%u: 无符号整数(unsigned int)。
%x: 十六进制整数。
%zd: size_t类型。
%%: 输出一个百分号。
C语言中常用的占位符(需要记一下)
%d | int类型的整数十进制形式打印 |
%o | int类型的整数八进制形式打印 |
%x | int类型的整数十六进制形式打印 |
%hd | short int类型的整数十进制形式打印 |
%ho | short int类型的整数八进制形式打印 |
%hx | short int类型的整数十六进制形式打印 |
%ld | long int类型的整数十进制形式打印 |
%lo | long int类型的整数八进制形式打印 |
%lx | long int类型的整数十六进制形式打印 |
%u | 打印无符号整数 |
%c | 字符 |
%s | 字符串 |
%f | 浮点数float |
%lf | 浮点数double |
%Lf | 浮点数long double |
%p | 打印地址 |
%zd | 打印size_t类型 |
%% | 打印百分号 |
1.4 限定宽度输出
printf()可以对占位符的输出格式化。printf()可以对占位符的最小宽度进行限定,方法是在%后面加上限定宽度的最小值,比如说%6d表示该占位符的最小宽度是6位。此外printf()也可以指定相应占位符输出是左对齐还是右对齐,占位符的输出默认是右对齐的,如果要左对齐的话需要将%后面加上一个 ‘-’ 号。如下面代码:
#include<stdio.h>
int main() {
int num = 1234;
printf("%6d\n", num); //最小宽度为6位默认是右对齐
printf("%-6d\n", num); //最小宽度是6位,设置为左对齐
return 0;
}
如果超过最小限定宽度也会按原来数字输出。
#include<stdio.h>
int main() {
int num = 1234;
printf("%3d\n", num); //超过最小位数仍按原来的数输出
return 0;
}
当然对于小数来说也会限定小数全部位数(小数点也算一位)的最小值。
#include<stdio.h>
int main() {
float num = 123.45;
printf("%12f\n", num); //小数点也算是一位
printf("%-12f\n", num);
return 0;
}
可以看到这样打印123.45出来却是123.449997,这个问题是C语言中打印小数位数不能精确的原因,来日方长,我会出一篇博文为大家细细分说。如果想打印精确的可以直接在参数中num替换写成123.45 或是将f换成lf。
1.5 限定小数位数
在使用printf()输出小数时可以限定小数的位数,如果想让小数点后面保留x位则可以写成%.xf。另外限定的小数位数可以与限定的最小宽度联合使用。
#include<stdio.h>
//在屏幕上输出“ 123.45”
int main() {
float num = 123.45;
printf("%10.2f\n", num);
return 0;
}
还有一点就是最小宽度和小数位数都可以用*代替,通过printf()的参数传进去。
#include<stdio.h>
//在屏幕上输出“ 123.45”
int main() {
float num = 123.45;
printf("%*.*f\n",10,2,num);
return 0;
}
输出结果和上面的一样。如果指定的小数位数小于实际的小数位数则导致四舍五入。
#include<stdio.h>
int main() {
printf("%*.*f\n",10,1,123.45);
return 0;
}
1.6 输出部分字符串
用%s输出字符串时可以用%.xs表述限定输出字符串的前x个字符。
#include<stdio.h>
int main() {
printf("%.7s\n","hello world");
return 0;
}
限定输出hello world的前七位。
1.7 输出正负号
默认输出一个正数是不带正号的只有输出负数才会带上符号如果想要输出正数时前面有+号需要在%后面加上一个+号。
#include<stdio.h>
int main() {
printf("%+d\n",5);
printf("%+d\n", -5);
return 0;
}
因此,%后面加上+号可以显示任意一个数的正负。
2 scanf(让程序会听话)
scanf函数的作用就是给函数输入值,另外还有可能会见到标准输入和标准输出这两个名词,标准输入(stdin)一般指的就是键盘,标准输出(stdout)一般指屏幕,下面举一个程序说明下问题:
#include<stdio.h>
int main() {
int num = 0;
printf("请输入数值:");
scanf("%d", &num);
printf("num = %d\n", num);
return 0;
}
这段代码先执行标准输出stdout到屏幕上,再执行标准输入stdin,从键盘上输入num的值,最后再执行标准输出stdout将num = 5输出到屏幕上。
还有一个问题是在某些编译器(譬如vs)上使用scanf程序会报错,但scanf是C语言库中有的函数,但是vs上定义须使用scanf_s来代替scanf,但用scanf_s其他的编译器是不认识的,导致代码的移植性不是很好。 (还有一点就是如果硬要使用scanf_s需要先研究一下scanf_s函数的使用语法规则,scanf_s与scanf在使用起来是不一样的)如果想要在vs上使用scanf需要在.c文件的第一行加上#define _CRT_SECURE_NO_WARNINGS 1之后就可以在文件中使用scanf了。每次新建都需要加这一句话略显麻烦了一点,在vs上所有.c和.cpp文件的创建期视都是拷贝自newc++file.cpp这个文件,因此只需在这个文件上附上这句话#define _CRT_SECURE_NO_WARNINGS 1就行了,以后创建的.c文件中会自带这一句代码。
打开文件加上#define _CRT_SECURE_NO_WARNINGS 1这句话保存退出即可。
2.1 scanf的定义
scanf的作用是读取用户从键盘上的输入,用户输入完数据之后,会处理用户的输入将输入存到变量。使用此函数必须要包含头文件<stdio.h>。
scanf中至少要有两个参数,这和printf是不一样的,printf可以只有一个字符串参数。scanf中第一个参数是格式化字符串,里面含有占位符,C语言的数据都是有类型的,因此scanf第一个参数必须首先知道输入的是什么类型才能告诉编译器怎么处理数据。其余的参数就是存放用户输入的变量,有多少个占位符就有多少个变量。
scanf("%d",&num);
第一个参数%d表示告诉编译器输入的是一个整数,第二个参数&num表示从键盘上输入的的值将存放在变量num中。&运算符表示scanf传递的不是而是地址,变量num的地址指向用户输入的值。但是如果这里的变量是指针型的就不用加&了。
当有多个值进行输入时,scanf处理占位符时会自动过滤空格,制表符,换行符 等空白字符。用户的输入先放入缓存中,按下回车键后按照占位符对缓存进行解读,解读时会从上次还没有解读的第一个字符开始,直至解读完缓存或者遇到第一个不符合条件的字符停止。
#include<stdio.h>
int main() {
int a;
float b;
int c;
scanf("%d", &a);
printf("%d\n", a);
scanf("%f", &b);
printf("%d\n", b);
scanf("%d\n", &c);
printf("%d\n", c);
return 0;
}
分析:首先%d会将前面的空格全部跳过,从-开始读取,读走数字9遇到.停下来因为‘.’对于%d来说不是有效字符。第二次调用scanf时就会从‘.’开始继续向后读取,读取‘.’占位符时%f因此第二次会读取到.26e24遇到#时停止,由于内存中的数是不能精确存储的尤其是小数因此会出现一堆的陌生数字,最后第三个scanf跳过#和空格读取最后一个数字0,但内存中的数不能精确存储所以也会打印出一个很不可思议的值。
2.2 占位符
scanf所具有的占位符和printf的占位符基本一样,下面是常用到的占位符。
%c指的是字符
%d指的是整数
%s指的是字符串
%f指的是浮点数
%lf指的是double类型的浮点数
%Lf指的是long double类型的浮点数
1、除了%c以外,其他的占位符都会自动忽略空白字符,但是%c不会忽略空白字符,总是返回第一个字符,无论该字符是否为空格。要想跳过空白字符,可以在%c前面加上一个空格,表示跳过零个或多个空白字符,例如scanf(" %c",&ch)。
2、 另外对于%s不能将它简单的对应成字符串,它读取的规则是从第一个非空白字符开始读起,到第一个空白字符(空格,换行符,制表符)为止。所以%s不会包含空白字符,,无法读取多个单词,但是可以将多个%s连用来解决这一个问题。另外如果在scanf中使用%s进行读取会在字符串末尾加上一个空字符\0。
3、还需要注意的一点是scanf会把字符串读入字符数组,并且不会检测字符串是否超出了字符数组的长度,可能会导致意想不到的结果。因此使用%s占位符是前面加上一个数字%[x]s,x表示读取字符串的最大长度,读不到的字符将被丢弃掉。
#include<stdio.h>
int main() {
char ch[6];
scanf("%5s", &ch);
printf("%s", ch);
return 0;
}
2.3 scanf的返回值
scanf的返回值是一个数值,这个数值表示读取成功的变量的个数,如果一个变量也没有读取或者匹配失败则返回0,如果在成功读取数据之前发生读取错误或者读取到文件尾部则返回EOF有时返回-1。
#include<stdio.h>
int main() {
int x = 1;
int y = 2;
int z = 3;
int count = scanf("%d %d %d", &x, &y, &z);
printf("x=%d y=%d z=%d\n", x, y, z);
printf("%d\n", count);
return 0;
}
另外为了测试程序,可以连续按住ctrl+z来终止代码。下面是输入两次后和什么也不输入按住ctrl+z的效果。
利用这一特性还可以实现多组输入的功能,请看代码:
#include<stdio.h>
int main() {
int num1 = 0;
int num2 = 0;
while (scanf("%d %d", &num1, &num2) == 2) {
printf("%d\n", num1 + num2);
}
return 0;
}
2.4 赋值忽略符
在我们实际的生活之中输入的时候总能遇到一些形式上的问题,比如说在输入日期的时候按照scanf的语法必须输入2024 1 24,中间必须是空格分开,但某些时候我们习惯用2024/1/24来表示日期,这时赋值忽略符就该要登场了。
赋值忽略符是一个 * 只要把 * 加在%号的后面该占位符就不会返回值,在编译器解析后自动删掉。%*c表示该字符处的变量解析时忽略掉,解读之后不需要返回。
#include<stdio.h>
int main() {
int x;
int y;
int z;
scanf("%d%*c%d%*c%d", &x, &y, &z);
printf("%d年%d月%d日\n", x, y, z);
return 0;
}
总结
到此,我们通过这篇文章已经成功让程序会听话和会说话了,好比人这一生会说话和会听话之后就要开始学习一些 后天性比较复杂的知识了。为了叫程序说话和听话花了三天闲暇时间来专注写这篇文章,有什么不合理或者需要改进的地方欢迎指正^_^