函数
代码的打包
函数的语法
1) void func() { ... }
2) void func(int min, int max) { ... }
3) int func() { ... }
4) int func(int min, int max) { ... }
函数的一个调用
func();
int num = func();
return
1) 无返回值函数 遇到 return 结束函数
2) 有返回值函数 结束函数, 同时将值返回
int func() {
return 10;
}
int func() {
return (10);
}
函数的嵌套使用
在函数 func1 中调用函数 func2
那么可以利用 func1 去调用 func2
同时可以利用 func1 实现对 func2 函数的补充
7, 递归函数
1) 找到递推关系 -> 得到递归体
2) 找到临界条件 -> 跳出递归
*/
----------------------------------------------------------------------------------------------------
// 数位
// 基数
// 权值
// 111
// 需要指明某一个数字在第几位上(从右往左,从 0 开始数)
// 基数是指组成这个进制数字的所有的数字符号
// 10进制: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
// 8: 0, 1, 2, 3, 4, 5, 6, 7
// 2: 0, 1
// 16: 0, 1, 2, 3 ,4 ,5 ,6 ,7, 8, 9, a, b, c, d, e, f
// 所谓的进制只是计数的方式
// 10: 10
// 2: 1010
// 16: 0xa
// 8: 012
// 权值,表示这个 数码 * 基数个数 ^ 数位
// 123
// 1 * 10^2 100
// 2 * 10^1 20
// 3 * 10^0 3
----------------------------------------------------------------------------------------------------
// 十进制的表示就是与平常书写一样
int num1 = 123;
// 八进制的表示是使用 数字0 和一个数字表示,这个数字就是八进制的
int num2 = 07; // => 7
int num3 = 011; // => 9
// printf("%d\n%d\n", num2, num3);
// 十六进制表示使用 0x 开头,然后紧跟一个十六进制数字
int num4 = 0x9; // => 9
int num5 = 0x11; // => 17;
int num6 = 0xc; // => 12;
// printf("%d\n%d\n%d\n", num4, num5, num6);
// 二进制的表示使用 0b 开头,然后跟上一个二进制数字
int num7 = 0b11111111; // 255
char ch = 0b11111111; // ? -128 -1
---------------------------------------进制 转换-------------------------------------------------------------
// 二进制数转八进制数
// 1) 将二进制数从右往左三个分组,左边不够的补零
// 2) 查表,将每组的二进制数表示成八进制数
// 3) 从左往右取八进制数即可
int num1 = 0b1111000000001111;
// (001)(111)(000)(000)(001)(111)
// 1 7 0 0 1 7
// 0170017
// 八进制转二进制
// 1) 每一个八进制数都查表转换成二进制数即可
// 2) 不要写错
int num2 = 0123;
// 123
// (001)(010)(011)
// 0101 0011
// 二进制转十六进制
// 1) 将二进制数从右往左四个分组,左边不够的补零
// 2) 查表,将每组的二进制数表示成十六进制数
// 3) 从左往右取十六进制数即可
int num3 = 0b1111000000001111;
// (1111)(0000)(0000)(1111)
// 0xf00f
// (1111)(0000)(0011)(1111)
// f 0 3 f
// 0xf03f
// 十六进制转二进制
// 每一个十六进制数都转换成4个二进制数
int num4 = 0x123;
// 0001 0010 0011
for (int i = 0; i < 16; i++) {
printf("%d\t%o\t%x\n", i ,i, i);
}
----------------------------------------------------------------------------------------------------
// 二进制转十进制
// 按权展开
// 123 = 100 + 20 + 3
// 11011011
// 2^7 + 2^6 + 2^4 + 2^3 + 2^1 + 2^0
// 128 + 64 + 16 + 8 + 2 + 1
// 219
// 推导出一个结论,任意进制的数据,转换成 10 进制数,都是按权展开
// 0x123
// 1*16^2 + 2*16^1 + 3
// 256 + 32 + 3
// 291
// 十进制数转二进制数
// 除以2倒取余数法
// 12 -> 二进制
// 133 -> 1000 0101
// 基数 原数
// 基数 试商 余数
// 基数 试商 余数
// 基数 试商 余数
// 0
// 133 -> 十六进制
// 得到一个结论:十进制数转换成其他进制数,只需要除以基数个数倒取余数法即可
// 2, 8, 10, 16
// 2,8 三合一查表
// 2,16 四合一查表
// 2,10 按权展开
// 8,10 按权展开
// 8,16 先二后十六
// 10,16 除以16倒取余数
// 8,2 一拆三
// 16,2 一拆四
// 10,2 除以2倒取余数
// 10,8 除以8倒取余数
// 16,10 按权展开
----------------------------------------------------------------------------------------------------
// 机器码与真值
// 什么是真值, 就是我们刚刚计算的进制数
// 在计算机中表示一个数字: 1, -1, 0
// 转换成二进制: 1, 0, -1?
// 二进制数从左往右数的第0为表示符号位,如果符号为0表示正数,如果符号为1表示负数
// 1 -> 0000 0001
// 0 -> 0000 0000
// -1 -> 1000 0001
// 真值就是最高位表示符号位,将数字以二进制表示的数据显示结果
// 数据的真值可以说是一个理论值,而计算机硬件中不会这么表示
// 计算机硬件中表示数据的方式称为机器值,或机器码
// 一般也将真值叫做原码
// 计算机中存储的是数据的补码
原码就是数字理论计算的值
最高位为符号位, 数字以二进制表示
反码是为了计算补码而提出来的
反码就是原码除了最高位符号位以外,所有位上的数据01互换
原码:1001001
反码:1110110
补码是计算机中数据的真实表示结果
正数的补码与原码相同
负数的补码是反码 + 1
数字:-3
原码: 1000 0011
反码: 1111 1100
补码: 1111 1101
1111 1101 + 1 => 1111 1110 + 1 => 1111 1111 + 1 = 0000 0000
给你一个数字,你要会算出原码,反码和补码
-123
原码: 1111 1011
反码: 1000 0100
补码: 1000 0101
----------------------------------------------------------------------------------------------------
在函数中,声明的局部变量,存储在栈内存中
1)函数中的变量,默认的存储形式是从高地址向低地址存储
2)内存会因为计算机的结构会对杂乱的内存进行优化(内存的分配不再一般化)
3)数据存储大端对齐与小端对齐概念
// 写一个数字:
// 十进制: 1234
// 二进制: 110110
// 左边是大数,右边是小数
// 内存结构(内存可以看做是从 0 开始编号的一(串)列盒子)
// 这里每一个盒子都可以放置一个二进制位
// 小 大
// [][][1][1][0][1][1][0][][][][][][][][]
// [][][0][1][1][0][1][1][][][][][][][][]
// 打印变量的地址,使用 &变量名 获得变量的地址, 使用 %p 打印地址
// 一个int类型的数据,占 4 个字节
// &获得的地址是哪一个?
// 获得的是首地址(低地址)
// 在C语言中支持指针数据类型,用来表示内存的地址
// 使用指针类型的变量,有一个算术运算需要注意
// p = 0x12345678; (伪代码)
// 指针变量 + 1 实际含义是指针的地址按照类型进行偏移
// p(char) p+1 => 0x12345679
// p(int) p+1 => 0x1234567c
// 有一个运算符 * 叫做取值运算符(寻址运算符)
// 可以得到地址所表示的值
// *p 将p表示的这个地址中的数据,按照p的数据类型读取出来
// p 地址指向一个内存 内存中存储的是 97
// p(char) *p 'a'
// p(int) *p 97
*/
-------------------------------位运算---------------------------------------------------------------------
位运算,都是将变量的数据取出来运算,得到一个新的数据,不会修改原来的数据
void _0按位与() {
// 按位与
// &
/*
0 & 0 == 0
1 & 0 == 0
0 & 1 == 0
1 & 1 == 1
*/
int num1 = 2;
int num2 = 3;
int res1 = num1 & num2;
// 0000 0010
// 0000 0011
// 按位与就是将每一个二进制位上的数据进行运算
// 0000 0010
printf("%d\n", res1);
// num & 0001 0000 == 0001 0000 0000 0000
// 使用按位与运算,可以得到某个数字的某一个二进制位上的值
}
void _0按位或() {
/*
按位或就是将每一个二进制位上的数据进行或运算
0 | 0 == 0
1 | 1 == 1
1 | 0 == 1
0 | 1 == 1
*/
int num1 = 2;
int num2 = 3;
// 0000 0010
// 0000 0011
// =>
// 0000 0011
printf("%d\n", num1 | num2);
}
void _0按位异或() {
/*
按位异或
^ 如果某一位上的两个数字是相同的,那么值为0,如果不同则为1
1 ^ 1 == 0
0 ^ 0 == 0
1 ^ 0 == 1
0 ^ 1 == 1
*/
int num1 = 2;
int num2 = 3;
// 0000 0010
// 0000 0011
// 0000 0001
printf("%d\n", num1 ^ num2);
}
void _0按位取反() {
printf("%d\n", ~1);
// -2
// 1000 000...0000 0010
// 1111 111...1111 1101
// 1111 111...1111 1110
// 1
// 0000 0000 ... 0000 0001
}
void _0左移与右移() {
/*
<< 左移运算符
二进制位上数字,每一个向左边移动n个二进制位
*/
// int num1 = 2;
// // 0000 0010
// // int num2 = num1 << 1; // num1 * 2^1 // << 3 num1 * 2^3
// //
// for(int i = 0; i < 10; i++) {
// printf("%d\n", num1 << i);
// }
/*
右移运算符,是将每一个二进制位的数字向右边移动n位
*不同的平台实现不一样
*下面只介绍苹果的平台
右移以后超出的数据丢失,左边补符号位
1000 0010
1100 0001
0100 0001
*/
}
------------------------------------偶数----------------------------------------------------------------
int num = 2;
// 计算 num * 8;
// printf("%d\n", num * 8);
// printf("%d\n", num << 3); // 推荐使用这个方法
// 2 10
// 4 100
// 6 110
// 8 1000
// 判断一个数字是否为偶数
// num & 1 != 1
while(1) {
int num1 ;
scanf("%d", &num1);
if((num1 & 1) == 1) {
printf("是奇数\n");
} else {
printf("是偶数\n");
}
}
----------------------------------------------------------------------------------------------------
void test() {
// int num = 123;
// 第0位: num & 1
// 100101010010101000
// 000000000000000001
// 000000000000000000 => 0 1
// 第1位: num & 2 == 2 0
// (num & 2)) != 0 就是1
// (num & (1 << 31)) >> 31
// for(int i= 0; i< 31; i++) {
// if(i % 4 == 0) printf(" ");
// // printf("%d", (num & (1 << i)) >> i);
// printf("%d", (num & (1 << i)) == 0 ? 0 : 1 );
// }
// printf("\n");
// 数字: 1001 1001
// (num >> 7) & 1 => 最高位的结果
// (num >> 6) & 1 =>
// ...
// (num >> 0) & 1 => 第0位的结果
}
void test1() {
// 打印一个数字的二进制数,就是要获得每一个二进制位的 0 还是 1
// 123
// 000... 0000 0111 1011
// 得到第0位
// 000... 0000 0111 1011 & 1 ==> 1
// 1 << 0
// 得到第1位
// 000... 0000 0111 1011 & 10 ==> 0000...00 0010 ==> 10 ---> 10 >> 1 == 1
// 1 << 1
// 得到第2位
// 000... 0000 0111 1011 & 100 ==> 0 == 0>>2 == 0
// 1 << 2
// 得到第3位
// 000... 0000 0111 1011 & 1000 ==> 1000 ----> 1000 >> 3 == 1
// 1 << 3
// 获得 32 个位
// 0 -> 31
// 值 == 0 ? 0 : 1
// 值 >> 次数位
// (num & (1 << i)) >> i
// (num & (1 << i)) == 0 ? 0 : 1
}
void printBinaryWithInt(int num) {
for(int i = 31; i >=0; i--) {
printf("%d", num >> i & 1);
}
printf("\n");
}
int main(int argc, const char * argv[]) {
// 打印一个数字的二进制数,就是要获得每一个二进制位的 0 还是 1
// 123
// 000... 0000 0111 1011
// 这个数字先右移31位
// ... 30
// ... 29
// ...
// 1
// 0
// int num = 123;
//
// for(int i = 31; i >=0; i--) {
// printf("%d", num >> i & 1);
// }
//
// printf("\n");
// 1010 1010
// >> 7
// 1111 1111 & 1 ==> 1 第7位
//
// >> 6
// 1111 1110 & 1 ==> 0 第6位
//
// >> 5
// 1111 1101 & 1 ==> 1 第5位
// ...
// >> 1
// 1101 0101 & 1 ==> 1 第1位
//
// >> 0
// 1010 1010 & 1 ==> 0 第0位
printf("请输入一个数字\n");
int num;
scanf("%d", &num);
printBinaryWithInt(num);
int num1 = 10;
int num2 = 5;
// ...
printf("num1 = %d, num2 = %d\n", num1, num2); // 5 10
return 0;
}
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------