1.算术操作符
%/ 2.移位操作符
<<左移操作符
整数的3种二进制 >>右移操作符
1.算术右移2.逻辑右移 3.位操作符
&|^练习
不创建临时变量交换2变量的值异或性质 4.赋值操作符
复合赋值 5.单目操作符
!逻辑反操作-负号&取地址操作符sizeof操作符~按位取反++ / --* 解引用(类型)练习 6.关系操作符7.逻辑操作符
&&||练习总结 8.条件操作符9.逗号表达式10.下标引用,函数调用,结构成员
下标引用操作符[]函数调用操作符()结构成员访问操作数 11.表达式求值
隐式类型转换
整型提升整型提升意义如何提升 算术转换操作符属性
优先级是否控制求值顺序:问题表达式 练习
2.求二进制中1个个数
1.法一2.法二3.法三 2的n次方判断3.求2个数二进制中不同的个数
1.法一2.法二 4.打印整数二进制的奇数位和偶数位5.算术转换6.判断整数奇偶数(多组输入)7.缓冲区问题
法一:法二:法三:
1.算术操作符+ - * / %%
%得到的是余数
取模(余)操作符的两个操作数必须为整数
返回的是整除之后的余数
模0或模负数无意义
10.0 % 3 非法
10 / 3 => 3
除法得到的是商
对于 / 操作符如果两个操作数都为整数则执行整数除法
而只要有一个浮点数那么执行的就是浮点数除法
10 / 3.0 => 3.33333
注意double类型要以%lf格式打印
移位操作符操作数只能是整数
<<左移操作符<< 左边抛弃,右边补0
#includeint main() { int a = 5;//0101 int b = a << 2; //把a在内存中存储的二进制向左移动2位 printf("%dn", b);//20 = 5 * 2 * 2 printf("%dn", a);//5 }
<<只是一种运算,没有改变a的值
<<有*2的效果
打印/使用时 用的是原码的值
整数的3种二进制int a = 5;
5 -十进制
00000000000000000000000000000101 -二进制(32位)
进制只是数值的一种表现形式
原码
反码
补码
正整数->三码相同
//5: 00000000000000000000000000000101 -原码 00000000000000000000000000000101 -反码 00000000000000000000000000000101 -补码
//负整数-> int a = -5; 1000000000000000000000000101 //-原码 1111111111111111111111111010 //-反码 -> 原码符号位不变,其他位按位取反得到反码 1111111111111111111111111011 //-补码 ->反码二进制+1得到补码
整数在内存种存储的是补码!!!
用16进制展示 但内存中是以2进制存储
-1在内存中的存储
到底右移是算术右移还是逻辑右移取决于编译器
常见的编译器下都是算术右移
左边补原来的符号位,右边丢弃
#includeint main() { int a = 5; int b = a >> 1; printf("%dn", b);//2 0010 printf("%dn", a);//5 0101 }
#includeint main() { int a = -5; int b = a >> 1; printf("%dn", b);// -3 printf("%dn", a);// -5 }
VS编译器输出结果为-3 证明采用的是算术右移
左边补0,右边丢弃
注意:
不要写出移动负数位
int b = a >> -2;//标准未定义行为3.位操作符
操作数必须为整数
&//2个都是1才是1,只要有0就是0 00000000000000000000000000000011 00000000000000000000000000000101 //结果: 00000000000000000000000000000001
int main()
{
int a = 3;
int b = -5;
int c = a & b; //补码相与
printf("%dn", c); //3
}
//a b计算时用的都是存在内存中的补码计算 00000000000000000000000000000011 3的补码 10000000000000000000000000000101 11111111111111111111111111111010 11111111111111111111111111111011 -5的补码 //a&b 00000000000000000000000000000011 补码 //正数三码相同,打印的是原码的值|
只要有1就是1,同时为0才是0
int main()
{
int a = 3;
int b = -5;
int c = a | b;
printf("%dn", c); //-5
}
a b计算时用的都是存在内存中的补码计算
00000000000000000000000000000011 3的补码 10000000000000000000000000000101 11111111111111111111111111111010 11111111111111111111111111111011 -5的补码 a | b 11111111111111111111111111111011 补码 打印的是原码 11111111111111111111111111111010 反码 10000000000000000000000000000101 -5
11111111111111111111111111111011 补码
10000000000000000000000000000100
10000000000000000000000000000101 原码
//负数的补码符号位不变,其他位取反,然后再+1就能得到原码
^
相同为0,不同为1
int main()
{
int a = 3;
int b = -5;
int c = a | b;
printf("%dn", c); //-8
}
a b计算时用的都是存在内存中的补码计算 00000000000000000000000000000011 3的补码 10000000000000000000000000000101 11111111111111111111111111111010 11111111111111111111111111111011 -5的补码 a^b 11111111111111111111111111111000 补码 11111111111111111111111111110111 反码 10000000000000000000000000001000 原码 -8练习 不创建临时变量交换2变量的值
int main()
{
int a = 3;
int b = 5;
printf("a=%d b=%dn", a, b);
a = a + b;
b = a - b;
a = a - b; //此时a里面是a+b b里面是a
printf("a=%d b=%dn", a, b);
return 0;
}
缺点:数值太大可能会溢出 毕竟只有32位
3^3 = 0
0^5 = 5
#include异或性质int main() { int a = 3; int b = 5; printf("a = %d b = %dn", a, b); a = a^b; b = a^b; //此时a^b^b 结果为a a = a^b;// b中存着的是a a^b^a 结果为b printf("a = %d b = %dn", a, b); return 0; }
1交换律 A ^ B = B ^ A
2结合律( A ^ B ) ^ C = A ^ ( B ^ C )
3自反性: A ^ B ^ B = A
如果交换2个浮点数呢?
位操作符只能操作整数
交换浮点数只能借助第三个变量了
=
a = x = y+1; //连续赋值 //不推荐这么写,调试起来不方便
左值 是可以放在等号左边的,一般是一块空间
右值 是可以放在等号右边的,一般是一个值,或者一块空间内容
+= -= *= /= %= >>= <<= &= |= ^=5.单目操作符
3+5
+是双目操作符
3是左操作数
5是右操作数
单目操作符 只有一个操作数
? : 三目操作符
!逻辑反操作#include-负号int main() { int flag = 0; if (!flag) { printf("hehen"); } } return 0;
#includeint main() { int flag = 1; int i = 0; for (i = 0; i < 10; i++) { printf("%d ", i * flag);//0 -1 2 -3 4 -5 6 -7 8 -9 flag = -flag; } return 0; }
绝对值函数:
abs -对整数求绝对值
fabs -对小数求绝对值
求变量(类型)所占空间的大小,单位是字节
printf("%dn",sizeof a);
这样写也对,证明了sizeof不是函数
sizeof int 这样写不对
sizeof(int)才行
尽量加上(),写代码要让别人看得懂
对一个数二进制位按位取反,是对内存中补码进行操作
但打印时按原码进行打印
#includeint main() { int a = -1; int b = ~a; //10000000000000000000000000000001 原码 //11111111111111111111111111111110 反码 //11111111111111111111111111111111 补码 printf("%dn", a);//-1 printf("%dn", b);//0 return 0; }
00000000000000000000000000000000 补码 三码相同 原码也是 00000000000000000000000000000000 int a = 10; 00000000000000000000000000001010 10 00000000000000000000000000000100 按位或 1<<2 00000000000000000000000000001110 a |= (1<<2) 就能把指定位变为1 变回来? 00000000000000000000000000000100 00000000000000000000000000001110 按位与 11111111111111111111111111111011 ~(1 << 2) 就能得到原来的 00000000000000000000000000001010 a &= ~(1 << 2);++ / –
i++ 先用了再加
++i 先加了再用
#includeint main() { int a = 10; //int b = ++a; //printf("a = %d b = %dn", a, b);//11 11 //int b = a++; //先使用,先把a的值赋给b,a再自增 //printf("a = %d b = %dn", a, b);//11 10 printf("%dn", a++);//10 先使用 a再加一 此时a是11了 printf("%dn", ++a);//12 a=11 先+1 再使用 printf("%dn", a--);//12 然后a-1变成11 printf("%dn", a--);//11 先使用a 然后再-1 return 0; }
#includeint main() { int a = 1; int b = (++a) + (++a) + (++a); printf("%dn", b);//12 printf("%dn", a); //4 return 0; }
VS2019的环境下结果是12 4
gcc环境下结果是10 4
这是错误的代码
3个4相加
解引用操作符/间接访问操作符
#include(类型)int main() { int a = 10; int* pa = &a; *pa = 20; printf("%dn", a);//20 return 0; } //*pa = 20;通过a的地址找到a,并改变其值
强制类型转换
#includeint main() { int a = 3.14; //int a = (int)3.14; printf("%dn", a); return 0; }
会报警告:
C4244“初始化”: 从“double”转换到“int”,可能丢失数据
(int*) p = &a;//err
不要写成这样,编译器会认为是强制类型转换
#includeint main() { int a = -10; int *p = NULL; printf("%dn", !2); //0 printf("%dn", !0); //1 a = -a; //10 p = &a; printf("%dn", sizeof(a)); //4 printf("%dn", sizeof(int)); //4 printf("%dn", sizeof a);//这样写行不行? 行 printf("%dn", sizeof int);//这样写行不行? 不行 return 0; }
计算变量大小,括号可以省略
但计算类型大小,括号不能省略
#includevoid test1(int arr[]) //此处int arr[]本质是 int* arr { printf("%dn", sizeof(arr));//4 } void test2(char ch[]) { printf("%dn", sizeof(ch));//4 指针大小 } int main() { int arr[10] = { 0 }; char ch[10] = { 0 }; printf("%dn", sizeof(arr)); //40 printf("%dn", sizeof(ch)); //10 printf("%dn", sizeof(int[10])); //40 test1(arr); //4 test2(ch); //4 return 0; }
sizeof(arr) 计算的是整个数组大小
sizeof内部单独放数组名,此时数组名表示整个数组
test1(arr) 数组传参,本质传的是指针,传过去的是首元素地址
指针大小是4/8个字节,与平台有关
= < <= != //用于测试“不相等” == //用于测试“相等”
注意不要把判断相等写成 =
if(a = 5)…
最好写成if(5 == a)…
老司机写法
逻辑操作符只关注变量的真假
位操作符是针对二进制位的
#include||int main() { int age = 0; scanf("%d", &age); if (age > 0 && age < 18) { printf("未成年n"); } //不要写成if(0 return 0; }
#include练习int main() { int month = 0; scanf("%d", &month); if (month < 1 || month > 12) { printf("输入错误n"); } else { } return 0; }
int main()
{
int i = 0,a = 0,b = 2,c = 3,d = 4;
i = a++ && ++b && d++;
//i = a++||++b||d++;
printf("a = %dn b = %dn c = %dnd = %dn", a, b, c, d);
return 0; }
//程序输出的结果是什么?
1 2 3 4
张三&&李四下课到办公室
张三李四都要来
左边为假时,后面就不执行了
后置++先使用a = 0再++
0 && …
有一个为假,后面没必要再算了
整体都为假了
int main()
{
int i = 0,a = 1,b = 2,c = 3,d = 4;
i = a++ && ++b && d++;
//i = a++||++b||d++;
printf("a = %dn b = %dn c = %dnd = %dn", a, b, c, d);
return 0; }
//程序输出的结果是什么?
2 3 3 5
a = 1时 都为真了,后面需要计算
&&操作符只关注真假
int main()
{
int i = 0,a = 1,b = 2,c = 3,d = 4;
//i = a++ && ++b && d++;
i = a++||++b||d++;
printf("a = %dn b = %dn c = %dnd = %dn", a, b, c, d);
return 0; }
//程序输出的结果是什么?
2 2 3 4
a++ 表达式值为1 a变为2
a++ 表达式为真,后面就不用算了
|| 左操作数为真,后面不用算
&& 左操作数为假,后面不用算
exp1 ? exp2 : exp3
也叫三目操作符
if (a > 5)
b = 3;
else
b = -3;
转换成条件表达式,是什么样?
b = (a > 5 ? 3 : -3);
最好加个()便于理解,不加也是对的
#include9.逗号表达式int main() { int a = 10; int b = 20; int max = a > b ? a : b; int min = a > b ? b : a; return 0; }
逗号表达式,从左向右依次执行
整个表达式的结果是最后一个表达式的结果
#includeint main() { int a = 3; int b = 5; int c = 6; int d = (a += 2, b = a - c, c = a + 2 * b); printf("%dn", d);//3 a=5,b=-1,c=5-2=3 return 0; }
必须从左向右依次计算,不能只算最后一个表达式
int a = 1; int b = 2; int c = (a>b, a=b+10, a, b=a+1);//逗号表达式 c是多少? 13
a = get_val();
count_val(a);
while (a > 0)
{
//业务处理
a = get_val();
count_val(a);
}
如果使用逗号表达式,改写:
while (a = get_val(), count_val(a), a>0)
{
//业务处理
}
10.下标引用,函数调用,结构成员
下标引用操作符[]
操作数:一个数组名 + 一个索引值
arr[7]
[]是下标引用操作符
[]的2个操作数为arr和7
编译器是把arr[7] --> * (arr+7) 处理成这样才进行计算,找到第8个元素,编译器依旧以指针的形式进行相应的计算
arr[7] --> * (arr+7) --> * (7+arr) --> 7[arr]
#include函数调用操作符()int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; printf("%dn", 7[arr]);//8 printf("%dn", arr[7]);//8 return 0; //说明[]只是个操作符而已 }
接受一个或者多个操作数:
第一个操作数是函数名,剩余的操作数就是传递给函数的参数
#include结构成员访问操作数void test1() { printf("hehen"); } void test2(const char *str) { printf("%sn", str); } int main() { test1(); //()作为函数调用操作符。 test2("hello bit.");//()作为函数调用操作符。 return 0; }
.
->
#include11.表达式求值struct Stu { char name[20]; int age; double score; }; int main() { struct Stu s = {"zhangsan", 20, 85.5}; //. printf("%s %d %.1lfn", s.name, s.age, s.score);//结构体变量.结构体成员 //-> struct Stu *ps = &s;//结构体指针 //printf("%s %d %.1lfn", (*ps).name, (*ps).age, (*ps).score); printf("%s %d %.1lfn", ps->name, ps->age, ps->score);//结构体指针->结构体成员 return 0; }
操作符优先级,结合性+类型转换
隐式类型转换 整型提升C的整型算术运算总是至少以缺省整型类型的精度来进行的
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升
整型提升是按照变量的数据类型的符号位来提升的
#includeint main() { char a = 5; char b = 126; char c = a + b;//均为char类型 printf("%dn", c);//结果为什么是-125? return 0; }
sizeof(char),sizeof(short)均小于sizeof(int)
char a = 5; //截断 00000000000000000000000000000101 00000101 //a里面只能存8位 低八位 char b = 126; 00000000000000000000000001111110 01111110 00000000000000000000000000000101 - a整型提升完的结果 00000000000000000000000001111110 - b整型提升完的结果 00000000000000000000000010000011 10000011 - c 当a和b相加的时候,a和b都是char类型 表达式计算时就要发生整形提升 char c = a + b; 10000011 - c 11111111111111111111111110000011 - 补码 10000000000000000000000001111100 - 反码 取反再+1就行 10000000000000000000000001111101 -> -125 原码
以%d格式打印的时候是打印原码的值,char型还需要整型提升
整型提升意义表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。
所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。
CPU计算的是整型,char,short型计算前要转化为整型
如何提升整形提升是按照变量的数据类型的符号位来提升的
//负数的整形提升
char c1 = -1;
变量c1的二进制位(补码)中只有8个比特位:
1111111
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为1
提升之后的结果是:
11111111111111111111111111111111
//正数的整形提升
char c2 = 1;
变量c2的二进制位(补码)中只有8个比特位:
00000001
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为0
提升之后的结果是:
00000000000000000000000000000001
//无符号整形提升,高位补0
int main()
{
char a = 0xb6;
short b = 0xb600;
int c = 0xb6000000;
if(a==0xb6)
printf("a");
if(b==0xb600)
printf("b");
if(c==0xb6000000)
printf("c");
return 0;
}
最终只打印c
a,b会发生整型提升,值发生了变化
int main()
{
char c = 1;
printf("%un", sizeof(c)); //1
printf("%un", sizeof(+c));//4
printf("%un", sizeof(-c));//4
return 0;
}
c只要参与表达式运算,就会发生整形提升,表达式 +c ,就会发生提升
sizeof()内部表达式没有真正进行运算,即不知道表达式结果,但是我们知道的是表达式结果的类型
知道类型属性
int main()
{
int a = 10;
int b = 20;
a + b;//表达式有2个属性:值属性,类型属性
30 就是值属性
int 类型属性
return 0;
}
类型属性不需要计算也知道
int main()
{
short s = 20;
int a = 5;
printf("%dn", sizeof(s = a + 4));//2
//计算的是sizeof(short)
printf("%dn", s);//20
return 0;
}
a+4是int类型
a+4的结果放到short里面,是short说了算
sizeof()内部表达式没有真正进行运算
sizeof在编译期间就进行了计算,也就是说
在编译期间,sizeof(s = a + 4) 已经变成了2了
运行期间自然没有什么s = a + 4了
long double
double
float
unsigned long int
long int
unsigned int
int
从下往上进行转换
int main()
{
int a = 3;
float f = 5.5;
float r = a + f;//算术转换
return 0;
}
操作符属性
表达式求值三个影响因素
1.操作符优先级
2.操作符结合性
3.是否控制求值顺序
两个相邻的操作符先执行哪个?
取决于他们的优先级。
如果两者的优先级相同,取决于他们的结合性。
&&
左边为假右边就不用算了
||
左边为真右边也不用算了
,逗号表达式
?:条件操作符
有了这些,也没办法确定某些表达式的唯一解
只能保证的*计算比+早, 但是优先级并不能决定第三个+比第一个+早执行 把abcdef看成互相影响的表达式,那么代码的逻辑是会出错的 除非明确加上()
//表达式2 int c = 5; 5 + 4 = 9 4 + 4 = 8 c + --c;//问题代码
左右操作数有关联的,不能确定谁先准备好了
这也是有问题的
int main()
{
int i = 10;
i = i-- - --i * ( i = -3 ) * i++ + ++i;
printf("i = %dn", i);
return 0;
}
非法表达式,在不同的编译器结果不一样,编译器也已经凌乱了
#include练习int main() { int i = 1; int ret = (++i) + (++i) + (++i); printf("%dn", ret); printf("%dn", i); return 0; }
1.优先级
#includeint main() { int a, b, c; a = 5; c = ++a;//c=6 a=6 b = ++c, c++, ++a, a++; //b=7 c=8 a=8 b += a++ + c; //+的优先级比+=高 //b=23 a=9 c=8 printf("a = %d b = %d c = %dn:", a, b, c); return 0; }
b = ++c, c++, ++a, a++;
b=++c 优先级比逗号要高,先算
b=++c 和后边的构成逗号表达式,依次从左向右计算的
#includeint main() { int a, b, c; a = 5; c = ++a;// ++a:加给a+1,结果为6,用加完之后的结果给c赋值,因此:a = 6 c = 6 b = ++c, c++, ++a, a++; // 逗号表达式的优先级,最低,这里先算b=++c, b得到的是++c后的结果,b是7 // b=++c 和后边的构成逗号表达式,依次从左向右计算的。 // 表达式结束时,c++和,++a,a++会给a+2,给c加1,此时c:8,a:8,b:7 b += a++ + c; // a先和c加,结果为16,在加上b的值7,比的结果为23,最后给a加1,a的值为9 printf("a = %d b = %d c = %dn:", a, b, c); // a:9, b:23, c:8 return 0; }
+= 的优先级 比+优先级低
2.求二进制中1个个数 1.法一n=15 00000000000000000000000000001111 15 % 2 = 1 15 / 2 = 7 00000000000000000000000000000111
类似是获取1234每一位的值
%10/10得到十进制每一位
%2/2得到二进制每一位
#includeint count_number_of_1(int n) { int count = 0; //只要2进制里有1就不可能是0 while (n) { if (n % 2 == 1) { count++; } n /= 2; } return count; } int main() { int n = 15;//n放在内存中补码的2进制中1的个数 int ret = count_number_of_1(n); printf("%dn", ret);//4 return 0; }
缺点:只适用正数
//如果测试-1呢? 10000000000000000000000000000001 原码 11111111111111111111111111111110 反码 11111111111111111111111111111111 补码
-1 % 2 = -1 不满足n%2 == 1的条件
商0余-1
改进:
形参写成unsigned int 就行了
无符号整型所有的位都是有效位
#includeint count_number_of_1(int n) { int count = 0; //只要2进制里有1就不可能是0 for (int i = 0; i < 32; i++) { if ((n & 1) == 1) { count++; } n >>= 1; } return count; } int main() { int n = -1;//n放在内存中补码的2进制中1的个数 int ret = count_number_of_1(n); printf("%dn", ret);//32 return 0; }
优化:
int NumberOf1(int n ) {
// write code here
int count = 0;
for(int i = 0; i < 32; i++)
{
if(n & (1<
都得循环32次
3.法三
n = 15
n = n&(n-1)
00001111
&
00001110
00001110
00001110
&
00001101
00001100
...
每一次&都少了个1
n = n&(n-1)这个表达式会把n的二进制序列中最右边的1去掉
#include
int count_number_of_1(int n)
{
int count = 0;
while (n)
{
n &= n - 1;
count++;
}
return count;
}
int main()
{
int n = -1;//n放在内存中补码的2进制中1的个数
int ret = count_number_of_1(n);
printf("%dn", ret);//32
return 0;
}
优点:有几个1就循环几次,不会浪费
2的n次方判断
一个数二进制只有1个1代表它是2的k次方
n = 8时
00001000
&
00000111
00000000
可以借此判断一个数是否是2^k次方
if((n & n-1) == 0) ....则n就是2的k次方
3.求2个数二进制中不同的个数
1.法一
循环32次,把每一位都拿下来比较
#include
int count_diff_bit(int m, int n)
{
int count = 0;
for (int i = 0; i < 32; i++)
{
if ((m & 1) != (n & 1))
{
count++;
}
m >>= 1;
n >>= 1;
}
return count;
}
int main()
{
int n = 1999;
int m = 2299;
int ret = count_diff_bit(m, n);
printf("%dn", ret);//7
return 0;
}
2.法二
先将m和n进行按位异或,此时m和n相同的二进制比特位清零,不同的二进制比特位为1统计异或完成后结果的二进制比特位中有多少个1即可
#include
int count_diff_bit(int m, int n)
{
int count = 0;
int tmp = m ^ n;
while (tmp)
{
tmp &= tmp - 1;
count++;
}
return count;
}
int main()
{
int n = 1999;
int m = 2299;
int ret = count_diff_bit(m, n);
printf("%dn", ret);//7
return 0;
}
4.打印整数二进制的奇数位和偶数位
不写函数返回类型,默认返回int
没有返回值要写void
如果不写return,会把最后一条指令执行结果返回过去
#include
void print(int m)
{
//00000000000000000000000000000101
//打印奇数位
int i = 0;
for (i = 30; i >= 0; i -= 2)//第1位右移0位,第31位右移30位
{
printf("%d ", (m >> i) & 1);
}
printf("n");
//打印偶数位
for (i = 31; i >= 1; i -= 2)//第2位右移1位,第32位右移31位
{
printf("%d ", (m >> i) & 1);
}
}
int main()
{
int m = 0;
scanf("%d", &m);
print(m);
return 0;
}
5.算术转换
下面代码结果?
#include
int i;//全局变量,默认为0
int main()
{
i--;
if (i > sizeof(i))
{
printf(">n");
}
else
{
printf("
结果为>
sizeof操作符计算的结果的类型是size_t 无符号整型
i > sizeof(i)
int > unsigned int
int会进行算术转换,提升为unsigned
10000000000000000000000000000001
11111111111111111111111111111110
11111111111111111111111111111111 补码
//4个字节放的是有符号数,打印的是原码的值 -1
如果认为内存中放的是无符号数,三码相同
所有的2进制位都是有效位
//32个1表示4294967295
6.判断整数奇偶数(多组输入)
scanf在读取失败时会返回EOF
end of file文件结束标志
EOF本质是-1
-1补码32个全1
11111111111111111111111111111111
~(-1)
00000000000000000000000000000000
while (~scanf("%d", &n))也是对的
#include
int main()
{
int n = 0;
while (scanf("%d", &n) != EOF)
//scanf读取失败返回EOF
{
if (n % 2 == 0)
{
printf("Evenn");
}
else
{
printf("Oddn");
}
}
return 0;
}
7.缓冲区问题
法一:
用数组把要判断的字母存起来
scanf读取字符,从缓冲区中获取
键盘敲下a时还附带了一个n
scanf获取了a,缓冲区还剩下n
n干扰了判断,得清理缓冲区
#include
int main()
{
char v[] = "AaEeIiOoUu";
char ch = 0;
int i = 0;
while(scanf("%c",&ch) != EOF)
{
for(i = 0; i < 10; i++)
{
if(ch == v[i])
{
printf("Voweln");
break;
}
}
if(i==10)
{
printf("Consonantn");//辅音
}
//清理缓冲区
getchar();//清理n
}
return 0;
}
法二:
while(scanf("%cn",&ch) != EOF)
%c拿走字符时会把缓冲区中的n也顺便拿走
法三:
%c前面加上空格,会跳过空白字符
n属于空白字符,会被跳过
while(scanf(" %c",&ch) != EOF)



