C语言基础——结构体

结构体的作用

在需要表示一些复杂信息时,使用单纯的数据类型很不方便。
比如:学生信息(学号,姓名,班级,电话,年龄);GPIO信息(GPIO输入输出、电平高低、是否中断等等)把这些信息组合在一起形成一种新的“数据类型”。

结构体的声明、结构体类型创建

结构体的声明可以分为三大类;①没有标签、②有标签、③有typedef

第一类
struct 
{
    char a;
    short b;
    int c;
} var1;

第二类
struct demo_tag 
{
    char a;
    short b;
    int c;
} var1;

第三类
typedef struct demo_tag 
{
    char a;
    short b;
    int c;
} demo_t;

typedef struct 
{
    char a;
    short b;
    int c;
} demo_t;

这三类都可以声明结构体,都是正确的。

区别在于:我们最终目的需要将一个变量定义为结构类类型;

采用第一种无标签的方法,每次需要写很多重复的东西,如下图

struct {
    char a;
    short b;
    int c;
} var1;


struct {
    char a;
    short b;
    int c;
} var2;

采用第二种有标签的方法,每次这么定义变量就行,如下图

(var1 是指var1变量是结构体类型的,不影响,相当于struct demo_tag var1)

struct demo_tag {
    char a;
    short b;
    int c;
} var1;

struct demo_tag var2;

采用第三种使用tpyedef的方法,定义变量时就更简单了,如下图:

typedef struct demo_tag {
    char a;
    short b;
    int c;
} demo_t;

demo_t var1,var2;

使用typedef时,代码中的demo_tag是没有用的,可以将demo_tag标签去掉,效果是一样的。

特别注意

1)结构体要包含 struct
2)最后要使用分号;
3)各成员之间也用分号隔开;;

结构体成员的访问

结构体成员依据结构体变量类型的不同,一般有2种访问方式,一种为直接访问,一种为间接访问。

直接访问应用于普通的结构体变量,间接访问应用于指向结构体变量的指针。直接访问使用结构体变量名.成员名,间接访问使用(*结构体指针名).成员名或者使用结构体指针名->成员名。相同的成员名称依靠不同的变量前缀区分。

struct SIMPLE
{
    int a;
    char b;
};
 
//声明结构体变量s1和指向结构体变量的指针s2
struct SIMPLE s1, *s2;
 
//给变量s1和s2的成员赋值,注意s1.a和s2->a并不是同一成员
s1.a = 5;
s1.b = 6;
s2->a = 3;
s2->b = 4;

计算结构体大小、结构体地址偏移

当我们用结构体保存GPIO寄存器时,每个寄存器地址偏移4字节,这时候就用到了结构的地址偏移。那么结构体的地址偏移和大小具体是怎么计算的呢?

两个原则:

1.结构体中成员的偏移量必须是该成员大小的整数倍;

2.结构体大小必须是所有成员大小的整数倍。

例1:

  struct stu1
  {
      int i;
      char c;
      int j;
  };

  结构体变量中第一个成员的地址就是结构体变量的首地址。因此,第一个成员i的偏移量为0。
第二个成员c的偏移量是第一个成员的偏移量加上第一个成员的大小(0+4),其值为4;
第三个成员j的偏移量是第二个成员的偏移量加上第二个成员的大小(4+1),其值为5。
单着并不是自身(int)大小的整数倍。编译器在处理时会在第二个成员后面补上3个空字节,
使得第三个成员的偏移量变成8。所以总共结构体大小为12

例2:

  struct stu2
  {
  int k;
  short t;
  };

  成员k的偏移量为0;成员t的偏移量为4,都不需要调整。但计算出来的大小为6,
显然不是结构体大小的整数倍。因此,编译器会在成员t后面补上2个字节,使得结构体的大小变成8从而满足第二个要求。

例3:

  struct stu3

  {
      char c1;
      int i;
      char c2;
  }
结构体的大小为12

出现结构体嵌套时,怎么计算结构体大小?

1.展开后的结构体的第一个成员的偏移量(嵌套的结构体偏移量)应当是被展开的结构体中最大成员的整数倍;

2.结构体大小必须是所有成员大小的整数倍,这里计算的是展开后的成员,而不是将嵌套的结构体看作一个整体。

例如:

值传递、指针传递、引用传递

值传递

1.值传递的效率低,因为值传递需要对结构体做一次拷贝

2.值传递只是改变了形参,并未改变实参。

例如:输出的值不会发生任何改变

#include<stdio.h>
#include<string.h>
struct student
{
	int num;
	char name[20];
	float score[3];
};
void change(struct student stu)
{
	stu.score[0] = 100;
	strcpy(stu.name, "jerry");
}
int main()
{
	
	struct student stu;
	stu.num = 12345;
	strcpy(stu.name, "Tom");
	stu.score[0] = 67.5;
	stu.score[1] = 89;
	stu.score[2] = 78.6;
	change(stu);
	printf(format, stu.num, stu.name, stu.score[0], stu.score[1],stu.score[2]);
	printf("\n");
	return 0;
}
 

指针传递

可以改变实参

<span style="font-family:Arial Black;font-size:12px;">#include<stdio.h>
#include<string.h>
#define format "%d\n%s\n%f\n%f\n%f\n"
struct student
{
	int num;
	char name[20];
	float score[3];
};
void change(struct student* p)
{
	p->score[0] = 100;
	strcpy(p->name, "jerry");
}
int main()
{
	
	struct student stu;
	stu.num = 12345;
	strcpy(stu.name, "Tom");
	stu.score[0] = 67.5;
	stu.score[1] = 89;
	stu.score[2] = 78.6;
	change(&stu);
	printf(format, stu.num, stu.name, stu.score[0], stu.score[1],stu.score[2]);
	printf("\n");
	return 0;
}
 

指针传递  中,函数声明用 "*",实参传递用  “&”, 结构体成员赋值用  "->"


void change(struct student* stu);     声明函数时用*号!

change(&stu);                         调用时用&

void change(struct student* p)
{
	p->score[0] = 100;
	strcpy(p->name, "jerry");         赋值时用->
}

引用传递

首先声明,在标准C语言中没有引用传递,只有C++才有引用传递。这里简单的提一下引用传递。

引用传递和指针传递是一样的,都是传指针。只不过引用传递少了“解指针”的操作。可能速度能快一丢丢。

引用传递中,函数声明用 "&",实参传递直接传结构体名字就行

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值