0
点赞
收藏
分享

微信扫一扫

从初阶到进阶,深入理解结构体

alanwhy 2022-02-03 阅读 30

1、结构体类型的申明

2、结构体初始化

3、结构体成员访问

4、结构体传参

结构体类型申明:结构是一些值的集合,这些值称为结构成员变量。成员变量类型可以是不同的。

#include<stdio.h>
struct tag
{
  char name[20];//member-list
  int age;//member-list
  char tellnumber[12];//member-list
  char sex[5];//member-list
}s1,s2,s3;//variaber-list,s1,s2,s3是全局结构变量。
int main()
{
  struct tag s;//s是局部的结构体变量
  return 0;
}

variaber-list 变量列表; struct-结构体关键字;tag-结构体标签;struct tag-定义了结构体类型(类似int、char、float等,不占内存空间,只有在定义变量时才给出内存空间);struct tag s-创建结构体变量s;

#include<stdio.h>
typedef struct stu//将结构体类型重新命名为stu
{
  char name[20];
  int age;
  char tellnumber[12];
  char sex[5];
}stu;
int main()
{
  stu s1={"zhangsan",18,"15528204052","man"};//结构体变量初始化。
}

结构成员类型可以是:标量、变量、数组、指针、结构体。

2、结构体变量的定义与初始化

#include<stdio.h>
struct point
{
  int x;
  int y;
}p2;//结构类型定义与变量p2定义。
int mian()
{
  struct point p1;//定义结构体变量p1
}
//或者
struct point p3={x,y};

若一个结构体类型里包含另外一个结构体类型,那怎么初始化,看下面例子:

#include<stdio.h>
struct S
{
  int a;
  char c;
  char arr[10];
  double d;
};
struct T
{
  char ch[10];
  struct S s;
  char *pc;
};
int main()
{
  char arr[]="hello world\n";
  struct T t={"hehe",{100,'w',"hello davie",3.14},arr};//嵌套结构体初始化
  printf("%s\n",t.ch);//hehe
  printf("%s\n",t.s.arr);//hello davie
  printf("%lf\n",t.s.d);//3.14
  return 0;
}

3.结构体成员的访问 :结构体变量.结构体成员名     指针变量->结构体成员名

#include<stdio.h>
typedef struct stu//将结构体类型重新命名为stu
{
  char name[20];
  int age;
  char tellnumber[12];
  char sex[5];
}stu;
void print1(stu tmp)//传参结构:结构体标签+结构体变量名
{
  printf("%s\n",tmp.name);//用新建的结构体变量名去访问结构体成员
  printf("%d\n",tmp.age);
  printf("%s\n",tmp.tellnumber);
  printf("%s\n",tmp.sex);
}
void print2(stu* ptr)
{
  printf("%s\n",ptr->name);//指针访问成员->,用箭头
  printf("%s\n",ptr->age);
  printf("%s\n",ptr->tellnumber);
  printf("%s\n",ptr->sex);
}
int main()
{ //初始化:结构体标签+结构体变量名
  stu s={"zhangsan",40,"15528204052","man"};
  print1(s);//结构体传参,把结构体变量s传入函数print1里面,采用传值的形式。
  print2(&s);//结构体传参,把结构体变量s传入函数print2里面,采用传址的形式。
  return 0;
}

上述两种传参形式肯定是传地址形式要好一点,形参是实参的临时拷贝,若采用传值的形式,内存将开辟临时空间,而传地址只需开辟4个字节的空间存放指针变量,内存利用率上更好。(传参过程实际上是压栈操作)。

4.结构体自引用:比如链表结点的创建

#include<stdio.h>
struct Node
{
  int data;
  struct Node* nxet;//结构体要能够找到同类型的结构体,用指针串联起来
};

5.类型重命名:

#include<stdio.h>
typedef struct Node
{
  int data;
  struct Node* next;
}Node;
int main()
{
  Node n1;
}

7.结构体内存对齐:

#include<stdio.h>
struct S1
{
  char c1;
  int a;
  char c2;
};
struct S2
{
  char c1;
  char c2;
  int a;
};
int main()
{
  struct S1 s1={0};
  printf("%d\n",sizeof(s1));
  struct S2 s2={0};
  printf("%d\n",sizeof(s2));
  return 0;
}//打印结果为12和8

 

 内存对齐以空间换时间、在写code时应尽量让占用空间小的成员集中在一起。

7.1结构体内存对齐之修改默认对齐数:预处理命令 #pragma。

#include<stdio.h>
#pragma pack(4)//设置默认对齐数为4
struct s
{
   double d;
   int a;
};
#pragma pack()//取消设置的默认对齐数。
int main()
{
  printf("%d\n",offsetof(struct s,d));//offsetof(structName,memberName)计算结构体成员偏移量
  printf("%d\n",offsetof(struct s,a));//offsetof是宏,不是函数
  return 0;
}

offsetof(structName,memberName)

 

举报

相关推荐

0 条评论