C语言结构体与链表
1.结构体
1.1.结构体的形式
主要形式:struct xxx{}和typedef struct xxx{}两个显示
- struct xxx{}形式也有两个,第一个如下:
#include<stdio.h> struct Demo //Demo是结构体名,可随便取 { int data1; int data2; }De; //De是结构体变量名,这是第一个方法定义的变量形式 int main() { printf("输入:"); scanf("%d%d",&De.data1,&De.data2); printf("输出:%d,%d\n",De.data1,De.data2); system("pause"); return 0; }
- 第二个形式如下:
#include<stdio.h> struct Demo { int data1; int data2; }; //第二种形式变量名可在函数中定义 int main() { struct Demo De; //定义结构体变量需包涵struct+结构体名+变量名 printf("输入:"); scanf("%d%d",&De.data1,&De.data2); printf("输出:%d,%d\n",De.data1,De.data2); system("pause"); return 0; }
- typedef struct xxx{}形式就比struct xxx{}形式高级一点,可以起结构体别名,从而简化结构体在函数中定义结构体变量,如下图:
#include<stdio.h> typedef struct Demo { int data1; int data2; }demo; //这个是将typedef struct Demo重新取名为demo,区别于上一个形式是结构体变量名 int main() { demo De; //这里才是定义结构体变量名 printf("输入:"); scanf("%d%d",&De.data1,&De.data2); printf("输出:%d,%d\n",De.data1,De.data2); system("pause"); return 0; }
- 结构体指针变量,这个就有点复杂,因为指针是通过地址取值,定义了指针变量,就要给指针分配地址,因此有两种做法,一种是先定义一个普通变量,然后再定义指针变量,将普通变量的地址赋给指针即可,如下:
#include<stdio.h> typedef struct Demo { int data1; int data2; }demo; int main() { demo de; //定义普通变量de demo *De; //定义指针变量 De=&de; //将普通变量地址赋给指针 printf("输入:"); scanf("%d%d",&De->data1,&De->data2); //注意,指针赋值和取值用->符号 printf("输出:%d,%d\n",De->data1,De->data2); system("pause"); return 0; }
- 第二种就是使用malloc初始化地址,这个方法后面的链表中讲解
1.2.小结:
- 结构体的形式有struct xxx{}和typedef struct xxx{}
- 结构体普通变量用.输入输出值,指针用->输入输出值
- 结构体指针变量需要赋初始地址
2.结构体与链表
本次只写单向链表的基础知识,毕竟链表的知识很多,一篇写不完
2.1.链表定义
- 链表:个人理解为一个接着一个地址连在一起的
- 为什么能连在一起:个人答案,可以理解为一个地址存数据的同时也存了下一个地址的地址信息,所以地址之间连接了起来,称之为链表
- 如下,结构体定义部分:
typedef struct Demo { int data; //结构体数据,也就是链表数据 struct Demo *next; //重点在这,next表示指针域,也就是当前地址存放下一个地址的信息的区域, //所以我们喜欢用next来作为指针,就是代表下一个地址的意思 }demo;
因此,链表的思想其实就是在本地址不仅存放数据,还存放下一个地址的信息
2.2.链表的构建
链表定义之后,那么就开始构建链表,并且获取链表的数据
- 构建:链表头是没有数据的,其实就是只存放下一个地址的信息,那么下一个地址又有下一个地址的信息,直到最后一个地址只有本身地址不存放下一个地址的信息,也就是NULL时,该链表存放地址结束,长度也定下来了,如下图:
- 怎样获取链表上的数据呢,这时候就用到了结构体指针变量了,通过指针在链表上的移动来获取数据,如下图解释:
- 完整链表代码如下:
#include<stdio.h> #include<stdlib.h> #include<string.h> typedef struct Demo { int data; struct Demo *next; //定义指针域,用于存放下一个地址信息 }demo; //demo是结构体别名 void print(demo *head) //子函数,接收从主函数传递表头,类型是结构体指针类型 { demo *p; //定义结构体指针变量 p=head->next; //p指针指向head的下一个地址的信息 printf("输出两个数据:"); while (p!=NULL) //因为链表长度为2,因此p现在不为空 { printf("%d,\n",p->data); //获取数据 p=p->next; //p再指向下一个地址的信息(相当于head->next->next) } } int main() { demo *head; //定义指针变量让其为表头 demo *p,*q; //定义其他两个指针变量,给表头连接其他地址,从而形成链表,成为真正的链表表头 int i; /*这里重点讲一下 1.可以写成head=(demo *)malloc(sizeof(demo)),(demo *)是明确是demo类型,因此可以省略 2.这一步是初始化指针,malloc可以理解为指定链表中每获得新的地址的固定大小 3.sizeof表示获取大小,demo是结构体,sizeof(demo)就是获取demo的大小 4.因此总的意思就是,以后链表每连接的地址大小都是sizeof(demo),也就是储存demo中的数据 */ head = malloc(sizeof(demo)); head->next=NULL; //让表头的下一个地址信息为空,也就是确保head没有连接然后地址 p=head; //将表头地址给p,这里是通过p来连接其他地址,因为head的地址给了p //因此p连接其他地址,也就是head连接其他地址 printf("输入两个数据:"); for(i=0;i<2;i++) { q=malloc(sizeof(demo)); //初始化q,指针都要初始化的, //这里我们每循环获取一次信息后就初始化一次,因为q只是用来传递地址的 //p是来连接每一个初始化得到数据后的q的地址 scanf("%d",&q->data); //给q数据 p->next=q; //根据上面head->next=NULL的,也就是p->next也等于NULL, //这一步就是把NULL变成q的地址的消息 p=q; //p移动到q的地址上,也就是移动到新的地址上,从而连接下一个地址 } q->next=NULL; //结束,以下一个地址的信息为NUll结尾 print(head); //将表头给print函数 system("pause"); return 0; }
3.总结
- 结构体有struct xxx{}和typedef struct xxx{}两个形式
- 结构体指针变量需要赋初始地址
- 链表可以理解为一个地址存数据的同时也存了下一个地址的地址信息,所以地址之间连接了起来
- 链表传递的是表头,通过其他指针遍历赋值或获取数据