一、结构体声明和定义
任意由程序员创建出来的新类型
1.1 声明
strcut 结构体名(大写)
{
属性(称为成员)
};(分号不能少)
int i (抽象,具体(i有内存))
1.2 定义
struct Student (类项名)s(变量名)
s. (结构体运算符)
注意
s 在栈区;struct student 在全局
stuct
{ } s1,s1;也可以这样声明变量s1,s2,;同时省略结构体名,以后只能用s1,s2,来实现。
1.3 结构体的初始化
初始化部分;和数组很相似,初始化部分之后,其他没有填写的都是0,成员名前加.,成员初始化之间加,来隔开。
1.4 结构体对齐
sizeof(struct )结构体,注意在此情况下,结构体对齐问题,系统会有意的浪费空间,来对齐实现系统的效率。
1.5 结构体对齐原则
1、结构体按照其最长成员大小对齐,意味着最终的大小必须是最长成员大小的整数倍;
2、结构体成员按照结构体成员声明先后次序依次存放,并且每个成员的首字节放置的位置必须能够整除成员的字节数;
所以我们在写的时候要注意顺序,防止浪费太多的空间
3、如果结构体某个成员的字节数大于CPU的字节数,则最长按照CPU的字节数对齐;这个时候不需要在按照刚开始的字节数放置,而是按照CPU字节数来使其对齐,按照这个CPU来整除放置。
在答题的时候注意,在某个gcc 里面64位系统,不同的系统处理结果不一样
4、用预处理命令#pragma pack(n) 可以强制编译器按照指定的n来对齐,合法的n的数值分别是1、2、4、8、16。强制之后,就按照其强制的来放置,不需要管以前的类型,只需将其都看待成强转的类型即可。
二、结构体传参
2.1 结构体传参
在结构体作为参数传递的时候,一般用指针传参,节省空间,指针只传8字节,若用实参传递的化,我们需要拷贝与他内存空间相同的大小。指针传参没有创建新对象,拿着自己的走天下,不需要类似于实参传递的销毁空间等。
结构体指向结构体成员的指针,用箭头是指针,变量是.(*s).id(指向s变量)
全初始化就是按照成员变量全部写出来,如下图所示
- 结构体可以之间允许整体赋值 s1 = s2
- 结构体与结构体之间是无法之间进行比较。
- 结构体成员与结构体成员之间可以比较。
- a[j] 表示的第几个元素 (a+j)是指针
- 对于数组,或者说是字符串的我们比较大小的时候,用strcmp调用来进行比较
- 最好不要在头文件里面加入其他头文件,故延迟头文件(尽量放在原文件)
2.2 延迟函数
2.3 缓冲区
输出缓冲区
1、再输出的时候碰到\n,就将所有的输出到屏幕
2、程序员手动强制刷新,到屏幕调用fflush(stdout)
3、如果缓冲区满了之后,一次性输出到屏幕
三、链表
3.1 链表的基本概念
- 分为 值域 真正装的东西 指针域 下一个结构体的地址
- 结点是有有限的,最后一个结点置为NULL
- pHead(头指针)保存的是第一个指针的地址,其他的指向下一个。这种数据结构为链表。
- 删除、插入的算法的复杂度为1.
- 结点一般都是从堆上来。
- 一开始的时候,实际上什么都莫有,等程序开始运行的时候,将结点一个一个的添加进去,从堆上取得的malloc,所以其不连续,不能通过加1操作,来访问数组。
- 查找复杂度 比较低,我们只能一个一个根据指针来判断。
3.2 有头链表
有头链表:第一个指针无效
第一个指针,从栈上来,让从栈上指向堆,称为首节点
3.3 头插法
头插(每次插入的点向最前面插入)
头插算法
void push_font(struct Node *phead,int n)
{
struct Node *pnew = malloc(sizeof(struct Node));
pnew->next = phead->next;
phead->next = pnew;
pnew->data = n;
}
先将开辟的新空间的next指向的头节点,这个弄完了之后,就将首节点指向现在新开的,开完之后,记得赋值。
遍历链表,在栈上定义一个结构体,然后进行遍历。
遍历链表算法
void printfNode(struct Node *phead)
{
struct Node *p = phead->next;
while(p != NULL)
{
printf("%d\n",p->data);
p = p->next;
}
}