C语言学习笔记-2021-03-22

一、结构体

------定义一个结构体--------
struct Student
{
	int age;
	float score;
	char sex;
}

int main(void)
{
	struct Student st = {80, 66.6, 'F'}
}
  • 为什么需要结构体
    为了表示一些复杂的食物,而普通的基本类型无法满足实际要求
  • 什么叫结构体
    把一些基本类型数据组合在一起,形成一个新的复合数据类型
  • 定义结构体有三种形式

如何使用结构体

1. 使用结构体中的每一个属性成员

struct Student
{
...
} 
int main()
{
	struct Student st = {80, 66.6, 'F'};
	struct Student *pst = &st;
	pst->age = 88; --- 第一种方式
	st.age = 88; ---第二种方式
}

2. 结构体变量的运算

  • 结构体变量不能进行加减乘除运算
  • 结构体变量可以相互赋值

举例-动态构造存放学生信息的结构体

struct Student
{
	char name[100];
	int age;
	double source;	
}

int main(void)
{
	int len;
	struct Student * pArr;
	printf("请输入学生的个数:\n");
	scanf("%d", &len);
	pArr = (struct Student *)malloc(len * sizeof(struct Student ));  //为数组pArr分配内存,分配学生个数*每个结构体占据字节数量
	
	//录入学生信息
	for (i=0; i<len; ++i)
	{
		printf("请输入第%d个学生的信息:\n", i+1);
		printf("学生的姓名为:\n");
		scanf("%s",pArr[i].name);  // 因为name是数组名,本身存放的就是数组首元素的地址,不用加取地址符&
		printf("学生的年龄为:\n");
		scanf("%d",&pArr[i].age);
		printf("学生的分数为:\n");
		scanf("%f",&pArr[i].source);
	}

	//输出学生信息
	for...
	{
		...
	}

	//根据成绩进行排序--冒泡排序法
	int i,j;
	struct Student t;
	for(i=0; i<len-1; i++)
	{
		for(j=0; j<len-1-i; j++)
		{
			if (pArr[j].source > pArr[j+1].source)
			{
				t = pArr[j];
				pArr[j] = pArr[j+1];
				pArr[j+1] = t;
			}
		}
	}

	return 0;
}

该段程序重复性内容比较多,易读性比较差,可以通过函数改进

二、枚举

...
enum Weekday
{
	Monday, Tuesday, Wednsday, Thursday, Friday, Saturday, Sunday
};

int main(void)
{
	enum Weekday day = Monday; // day只能赋予定义的有效值
	printf("%d\n", day); // 会输出0
}
  • 枚举的优点:
    代码更安全,但是书写麻烦

三、补码

1. 原码

  • 第一位0表示正,1表示负,后续位是所表示的数的绝对值的二进制位
  • 简单易懂,但是运算复杂
  • 的表示不唯一

2. 反码

  • 反码运算不变,也没有应用

3. 移码

  • 移码表示数值平移n位,n称为移码量
  • 移码主要用于浮点数的阶码的存储

4. 补码

  • 主要解决整数存储
  • 十进制转二进制
  1. 正整数转二进制: 除以2取余,直至商为0,余数倒叙排序
  2. 负整数转二进制: 先求与该负数相对应的正整数的二进制代码,然后将所有位取反,末尾加1,不够位数时,左边补1
  3. 零的二进制: 全是0
  • 8位二进制代码能表示的十进制数的范围是:-128~127

四、链表简介-帮助理解算法

算法:

  • 通俗定义:解题的方法和步骤
  • 狭义定义:对存储数据的操作,比如输出数组中的元素和输出链表中的元素,操作是不一样的,这种算法是依赖与存储结构的。
  • 广义定义:泛型,无论数据如何存储,对该数据的操作都是一样的,例如,可以把输出数组元素中的p++看作链表中的p = p->pNext,这样看来,输出数组和链表的元素思路是一样的
  • 我们至少可以通过两种结构来存储数据

数据存储方式

1. 数组

  • 优点:存取速度快
  • 缺点:需要一快连续的很大的内存,插入和删除元素的效率很低

2. 链表

  • 优点:可以有效利用内存,插入删除元素的效率高
  • 缺点:查找元素慢
  • 术语:
  1. 首节点:存放第一个有效数据的节点
  2. 尾节点:存放最后一个有效数据的节点
  3. 头结点:和首节点数据类型一样,不存放有效数据,设置头结是为了方便对链表进行操作
  4. 头指针:存放头结点地址的指针变量
...
struct Node
{
	int data;
	struct Node * pNext;
}
//函数声明
struct Node * create_list(void);
void traverse_list(struct Node *);

int main(void)
{
		struct Node * pHead; // 定义头指针,存放链表头结点的地址
		pHead = create_list(); //创建一个非循环单链表,并将头结点的地址存放pHead中
		traverse_list(pHead); 输出链表
		return 0;
}

struct Node * create_list(void);// 函数返回值是头指针,因此声明类型为 struct Node *
{
	...	
}

void traverse_list(struct Node * pHead)
{
	struct Node * p = pHead->pNext;
	while (NULL !=p)
	{
		printf("%d\n", p->data);
		p = p->pNext; //关键理解这一句
	}
	
	return;
}
上一篇:从线性连续存储开始,重新认识《数据结构》


下一篇:buffer cache中,各个object对象占用的buffer blocks