一、结构体
------定义一个结构体--------
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. 补码
- 主要解决整数存储
- 十进制转二进制
- 正整数转二进制: 除以2取余,直至商为0,余数倒叙排序
- 负整数转二进制: 先求与该负数相对应的正整数的二进制代码,然后将所有位取反,末尾加1,不够位数时,左边补1
- 零的二进制: 全是0
- 8位二进制代码能表示的十进制数的范围是:-128~127
四、链表简介-帮助理解算法
算法:
- 通俗定义:解题的方法和步骤
- 狭义定义:对存储数据的操作,比如输出数组中的元素和输出链表中的元素,操作是不一样的,这种算法是依赖与存储结构的。
- 广义定义:泛型,无论数据如何存储,对该数据的操作都是一样的,例如,可以把输出数组元素中的p++看作链表中的p = p->pNext,这样看来,输出数组和链表的元素思路是一样的
- 我们至少可以通过两种结构来存储数据
数据存储方式
1. 数组
- 优点:存取速度快
- 缺点:需要一快连续的很大的内存,插入和删除元素的效率很低
2. 链表
- 优点:可以有效利用内存,插入删除元素的效率高
- 缺点:查找元素慢
- 术语:
- 首节点:存放第一个有效数据的节点
- 尾节点:存放最后一个有效数据的节点
- 头结点:和首节点数据类型一样,不存放有效数据,设置头结是为了方便对链表进行操作
- 头指针:存放头结点地址的指针变量
...
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;
}