一:signed / unsigned关键字
在正式了解signed / unsigned关键字之前,我们需要对数据在所开辟内存中到底是如何存储进行一个深入了解。 首先就要了解:
整数的二进制表示有3种表示形式:原码----反码----补码
而内存存储的是二进制的补码!
整数:正数 / 负数
正数:原码反码补码相同
负数:原码:按照一个数的正,负直接写出来的二进制就是原码
反码:符号位不变,其他位按位取反
补码:反码的二进制序列+1,就是补码
符号位为0,正数,为1,负数
15:
00000000000000000000000000001111 ----->原码-反码-补码 最高位为符号位0,正数
-15:
//10000000000000000000000000001111 ----->原码
//11111111111111111111111111110000 ----->反码
//11111111111111111111111111110001 ----->补码
10
00000000000000000000000000001010 原码反码补码相同
4个二进制转化为一个16进制
0 0 0 0 0 0 0 1
-10
10000000000000000000000000001010 原码
11111111111111111111111111110101 反码
11111111111111111111111111110110 补码
4个二进制转化为一个16进制
f f f f f f f 6
为什么内存存储的是二进制的补码呢
计算机只有加法器
如 1+(-1)=0
若采用原码相加:
00000000000000000000000000000001 1的原码
10000000000000000000000000000001 -1的原码
--------------------------------- 相加
10000000000000000000000000000010 ----> -2 err
若采用补码相加:
00000000000000000000000000000001 1的补码
11111111111111111111111111111111 -1的补码
--------------------------------- 相加
100000000000000000000000000000000 ----> 0 right
原码到补码,补码到补码:
1
法一:
10000000000000000000000000000001 原码
取反
11111111111111111111111111111110 反码
加1
11111111111111111111111111111111 补码
减1
11111111111111111111111111111110 反码
取反
10000000000000000000000000000001 原码
法二:
10000000000000000000000000000001 原码
取反
11111111111111111111111111111110 反码
加1
11111111111111111111111111111111 补码
取反
10000000000000000000000000000000
加1
10000000000000000000000000000001 原码
综上所述:
原码取反+1得到补码,补码再取反+1得到原码
正如我们实际定义一个无符号数如下:
#include<stdio.h> int main() { unsigned int b = -10; printf("%d\n", b); // -10 printf("%u\n", b); // 4294967286 return 0; }
解析:
我们在此代码中定义了一个无符号数b=-10的变量,
数据要先存再取,存补码,取原码。
我们都清楚内存存储的是补码
-10
10000000000000000000000000001010 原码
11111111111111111111111111110101 反码
11111111111111111111111111110110 补码
当用%d的形式输出时,此时就将其看成是一个有符号数,将上述补码转换为原码即为-10
当用%u的形式输出时,才是正儿八经的无符号数,而无符号数的最高位就不再是符号位,此时原码反码补码相同,将上述二进制补码转换为十进制就是一个超大的数字4294967286
二:switch关键字
基本语法结构:
switch (整型变量 / 常量 / 整型表达式) { case var1: break; case var2: break; case var3: break; default: break; }
注意:
// // 任何具有判定能力的语法结构,都必须具备:判定+分支
// //case本身是用来判定的
// //break用来进行分支功能
#include<stdio.h> int main() { int day = 0; while (1) { scanf("%d", &day); switch (day) // 整型||整形表达式||常量 { case 1: // case本身是用来判定的 printf("星期1\n"); break; //break用来进行分支功能 case 2: printf("星期2\n"); break; default: printf("请输入正确的数字\n"); break; } }
若要一个case执行多条语句:
可以在其中一条case语句后多输出相关语句
case 3: printf("星期3\n"); printf("星期3\n"); printf("星期3\n"); printf("星期3\n"); printf("星期3\n"); break;
但是,如果我们在case后定义一个变量并且需要访问它时,如下:
不难发现,编译器出错 ,但是当我们在整个case3后面加一个花括号呢
此时编译器是可以正常运行的 ,当然,想要执行上述操作,我们最建议的还是创造函数来解决:
如果想要多条case执行一条语句时:
#include<stdio.h> int main() { int day = 0; while (1) { scanf("%d", &day); switch (day) // 整型||整形表达式 { case 1: case 2: case 3: case 4: case 5: printf("周内\n"); break; case 6: case 7: printf("周末\n"); break; default: printf("请输入正确的数字\n"); break; } } return 0; }
注意:case 后面不能直接跟变量,但可以用宏定义变量即为常变量,default语句的位置可以放在任意位置。
#include<stdio.h> #define A 10 int main() { const int a = 10; switch (a) { //case 10: //case a: err //case 后面不能直接跟变量,但可以用宏定义变量即为常变量 case A: printf("hello bit!\n"); break; default : break; } return 0; }
总结:
1.switch语法结构中,case完成的判定功能,break完成的分支功能,default处理异常情况
2.case:执行语句==1:n,case多条语句(不能定义变量,如果需要,{},函数) break
3.case:执行语句= =n:1,多条case后续不写break
4.default:可以出现在任何地方,推荐放在结尾
5.case:不能:const,普通的变量,建议要有好的布局case的方式
三:break / continue关键字
while
先看一段代码(break)
我们不难发现break的作用就是跳出循环,当把break换成continue时
continue的作用就是结束本次(一次)循环,既然是结束本次循环,所以此时continue跳到while条件判定那进行循环
do while
先看一段伪代码
do { printf("hello\n"); if (flag) { continue; } } while (cond);
在do while中,使用continue,continue会跳到哪呢?
条件判断在哪里,continue就跳转到哪里,所以continue跳转到while(cond)条件判断那
for
再看一段伪代码
在for循环中,使用continue,continue会跳到哪呢?
此时我们不难发现 ,for循环的continue会跳转到条件更新处i++处
总结:
while循环 do while循环用continue都是到条件判定处
for 循环是到条件更新处
四:goto关键字
看代码:
向下跳转:
#include<stdio.h> int main() { goto end; printf("hello 1\n"); printf("hello 2\n"); printf("hello 3\n"); end: // 标签 printf("hello 4\n"); // hello 4 printf("hello 5\n"); // hello 5 printf("hello 6\n"); // hello 6 return 0; }
向上跳转:
#include<stdio.h> int main() { end: // 标签 printf("hello 1\n"); printf("hello 2\n"); printf("hello 3\n"); goto end; printf("hello 4\n"); printf("hello 5\n"); printf("hello 6\n"); // 死循环 // goto语句在代码块中可以跳转 return 0; }
案例:
#include<stdio.h> int main() { int i = 0; start: printf("[%d] goto running...\n", i); i++; if (i < 3) { goto start; } printf("goto end...\n"); return 0; }
goto语句只能在本代码块内使用,不能跨文件和使用函数访问!!!
总结:
//很多公司确实禁止使用goto,不过,这个问题我们还是灵活对待,goto在解决很多问题是有奇效的。
//我们可以认为goto使用场景较少,一般不使用。但是必须得知道goto,需要的时候,也必须会用