目录
一: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,需要的时候,也必须会用