C语言学习-Day_08


  • 学习参考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 00000
0000 00011
0111 1111127
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
    • 字符串结束的标记
    • 空指针NULL,表示编号为0的地址
  • 以0为编号的存储单元的内容不可读、不可写

以上内容均属原创,如有不详或错误,敬请指出。
做别人的宝贝,别来淌我这趟浑水。
原文地址:https://www.cnblogs.com/bad5/p/14633763.html