C语言——结构体知识点总结

目录

1.结构体的定义与使用

2.结构体数组

3.结构体指针

4.结构体然后计算大小

5.typedef关键字

6.结构体常见问题


1.结构体的定义与使用

结构体跟我们之前接触的数组的概念很相似,数组是类型相同的一组变量的集合,而结构体类型不同的一组变量的集合。这样就会使数据更多,类型更丰富,数据量更大。

结构体在定义的时候我们不关心这个结构体里面变量的值,它就类似于模板一样,至于变量的大小或内容我们再编程的时候会给它们补充完整,哪怕定义的变量没有用到也是可以的。

如何定义结构体

在给结构体中的赋值的时候,可以类比我们平时给普通变量赋值的情况。

struct student   //struct关键字+结构体名字
{
	int score;
	char name[128];
};    //记得有分号

int main()
{	  
	//类型          变量名   初始值
      int             a   =  10;
      struct student stu  = {98,"jhsad"}; 
	  //struct student可以看作是我们自定义的一种类型
	  return 0;
}

如何访问结构体

上面我们已经定义好了一个结构体,现在我们把结构体里面的值拿出来访问。同样类比普通变量的访问方式。

#include 
#include  

struct student
{
	int score;
	char name[128];
};

int main()
{	
	int a = 10;
    //第一种访问方式
    struct student stu = {98,"jhsad"};
	
    printf("a=%d\n",a);            //普通变量的访问方式
    printf("score=%d\n",stu.score);//访问结构体用.运算符
    printf("name=%s\n",stu.name);

    //第二种访问方式
    struct student text;
    text.score = 20;
 	strcpy(text.name,"李四");
    printf("score=%d\n",text.score);
    printf("name=%s\n",text.name);

	return 0;
}

2.结构体数组

结构体数组的定义方式跟上面都一样的,还是通过类比普通数组的定义方式。

#include 

struct student
{
	int sorce;
	char *name;
};

int main()
{	
//  类型         变量 大小 
	int            a  [3];
    struct student stu[3];
     
	return 0;
}

练习:通过结构体数组操作学生成绩

#include 
#include  
#include 

struct student
{
	int sorce;
	char *name;
};

