课堂内容
PART A:基本数据类型和输出语句
1.关于scanf的扩展,了解getchar(),缓存区,加深。
引入 :不推荐使用scanf
scanf 的定义
scanf函数的一些陷阱
举例情况:
1.输入 scanf(“%d,%d”,&a&b);
输出结果
A是正常 但是B为”随机数”,原因?
以下,从 MSDN 中节选:
[1] Characters outside format specifications are expected to match the sequenceof characters in the input stream;
就是说,你写的"%d,%d,%d,%d" 中的逗号,被期待在你的输入中出现。
[2] the matching characters in the input stream are scanned but notstored.
就是说,你写的逗号仅仅会被扫描(不会被存储到某个 field 之中)。
[3] If a character in the input stream conflicts with the formatspecification,scanf terminates, and the character is left in the inputstream as if it had not been read.
。重点是,你的输入 "1 2 3 4 ...",和你写的指定格式“%d,%d,%d,%d" 首次发生冲突时,scanf 就会终止。其余字符停留在输入缓冲区中。
因此,你写的代码,在扫描到空格时, a 会被赋值。然后 scanf因为需要扫描到一个逗号,但是输入流缓冲区中当前位置不是逗号,于是 scanf 就结束了。后面的 b,c,d 没有被赋值。
简而言之:bcd都匹配失败了,没有改变,又因为没有初始化,所以是随机数
代码:
#include<stdio.h>
int main()
{
int a ;
int b;
scanf("%d ,%d",&a,&b);
printf("%d %d\n",a,b);
return 0;
}
2.输入scanf(“%d%d”,&a&b);
正常输入结果
代码:
#include<stdio.h>
int main()
{ int a ;
int b;
scanf("%d %d",&a,&b);
printf("%d %d\n",a,b);
return 0;
}
3.在定义变量的同时初始化,也是正常输出,程序如下:
#include<stdio.h>
int main()
{
int a =4 ;
int b=5;
printf("%d %d\n",a,b);
return 0;
}
2.%d换成%c后
#include<stdio.h>
int main()
{
char a ;
char b;
scanf("%c ,%c",&a,&b);
printf("%d %d\n",a,b);
return 0;
}
程序输出正常
(1) scanf格式控制串"%c %c"之间有空格(逗号)时,输入的数据之间可以有空格间隔。这时候我们应该这样输入’a’空格’(逗号)b’。
(2) 空格,回车,跳格等结束符在输入前碰到的话,会自动抛弃,输入后碰到的话,就会认为结束。
(3) 以上是针对除了%c而言的
对于%c,遇到这些字符都会读取的。
Getchar 可以吃回车
如果输入:
scanf(“%c”,&m);
scanf(“%c”,&n);
输入a[回车]b的话
就会使m=a,n=回车
但如果中间加上getchar()
得到m=a,n=b,
所以一般用getchar来吃回车时,是用在%c后面。
那么接下来,关于scanf和getchar以及缓存区的影响,扩展一下。
1. getch getche getchar的区别和缓冲区的概念http://blog.csdn.net/cxyol/article/details/628324
2. c语言学习笔记--chapter0-getchar,scanf以及缓冲区的概念
http://blog.chinaunix.net/uid-20568790-id-1632289.html
2、常量和变量
3、数据类型
4、整型数据
5、字符型数据
6、浮点型数据
7、强制类型转换
PART B
1. if else语句
a. 单分支 (执行这个操作;跳过它)
b. 双分支(两个不同的操做,选择一个来执行)
c. 多分支(多个不懂的操作,选择一个来执行)
d. If else 和 else if
if(条件句)+执行句
else +执行句
end
如果条件句成立,则执行if 后面的执行句。如果不成立,则执行esle后面的句子;
if (条件句1)+执行句
elseif (条件句2)+执行句
else +执行句
end
如果条件句1成立,则执行if后面的执行句,如果条件句1不成立,然后条件句2成立,则执行elseif后面的执行句,如果条件句1和条件句2都不成立,则执行else后面的执行句。
2. switch 语句
switch(表达式 1)---常量表达式
{ case 常量表达式 1: 语句块 1; break;
case 常量表达式 2: 语句块 2; break;
....
default: 语句块: break; }
从表达式值等于某个case语句后的值开始,它下方的所有语句都会一直运行,直到遇到一个break为止。随后,switch语句将结束,程序从switch结束大括号之后的第一个语句继续执行,并忽略其他case。
假如任何一个case语句的值都不等于表达式的值,就运行可选标签default之下的语句。假如表达式的值和任何一个case标签都不匹配,同时没有发现一个default标签,程序会跳过整个switch语句,从它的结束大括号之后的第一个语句继续执行。
PART C
课堂问题:
1. 关于sizeof ()的使用
int main()
{int a = 10;
int n = sizeof(a++);//sizeof(a++)
printf("%d,%d\n",a,n);
return 0;}
程序输出: 10;4
sizeof()函数在预处理的时候就执行了, ()里面的表达式不参与运算
a++ 中,a在定义的时候就是一个整形变量, 在预处理的时候相当于 int n = 4,但是没有执行a 的自增运算,所以输出还是4 ?
2. switch 表达式
switch()//表达式
{case ;}//常量 为什么float,double不可以
选自:https://stackoverflow.com/questions/15572657/why-can-switch-only-compare-to-const-values#
总结如下:
因为在编译时进行类型检查,编译的时候就应该知道值是什么
函数在运行时候才知道返回值,变量运行的时候才知道值是什么,所以不能。
switch(myVar)
{
case(label):
...
break;
}
3. switch 和 if else 区别
switch...case与if...else的根本区别在于,switch...case会生成一个跳转表来指示实际的case分支的地址,而这个跳转表的索引号与switch变量的值是相等的。从而,switch...case不用像if...else那样遍历条件分支直到命中条件,而只需访问对应索引号的表项从而到达定位分支的目的。
具体地说,switch...case会生成一份大小(表项数)为最大case常量+1的跳表,程序首先判断switch变量是否大于最大case 常量,若大于,则跳到default分支处理;否则取得索引号为switch变量大小的跳表项的地址(即跳表的起始地址+表项大小*索引号),程序接着跳到此地址执行,到此完成了分支的跳转。
4. if 和switch那个效率更高 (深入理解计算机系统)
switch有点以空间换时间的意思.
a. 当分支较多时,当时用switch的效率是很高的。因为switch是随机访问的,就是确定了选择值之后直接跳转到那个特定的分支,但是if。。else是遍历所以得可能值,知道找到符合条件的分支。如此看来,switch的效率确实比ifelse要高的多。
b. .由上面的汇编代码可知道,switch...case占用较多的代码空间,因为它要生成跳表,特别是当case常量分布范围很大但实际有效值又比较少的情况,switch...case的空间利用率将变得很低。
c. switch...case只能处理case为常量的情况,对非常量的情况是无能为力的。例如 if (a > 1 && a < 100),是无法使用switch...case来处理的。所以,switch只能是在常量选择分支时比ifelse效率高,但是ifelse能应用于更多的场合,ifelse比较灵活
5. const 和 define的区别
a. define 实在编译预处理时展开
const 常量在编译运行时候使用
b.define宏没有类型,不做类型检查
const常量有类型,编译时会检查
c.宏定义不分配内存,变量定义分配内存
const会在内存中分配(堆或者栈)
6. if 三个分支
错误 .可以嵌套,但是复杂都会增加不如用switch
7. 宏