结构基础知识
在C语言中结构体是一种数据结构。结构体可被声明为变量,指针或者数组等;同时,也是一些元素的集合,这些元素被称为结构体成员,且这些成员可以是不同的类型,成员一般用名字访问
struct Stu //Stu为结构体标签{ char name[20]; int age; charsex[5]; char tele[12]; char addr[30];//成员}stu1,stu2;//stu1和stu2均为全局的结构体变量,int main(){ struct Stu stu;//创建结构体变量}
匿名结构体,将结构体标签省略,则必须在后面申明全局变量,但是也存在类型不同的问题
struct{ char name[20]; int age; charsex[5]; char tele[12]; char addr[30];//成员}stu1;struct{ char name[20]; int age; charsex[5]; char tele[12]; char addr[30];//成员}*pstu;//两结构体成员一模一样int main(){pstu=&stu1;/*error,两个类型不同,因为是匿名的结构体类型,通过其创建的变量编译器会认为他们是不同的类型*/}
typedef简化struct
struct Stu { char name[20]; int age; charsex[5]; char tele[12]; char addr[30];//成员}stu1,arrstu[10],*pstu;typedef struct Stu stu;/*如果typedef加在结构体前面,则后面的全局变量则表示为这个结构体的新名字*/int main(){ stu stu2;//省略struct stu arr2[10]; stu *pstu; return 0;}
结构体成员
1.直接访问
struct stu { char name[20]; int age; char sex[5]; char tele[12]; char addr[30];//成员};typedef struct stu stu;int main(){stu stu;//结构体变量//stu.name="bit";//error,不能给常量赋值strcpy(stu.name,"aaa");stu.age=10;printf("name=%s",stu.name);printf("age=%d",stu.age);return 0;}
2.间接访问
-> 用于结构体指针
. 用于结构体变量
struct stu { char name[20]; int age; char sex[5]; char tele[12]; char addr[30];//成员};typedef struct stu* pstu;int main(){stu stu;//结构体变量pstu pstu1=&stu;//strcpy((*pstu1).name,"aaa");//(*pstu1).age=20;strcpy(pstu1->name,"aaa");return 0;}
结构体自引
例1.错误的方式
struct A{char name[10];int age;struct A sa;}int main(){struct A sa;}
用递归造成死循环,不断的自己引用自己
改正
struct A{char name[10];int age;struct A *sa;//大小为一个确切的值,通过指针找到下一个}int main(){struct A sa1;struct A sa2;struct A sa3;sa1.pa=&sa2;sa2.pa=&sa3;sa3.pa=NULL;}
若想用typedef改写,则
typedef struct A//结构体内部嵌套同类型指针,重命名不能是匿名的结构体{char name[10];int age;struct A *sa;}a;int main(){ a sa1; a sa2; a sa3;sa1.pa=&sa2;sa2.pa=&sa3;sa3.pa=NULL;}
不完整声明
struct A{int i;struct B b;};struct B{int i;struct A a;};//不允许这种写法,会一直相互调用下去
改写为
struct B;struct A{int i;struct B *b;};struct B{int i;struct A *a;};
结构体初始化
struct stu{char name[10];int age;char sex[4];char tel[12];char add[20];};int main(){struct stu stu={"aaa",12,"male","123","xia"};printf("%s\n",stu.name);printf("%d\n",stu.age);return 0;}
结构体中含有结构体的初始化
struct A{ int a; char c; double d;};struct stu{char name[10];int age;char sex[4];char tel[12];char add[20];struct A sa;};int main(){struct stu stu={"aaa",12,"male","123","xian"};//不完全初始化struct stu stu={"aaa",12,"male","123","xian",{1,'w',12.34}};//sa前的成员不可省略printf("%s\n",stu.name);printf("%d\n",stu.age);printf("%1f\n",stu.sa.d);return 0;}
结构体大小
struct s{int a;char c;couble d;};struct s2{int a;double d;char c;};int main(){printf("%d\n",sizeof(struct s));printf("%d\n",sizeof(struct s2));return 0;}//输出16 24
存在内存对齐规则
第一个成员在与结构体变量偏移地址为0的地址处
其他成员变量要对齐到某个数字(对齐数)的整数倍的地址
对齐数=编译器默认的一个对齐数与该成员大小的较小值
vs中默认8,linux默认4
3. 结构体总大小为最大对齐数(每个成员变量除了第一个成员都有个对齐数)的整数倍
4. 如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍出,结构体的整体大小就是所有最大对其数(含嵌套结构体的对齐数)的整数倍
struct A{double d;char c; short s; dpuble d2;};int main(){printf("%d",sizeof(struct A));//24printf("%d",offsetof(struct A,d));//0}
offsetof是求每个类型对其的地址