int main()
{	
	int i;
	struct student stu[3];
    
    for(i=0;i

3.结构体指针

定义结构体指针的时候要注意两点:

1.如果用结构体指针,就不能用点运算符,访问结构体中的变量要用->

2.指针要注意是否是野指针或者NULL。

#include 
#include  
#include 

struct student
{
	int sorce;
	char *name;
}; 

int main()
{	
	struct student *p;   //定义结构体指针
	p = (struct student *)malloc(sizeof(struct student)); 
	p->name = (char *)malloc(sizeof(128));  //用->访问结构体中的内容
	p->sorce = 100;
	strcpy(p->name,"张三");
	
	printf("%s的成绩是%d\n",p->name,p->sorce);
    free(p);    //释放空间,防止内存泄漏
	return 0;
}

4.结构体然后计算大小

结构体计算大小由于要遵循计算机的访问规则,所以我们引入了内存对齐和偏移量的概念。

内存对齐简单的可以理解为跟盖章差不多,比如一张纸有12个字节,一个印章有四个字节,那么刚好印章盖三次可以盖完,假设这个印章有5个字节,那么怎么改都不可能刚好盖满12个字节。所以纸的大小一定要和章的大小成整数倍的关系,这样才可以做到对齐。

对齐的方式很浪费空间,但根据计算机的访问规则,大大提高了运行效率。

偏移量可以这样理解,现在我连续定义几个变量,第一个变量成员的大小就是下一个变量成员的偏移量大小。比如第一个成员是一个int型的变量,那么第二个变量成员的偏移量就是四个字节。

因此计算结构体大小的规则:
1.每一个成员的偏移量都必须是该成员的倍数。
2.结构体的大小必须是该结构体字节数最大成员的倍数(数组除外,结构体除外)

struct s1
{
	char ch1;  //一个字节
	char ch2   //一个字节 
	int ch3;   //四个字节,因此要遵循第一条规则,2个char一共偏移2个字节
};             //不是4的整数倍,因此要再多偏移两个字节,一共偏移8个字节
//可以用sizeof验证一下:printf("%d\n",sizeof(struct student));

再看下面这段代码,我们将解释第二条规则。

下面这段代码如果只遵循第一条规则的话所计算出的大小是9个字节,但是我们还有一个规则结构体的大小必须是该结构体字节数最大成员的倍数。9不是int型大小的整数倍,int型是4个字节,不是9的整数倍。因此我们还需再偏移3个字节,所以改结构体的大小为12个字节。

struct s2
{
	char ch1;  
	int ch3;
	char ch2;	
}; 

结构体中包含数组

struct s3
{
	char ch1;       //1个字节
	int ch3;        //4+3个字节(多偏移3个字节)
	char ch2[12];	//12个字节
};                  //共20个字节

struct s4
{
	char ch1;       //1个字节
	int ch3;        //4+3个字节(多偏移3个字节)
	char ch2[10];	//10个字节
};                  //多偏移两个字节,共20个字节

结构体中包含结构体

下面的代码不同之处就是一个是声明了结构体且定义了结构体变量,一个是声明了结构体且没有定义了结构体变量,计算出的结果大不相同。

struct s2
{
	char ch1;       //1个字节
	int ch2;        //4+3个字节(多偏移3个字节)
	struct s{
        char ch3;  
        int ch4;    //结构体中8个字节
    }stmp;          //声明结构体且定义了结构体变量
    float f;        //4个字节
};                  //8+8+4,共20个字节

struct s2
{
	char ch1;       //1个字节
	int ch2;        //4+3个字节(多偏移3个字节)
	struct s{
        char ch3;  
        int ch4;    //结构体中8个字节
    };              //声明结构体且没有定义了结构体变量,不占内存空间
    float f;        //4个字节
};                  //8+4,共12个字节

指定对齐方式(向4对齐)

#pragma pack(4) //指定向4对齐   最大是8
struct s5
{
	char ch1;  //1个字节
	int ch3;   //4+3个字节
	float b;   //4个字节
    double b;  //8个字节
};             //共20个字节

指定对齐方式(向10对齐)

如果结构体成员大小超过了pack的要求,就按pack来对齐。

如果最大成员大小没有超过pack,就按最大的成员大小来对齐。

#pragma pack(10) //指定向10对齐   
struct s6
{
	char ch1;  //1个字节
	int ch3;   //4+3个字节
	float b;   //4个字节
    double b;  //8个字节
};             //共24个字节

5.typedef关键字

typedef作为c语言关键字,作用是为一种数据类型定义一种新名字。这里的数据类型包括内部数据类型(int,char等),也包含自定义的数据类型(struct等)。

和struct匹配为了代码编写简洁。

和普通变量匹配,通过名字来获取一些信息。

在单片机开发中,经常会看到typedef unsigned char u_int8这样的写法,这样表示就相当于给unsigned char起了一个名字叫做u_int8,能表示的范围是0~255。

和结构体结合通常这样使用:

#include 
#include  
#include 

typedef struct s2
{
	char *ch1;    
	int ch2;        	
}STU;                

int main()
{	
	STU student;
	student.ch2 = 10;
	student.ch1 = (char *)malloc(128);
	strcpy(student.ch1,"uyuiy");
	
	printf("%d\n",student.ch2);
	printf("%s\n",student.ch1);
	return 0;
}

6.结构体常见问题

在定义结构体的时候最容易犯的错误就是定义了一个野指针,然后访问的时候造成段错误。就比如下面这段代码:

#include 
#include  
#include 

struct student
{
	char *p;
};

int main()
{	
  
    /*
    struct student stu;
    strcpy(stu.p,"sagdh");  这种写法是错误的,p在这里是一个野指针,内存空间没有申请
    printf("%s\n");         所以应该使用malloc给它安排空间,一定要有空间!
    */
    
    struct student stu;
	stu.p=(char *)malloc(128);
 	memset(stu.p,'\0',128);   //把里面每一项都初始化成0
	strcpy(stu.p,"sagdh");
    printf("%s\n",stu.p);

	return 0;
}

你可能感兴趣的:(C语言,c语言,开发语言,单片机,51单片机,stm32)