目录
- 一、结构体类型定义
- 二、结构体变量的定义
- 三、结构体变量赋值
- 1. 定义结构体变量的同时进行赋值
- 2. 定义结构体类型的同时定义变量并进行赋值
- 3. 在定义结构体变量时对指定成员进行赋值
- 4. 在定义完结构体变量后,通过'.'进行赋值
- 四、结构体成员访问
- 五、结构体内部指针的使用
- 六、结构体指针传参
- 七、结构体变量交换成员的值
- 1. 单成员交换
- 2. 所有成员交换
- 八、结构体内部的结构体指针
- 1. 栈区链表实现
- 2. 堆区单链表
- 九、结构体数组
- 十、结构体指针数组
- 十一、结构体内存大小
- 1. 结构体对齐
- 2. 结构体对齐的作用
- 3. 结构体对齐的方式
- 十二、结构体位域
结构体是一个构造类型,可以由不同类型的元素的成员组成。
结构体是一个类型,而非变量。
一般定义在全局,如果定义在函数中,只能在函数内部使用
一、结构体类型定义
struct <结构体名称>
{<变量类型1> <变量名1>;<变量类型2> <变量名2>;...<变量类型n> <变量名n>;
}; //分号不能省略
eg: 定义一个结构体
#include <stdio.h>struct Student{char name[128];int age;float sore;
};
- 注:
-
- struct 是结构体的关键字,必须书写。
-
- 结构体名称可以省略,一般定义在结构体内部时使用这种方式,定义变量的方式略有不同。
-
- 结构体内部的成员是通过花括号来包括的
-
- 结构体类型的最后必须包括一个’;’
-
- 结构体内部的成员必须是确定大小的,所以结构体内部是不能写函数的。
-
- 结构体内部成员的数据类型可以相等,也可以不等
-
- 注意C语言中不能在定义结构体时在结构体内部进行赋值,即下面的定义是错误的
#include <stdio.h>
/***这种定义方法是错误的***/
struct Student{char name[128] = “lily”;int age = 10;float sore = 100;
};
二、结构体变量的定义
结构体变量定义:
struct <结构体名称> 标识符;结构体指针变量:
struct <结构体名称> *标识符;
三、结构体变量赋值
1. 定义结构体变量的同时进行赋值
struct Student s2 ={"xiao,18,99.9"};
//访问
printf("name:%s\n",s2.name);
2. 定义结构体类型的同时定义变量并进行赋值
struct Student{char name[128];int age;float sore;
}s1={"lily",17,99};
3. 在定义结构体变量时对指定成员进行赋值
struct Student{char name[128];int age;float sore;
}s1={.name="Lily"};
- 注:不能写成下面的形式
/***错误的写法***/
struct Student{char name[128];int age;float sore;
}s1={s1.name="Lily"};//这种是错误的写法
4. 在定义完结构体变量后,通过’.'进行赋值
struct Student{char name[128];int age;float sore;
};int main()
{struct Student s1;strcpy(s1.name,"Lily");s1.age = 18;s1.sore = 99;
}
四、结构体成员访问
结构体变量:
通过 <结构体变量>.<成员>
来访问
结构体指针:
*p . <成员>
p -> <成员>
eg :使用指针访问结构体的值,实现两个虚数相加。
#include <stdio.h>struct vir
{int x;int y;
}s1={12,3},s2={65,32},s3;
//此时s1,s2,s3均为全局变量
//他们的成员也都是全局变量,存储在常量区的.bss段和.data段int main(int argc, const char *argv[])
{struct vir *p1 = &s1;struct vir *p2 = &s2;struct vir *p3 = &s3;p3->x=(p1->x)+(p2->x);p3->y=(p1->y)+(p2->y);printf("s1+s2=%d+%d*i\n",p3->x,p3->y);p3->x=(p1->x)-(p2->x);p3->y=(p1->y)-(p2->y);printf("s1-s2=%d+%d*i\n",p3->x,p3->y); return 0;
}
五、结构体内部指针的使用
#include <stdio.h>
#include <stdlib.h>
struct Place
{int *arr;int size;int capacity;
};
int main()
{struct Place t;t.arr=(int *)malloc(4*50);//申请50个int型数据的空间大小t.size = 0;//相当于下标t.capacity = 50;//可以容纳的数据的个数
}
六、结构体指针传参
eg:在堆区申请一段地址连续的空间
create函数,申请一块空间
write函数,向申请的空间内写值
#include <stdio.h>
#include <stdlib.h>//定义结构体类型
typedef struct Place{int* arr;int size;int capacity;
}Place_t;//创建空间
int create(Place_t *s,int size)
{if(!p){printf("struct is empty!\n");return -1;}s->arr = (int *)malloc(4*size);if(!(s->arr)){printf("create fail!\n");return -1;}s->size=0;s->capacity=size;printf("create %d please success!\n",size);return 0;
}
//向空间中写值
int write(Place_t *s,int num)
{if(!p){printf("struct is empty!\n");return -1;}if((s->size)<=(s->capacity)){ *((s->arr)+(s->size)) = num;(s->size)++;}else{ printf("capacity is full!\n");return -1; } return 0;
}int main(int argc, const char *argv[])
{Place_t a;int size;int num;printf("请输入需要多少空间:");scanf("%d",&size); create(&a,size);for(int i=0;i<size;i++){ printf("please input %d number:",i);scanf("%d",&num);if(write(&a,num)){printf("write fail!\n");}}for(int i=0;i<size;i++){printf("%d\n",*(a.arr+i));}//释放内存free(a.arr);a.arr=NULL;return 0;
}
七、结构体变量交换成员的值
1. 单成员交换
#include <stdio.h>
#include <string.h>struct Cat_t
{char name[128];int age;
}; int main()
{struct Cat_t c1 = {"mimi",1};struct Cat_t c2 = {"huahua",2};printf("交换前:\nc1.name=%s,c1.age=%d;\nc2=%s,c2.age=%d\n",c1.name,c1.age,c2.name,c2.age);struct Cat_t ret;strcpy(ret.name,c1.name);strcpy(c1.name,c2.name);strcpy(c2.name,ret.name); printf("交换后:\nc1.name=%s,c1.age=%d;\nc2=%s,c2.age=%d\n",c1.name,c1.age,c2.name,c2.age); return 0;
}
输出结果:
2. 所有成员交换
#include <stdio.h>struct Cat_t
{char name[128];int age;
}; int main()
{struct Cat_t c1 = {"mimi",1};struct Cat_t c2 = {"huahua",2};printf("交换前:\nc1.name=%s,c1.age=%d;\nc2=%s,c2.age=%d\n",c1.name,c1.age,c2.name,c2.age);struct Cat_t ret;ret = c1;c1 = c2;c2 = ret;printf("交换后:\nc1.name=%s,c1.age=%d;\nc2=%s,c2.age=%d\n",c1.name,c1.age,c2.name,c2.age);return 0;
}
输出结果:
八、结构体内部的结构体指针
1. 栈区链表实现
#include <stdio.h>typedef struct Node
{int number;struct Node* next;
}Node_t, *Node_p;void show(Node_p p)
{while((p->next)!=NULL){printf("%d ",p->next->number);p = p->next;}putchar(10);
}int main(int argc, const char *argv[])
{Node_t head = {-1,NULL};Node_t n1 = {10,NULL};Node_t n2 = {20,NULL};head.next = &n1;n1.next = &n2;show(&head);return 0;
}
输出结果:
2. 堆区单链表
#include <stdio.h>
#include <stdlib.h>typedef struct Node
{int number;struct Node* next;
}Node_t, *Node_p;int init(Node_p *phead);
//创建头节点:头节点number赋值成-1;next赋值成NULL
int creat(Node_p head,int number);
//创建节点:先找到链表尾部,在尾部插入节点
void sfree(Node_p head);
//
void show(Node_p p);int main(int argc, const char *argv[])
{Node_p head;init(&head);creat(head,10);creat(head,20);creat(head,30);creat(head,40);show(head);sfree(head);return 0;
}int init(Node_p *phead)
{*phead = (Node_p)malloc(sizeof(Node_t));if(!(*phead)){return -1;}(*phead)->number = -1; (*phead) -> next = NULL;return 0;
}int creat(Node_p head,int number)
{//在堆区申请一块空间Node_p ret = (Node_p)malloc(sizeof(Node_t));if(!ret)return -1;//给空间赋值ret -> number =number;ret -> next = NULL;Node_p tail = head;//链接while(tail->next){tail=tail->next;}tail->next = ret;return 0;
}
//释放堆区空间
void sfree(Node_p head)
{Node_p ret;while(ret = head->next) {free(head);head = ret;}free(head);
}
//打印
void show(Node_p p)
{while((p->next)!=NULL){printf("%d ",p->next->number);p = p->next;}putchar(10);
}
关于释放空间的第二种思路:
void sfree(Node_p head)
{Node_p p;while(head -> next){p = head -> next;head -> next = p -> next;free(p);}free(head);
}
九、结构体数组
结构体数组的本质是一个数组,数组中的每一个值都是结构体。
struct <结构体名称> <标识符>[成员个数];
eg:
#include <stdio.h>typedef struct Student
{char name[128];int age;float score;
}St_t,*St_p;int main(int argc, const char *argv[])
{St_t s1={"Lily",10,100.0};St_t s2={"LiMing",14,98.9};St_t s3={"Mary",9,97.5};St_t s4={"Bob",13,96.3};St_t s5={"Caily",11,120.0};St_t s_arr[5]={s1,s2,s3,s4,s5};for(int i=0;i<5;i++){ printf("%d:name=%s,age=%d,sore=%.2f\n",i,s_arr[i].name,s_arr[i].age,s_arr[i].score); } return 0;
}
十、结构体指针数组
结构体指针数组本质是一个数组,数组中的每一个元素都是结构体指针。
eg:
struct <结构体名称> *<标识符>[成员个数];
eg:
#include <stdio.h>typedef struct Student
{char name[128];int age;float score;
}St_t,*St_p;int main(int argc, const char *argv[])
{St_t s1={"Lily",10,100.0};St_t s2={"LiMing",14,98.9};St_t s3={"Mary",9,97.5};St_t s4={"Bob",13,96.3};St_t s5={"Caliy",11,120.0};St_p arr[5]={&s1,&s2,&s3,&s4,&s5};for(int i=0;i<5;i++){ printf("%d:name=%s,age=%d,sore=%.2f\n",i,arr[i]->name,arr[i]->age,arr[i]->score);} return 0;
}
十一、结构体内存大小
1. 结构体对齐
结构体的整个大小并不是所有成员依次加起来的大小,因为会发生结构体对齐。
2. 结构体对齐的作用
CPU不是按照字节大小进行取值的,而是按块(一般是四字节)进行取值。
为了使计算机更快地进行取值,所以结构体内部成员要对齐。
3. 结构体对齐的方式
结构体的第一个成员存放在结构体变量的0地址处。
其他成员存放在该成员的对齐数的整数倍的位置上。
对齐数:该成员的大小和编译器设置的最大对齐数的整数中的最小值。
(Linux中没有设置最大对齐数,windows默认对齐数是8)
结构体的整体大小,是这个结构体的所有成员的最大对齐数的整数倍。
- 注:
- 如果结构体的成员中有数组,则按数组的每个元素的大小作为对齐数。
- 如果结构体的成员中有结构体,先将结构体内部成员对齐,再整体对齐,同样按照上面的规则计算。
eg:
#include <stdio.h>struct Person
{char name[3];int age;
}; //8struct A
{int a;struct Person boy;;
};//12struct B
{int a;double b;char c;
}; //24struct C
{int a; char arr[20];int b;
};//28struct D
{double a;char b;double c;struct E{int o1;char [5];};//12
};//24+12=36,整体对齐:最大对齐数是8,因此是40
十二、结构体位域
结构体位域本质上是压缩内存的一种方式。一般是unsigned int、char类型使用。
eg:
struct A
{unsigned int a:10; //使用了int的10位unsigned int b:5;//如果存不下,会只取后五位
}struct A n;
此时结构体n占用的字节数就是4。一个int型空间就可以容纳。
a占10位,b占5位。