- 学习参考B站郝斌老师的视频,文章内的源码如有需要可以私信联系。
枚举
- 把一个事物所有可能的取值一一列举出来
- 代码更直观,更安全
例:
/*枚举*/
# include <stdio.h>
//定义一个数据类型为enum WeekDay,没有定义变量
enum WeekDay
{
Monday, Tuesday, Wednesday, Thursday, Friday = 5, Saturday, Sunday
};
int main(void)
{
enum WeekDay day1 = Monday;
enum WeekDay day2 = Friday;
printf("%d %d
", day1, day2);
return 0;
}
- 枚举中的值编号默认是以0开始的,也可以手动指定
- 可以修改值的编号,但是不能通过编号修改值,不能通过编号输出值
/*运行结果*/
0 5
Press any key to continue
例:
/*枚举举例*/
# include <stdio.h>
enum WeekDay
{
Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
};
void f(enum WeekDay i)
{
switch (i)
{
case 0:
printf("Monday!
");
break;
case 1:
printf("Tuesday!
");
break;
case 2:
printf("Wednesday!
");
break;
case 3:
printf("Thursday!
");
break;
case 4:
printf("Friday!
");
break;
case 5:
printf("Saturday
");
break;
case 6:
printf("Sunday
");
break;
}
}
int main(void)
{
f(Friday);
return 0;
}
/*运行结果*/
Friday!
Press any key to continue
进制转换
- R进制转换为十进制
- 从最右边的数开始,计算R第几位
- 如:123CH转换为十进制:12*160+3*161+2*162+1*163
- 十进制转R进制
- 除以R,取余数,直到商为0,余数倒叙排列
- 如:123转换为二进制:123/2 余1,61/2 余1,30/2 余0,15/2 余1,7/2 余1,3/2 余1,1/2 余1。结果即:1111011
- 二进制转十六进制
- 一个十六进制数需要使用四个二进制位表示
- 从右向左,四位一段,分段转化,不够四位的补充0
- 十六进制转二进制
- 一位十六进制数转换为四位二进制
3FB9H表示十六进制数3FB9,也可以写成(3FB9)_{16}、0x3FB9、0X3FB9
2049D表示十进制数2049,也可以写成(2049)_{10}、2049
1357O表示八进制数1357,也可以写成(1357)_8、01357
1011B表示二进制,也可以写为(1011)_2
补码
-
补码的十进制转二进制
- 正整数的二进制
- 除以2,取余数,直到商为0,余数倒叙排列
- 负整数的二进制
- 先计算与该负数对应的正数的二进制数
- 将二进制数所有位取反,末尾加1
- 四位一组,不够位数时,用1补全
- 零的二进制
- 全为0
- 正整数的二进制
-
补码的二进制转十进制
- 首位是0,则表明是正整数,按照普通方法计算
- 首位是1,则表明是负整数
- 将所有位取反,末尾加1,所得数值是该负整数的绝对值
- 全为0,则对应的十进制数就是零
-
原码,也叫符号-绝对值码
- 最高位的0或1表示正负,其余二进制位是该数值的绝对值的二进制
- 加减乘除运算复杂,增加了CPU的复杂度,零的表示不唯一
-
反码
- 所以数值取反
-
移码
- 表示数值平移n位,n为移码量
- 主要用于浮点数的阶码的存储
例:负整数的十进制转二进制
/*负整数的十进制转二进制*/
/*
计算 -5 的二进制
1.计算 5 的二进制为 0101
2.所有位取反为 1010
3.末尾加 1 为 1011,十六进制即为B
4.前面所有位数用 1 补全
*/
# include <stdio.h>
int main(void)
{
int i = -5;
printf("%#X
", i); //以十六进制输出
return 0;
}
/*
在Visual C++6.0中的运行结果
-----------------------
0XFFFFFFFB
Press any key to continue
-----------------------
*/
例:负整数的二进制转十进制
/*负整数的二进制转十进制*/
/*
计算 1 0101 1101 的十进制数
1.首位是 1 表示是负整数
2.将所有位取反,即为 0 1010 0010 对应的十六进制数为 0XFFFFFFA2
3.末尾加 1 即为 0 1010 0011 对应十进制数即为 163
*/
# include <stdio.h>
int main(void)
{
int i = 0XFFFFFFA2;
printf("%d
", i);
return 0;
}
/*
在Visual C++6.0中的运行结果
-----------------------
-94
Press any key to continue
-----------------------
*/
- 8位二进制数代表的十进制数
二进制 | 十进制 |
---|---|
0000 0000 | 0 |
0000 0001 | 1 |
… | … |
0111 1111 | 127 |
1000 0000 | -128 |
1000 0001 | -127 |
… | … |
1111 1111 | -1 |
例:8位二进制数代表的十进制数
/*8位二进制数代表的十进制数*/
# include <stdio.h>
int main(void)
{
char ch = 0X80;
/*
对应的二进制数即为 1000 0000
字符占用1字节,即8位
*/
printf("%d
", ch);
ch = 128;
/*
128对应二进制数为 1000 0000
整形占用4字节,赋值给字符型时,高3字节会丢失
所有字符型变量ch中存放的是 1000 0000
*/
printf("%d
", ch);
return 0;
}
/*
在Visual C++6.0中的运行结果
-----------------------
-128
-128
Press any key to continue
-----------------------
*/
链表
- 数组
- 优点:存取速度快
- 缺点:需要一个连续的很大的内存
- 插入和删除元素的效率低
- 链表
- 优点:插入删除元素效率高,不需要很大的内存
- 缺点:查找某个位置的元素效率低
- 确定一个数组需要知道两个参数:第一个元素的地址和数组的长度
- 确定一个链表,只需要知道头指针
- 头指针:存放头节点地址的指针变量
- 头节点:
- 数据类型和首节点的类型一样
- 头节点是首届点前面的节点
- 头节点不存放有效数据,是为了方便链表的操作
- 首节点:存放第一个有效数据的节点
- 尾节点:存放最后一个有效数据的节点,地址指向为空(NULL)
- 数组中的元素必须存放在同一块存储空间中,即地址是连续的,删除或增加一个元素,后面的所有元素的地址都需要前移或后移
- 链表中的元素可以存放在不同的存储空间,即地址可以不连续,但是存储元素时同时要存储下一个元素所存放的地址,指向下一个元素的地址。删除或增加元素时,只需要修改指向的下一个元素的地址即可,后面的元素地址不需要改变
例:用户输入链表中的元素个数,再依次输入每个元素,最后输出链表中的元素
/*用户输入链表中的元素个数,再依次输入每个元素,最后输出链表中的元素*/
# include <stdio.h>
# include <malloc.h>
# include <stdlib.h>
struct Node
{
int data; //数据域,定义链表中的数据部分
struct Node * pNext; //指针域,定义链表的头节点,用于存放地址
};
/*函数声明*/
struct Node * Create_List(void); //创建链表
void Traverse_List(struct Node *); //遍历链表
int main(void)
{
struct Node * pHead = NULL; //用于存放链表的头节点地址
pHead = Create_List(); //创建一个链表,并将这个链表的头节点地址返回,赋值给pHead
Traverse_List(pHead); //遍历链表,对链表进行输出
return 0;
}
struct Node * Create_List(void) //void表示不接收参数
{
int len; //用于存放链表中元素的个数
int i;
int val; //用于临时存放用户输入的元素的值
struct Node * pHead = (struct Node *)malloc(sizeof(struct Node));
/*
pHead用于存放链表的头节点地址
*/
if (NULL == pHead)
{
printf("节点分配失败!程序终止!
");
exit(-1); //终止程序
}
struct Node * pTail = pHead; //pTail用于修改每一个输入的值和指向的下一个地址
pTail->pNext = NULL;
printf("请输入您需要生成的链表的节点个数:");
scanf("%d", &len);
for (i = 0; i < len; ++i)
{
printf("请输入第%d个节点的值:", i + 1);
scanf("%d", &val);
struct Node * pNew = (struct Node *)malloc(sizeof(struct Node));
/*
用于临时存放用户输入的值和地址
*/
if (NULL == pNew)
{
printf("分配失败!程序终止!
");
exit(-1);
}
pNew->data = val;
pTail->pNext = pNew;
pNew->pNext = NULL;
pTail = pNew;
}
return pHead;
};
void Traverse_List(struct Node * pHead)
{
struct Node * p = pHead->pNext;
printf("链表中的元素为:");
while (NULL != p)
{
printf("%d ", p->data);
p = p->pNext;
}
printf("
");
return;
}
/*运行结果*/
请输入您需要生成的链表的节点个数:5
请输入第1个节点的值:1
请输入第2个节点的值:2
请输入第3个节点的值:3
请输入第4个节点的值:4
请输入第5个节点的值:5
链表中的元素为:1 2 3 4 5
Press any key to continue
算法
- 狭义算法
- 对存储的数据进行操作
- 不同的存储结构,要完成某一功能所执行的操作是不一样的
- 算法依附于存储结构,不同的存储结构所执行的算法不同
- 广义算法
- 也叫泛型,无论数据如何存储,对数据的操作是一样的
位运算符
- 按位与:
&
3 & 5
:表示把3和5的二进制每一位都进行比较,两者都为1时才为1,否则为0- 3:0011,5:0101,计算后得:0001,即1
- 逻辑与:
&&
i && j
:表示i与j都为真时,结果才为真,1表示真,0表示假
- 按位或:
|
3 | 5
:表示把3和5的二进制每一位都进行比较,只要有一个为1,则结果为1- 3:0011,5:0101,计算后得:0111,即7
- 逻辑或:
||
i || j
:表示i与j中只要有一个为真,则结果即为真
- 按位取反:
~
~i
:表示把变量i所有的二进制位取反
- 按位异或:
^
3 ^ 5
:表示把3和5的二进制每一位都进行比较,相同为0,不同为1- 3:0011,5:0101,计算后得:0110,即6
- 按位左移:
<<
i << 1
:表示把变量i的二进制左移一位- 二进制左移n位表示这个数乘以2n
- 按位右移:
>>
i >> 1
:表示把变量i的二进制右移一位- 二进制右移n位表示这个数除以2n,前提是数据不能丢失
- 通过位运算符可以对数据的操作精确到每一位
- 负数的十进制转二进制:先计算该数对应的正数的二进制数,所有位取反,末位加1
- 负数得二进制转十进制:所有位取反,末位加1,所得数为该负数的绝对值
例:位运算符
/*位运算符*/
# include <stdio.h>
int main(void)
{
int i = 3;
int j = 5;
int k;
k = i & j; //i的二进制为:0011,j的二进制为:0101
printf("i & j = %d
", k); //计算得到得二进制为:0001,即1
k = i && j; //逻辑与运算,i和j都不为0,则结果为真
printf("i && j = %d
", k); //计算得到的值为1,C语言中1表示真,0表示假
k = i | j; //i的二进制为:0011,j的二进制为:0101
printf("i | j = %d
", k); //计算得到得二进制为:0111,即7
k = i || j; //逻辑或运算,i和j都不为0,则结果为真
printf("i || j = %d
", k); //计算得到的值为1
k = ~i; //变量i的所有二进制位取反,i的二进制为:0011
printf("~i = %d
", k); //计算得到的二进制为:1100,负数转化为十进制为:-4
k = i << 1; //i的二进制为:0011,左移一位
printf("i << 1 = %d
", k); //计算得到的二进制为:0110,即6
k = i >> 1; //i的二进制为:0011,右移一位
printf("i >> 1 = %d
", k); //计算得到的二进制为:0001,即1
return 0;
}
/*运行结果*/
i & j = 1
i && j = 1
i | j = 7
i || j = 1
~i = -4
i << 1 = 6
i >> 1 = 1
Press any key to continue
NULL
- 二进制全为0
- 数值0
- 字符串结束的标记