C语言-结构体与位域

这是我参与11月更文挑战的第29天,活动详情查看:2021最后一次更文挑战

  1. 结构体介绍

C语言里的结构体是可以包含不同数据类型和相同数据类型的一个有序集合,属于构造类型,可以自己任意组合,并且结构体里也可以使用结构体类型作为成员。

结构体在项目开发中使用非常多,无处不在,有了结构体类型就可以设计很多框架,模型,方便数据传输,存储等等。

结构体定义语法

1
2
3
4
5
6
7
8
9
10
cpp复制代码struct 结构体名称
{
数据类型1 成员名1;
数据类型2 成员名2;
数据类型3 成员名3;
.....
};

结构体的名称命名规则: 和普通变量命名规则一样—遵循C语言变量命名标准。
‘A’~‘Z’ ‘a’~ ’z’ ‘0’~’9’ _

示例代码:

1
2
3
4
5
6
7
8
cpp复制代码struct app
{
int age; //年龄
char name[100]; //姓名
int number; //学号
};

上面这一块代码表示定义(声明)一个新的结构体类型。 数据类型名称:struct app
  1. 如何使用结构体定义变量?

结构体定义变量有3种形式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
cpp复制代码#include <stdio.h>

//第一种形式:在定义结构体类型的时候同时定义变量
struct app1
{
int age; //年龄
char name[100]; //姓名
int number; //学号
}a1,a2,a3; //a1 a2 a3就是定义的结构体变量

//第二种形式
struct app2
{
int age; //年龄
char name[100]; //姓名
int number; //学号
};

//第三种形式: 匿名方式定义结构体
struct
{
int age; //年龄
char name[100]; //姓名
int number; //学号
}c1,c2,c3; //c1 c2 c3就是定义的结构体变量

int main()
{
//使用结构体类型定义变量
struct app2 b1;
struct app2 b2;
struct app2 b3;

return 0;
}
  1. 结构体的赋值

结构体变量的赋值语法:

1
cpp复制代码 结构体变量名.成员名=xxx;

结构体初始化赋值说明:

结构体只能在(定义结构体变量的时候)初始化的时候支持整体赋值,之后就只能按照成员单个赋值。

注意:结构体变量之间支持直接赋值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
cpp复制代码#include <stdio.h>
#include <string.h>

//第一种形式:在定义结构体类型的时候同时定义变量
struct app1
{
int age; //年龄
char name[100]; //姓名
int number; //学号
}a1={23,"小白",5678},a2,a3={12,"小明",1234}; //a1 a2 a3就是定义的结构体变量

//第二种形式
struct app2
{
int age; //年龄
char name[100]; //姓名
int number; //学号
};

int main()
{
//使用结构体类型定义变量
struct app2 b1={15,"小李",6878};
struct app2 b2;
struct app2 b3;

//单个修改结构体成员变量的值
b1.age=18;
//b1.name="555";
strcpy(b1.name,"小丽");

printf("b1:%d\n",b1.age);
printf("b1:%s\n",b1.name);

printf("a1:%d\n",a1.age);
printf("a1:%s\n",a1.name);

//结构体变量之间支持直接赋值 (要保证变量的类型要一致)。
//int a=100;
//int b;
//b=a;
b2=b1; //将b1结构体变量赋值给b2结构体变量
printf("b2:%d\n",b2.age);
printf("b2:%s\n",b2.name);
return 0;
}
  1. 结构体指针定义与使用

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
cpp复制代码#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct app
{
int age; //年龄
char name[100]; //姓名
int number; //学号
};

int main()
{
struct app a1; //定义一个结构体变量
struct app *p1; //定义一个结构体指针
struct app *p2; //定义一个结构体指针
p1=&a1; //地址赋值 p1指向a1的空间

//申请堆空间
p2=malloc(sizeof(struct app));

//通过指针访问成员
p1->age=20;
strcpy(p1->name,"小红");
p1->number=1234;
//输出数据
printf("姓名:%s\n",p1->name);
printf("学号:%d\n",p1->number);
printf("年龄:%d\n",p1->age);

//通过指针访问成员
p2->age=13;
strcpy(p2->name,"小李");
p2->number=5678;
//输出数据
printf("姓名:%s\n",p2->name);
printf("学号:%d\n",p2->number);
printf("年龄:%d\n",p2->age);

//释放空间
free(p2);
return 0;
}
  1. 结构体数组定义与使用

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
cpp复制代码#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct app
{
int age; //年龄
char name[100]; //姓名
int number; //学号
};

int main()
{

//定义一个结构体数组
struct app buff[10]; //一次定义了10个结构体变量
struct app *p=buff; //定义一个结构体指针

//访问成员
buff[0].age=10;
strcpy(buff[0].name,"小米");
buff[0].number=1234;

//打印数据
printf("姓名:%s\n",buff[0].name);
printf("学号:%d\n",buff[0].number);
printf("年龄:%d\n",buff[0].age);

printf("姓名:%s\n",p[0].name);
printf("学号:%d\n",p[0].number);
printf("年龄:%d\n",p[0].age);
return 0;
}
  1. 结构体当做函数的形参和返回值

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
cpp复制代码#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct app
{
int age; //年龄
char name[100]; //姓名
int number; //学号
};

struct app *func_stu(struct app *p);

int main()
{

//定义一个结构体数组
struct app buff[10]; //一次定义了10个结构体变量

//调用函数
func_stu(&buff[0]);

//打印数据
printf("姓名:%s\n",buff[0].name);
printf("学号:%d\n",buff[0].number);
printf("年龄:%d\n",buff[0].age);
return 0;
}

//定义函数
struct app *func_stu(struct app *p)
{
//访问成员
p->age=10;
strcpy(p->name,"小米");
p->number=1234;
return p;
}
  1. typedef关键字在结构体里使用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
cpp复制代码#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct app
{
int age; //年龄
char name[100]; //姓名
int number; //学号
}STU; //STU叫结构体类型,相当于struct app的别名。 struct app == STU

STU *func_stu(STU *p);

int main()
{
//定义一个结构体数组
STU buff[10]; //一次定义了10个结构体变量

//调用函数
func_stu(&buff[0]);

//打印数据
printf("姓名:%s\n",buff[0].name);
printf("学号:%d\n",buff[0].number);
printf("年龄:%d\n",buff[0].age);
return 0;
}

//定义函数
STU *func_stu(STU *p)
{
//访问成员
p->age=10;
strcpy(p->name,"小米");
p->number=1234;
return p;
}
  1. 结构体位域

位域用的不多,但是也有地方使用,主要是节省空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
cpp复制代码#include <stdio.h>
struct app
{
unsigned int a:12; //定义位域,指定位宽 12的单位是位
unsigned int b:16;
unsigned char c:1; //定义空间存储1位的数据。 1和0
unsigned int :5; //位域的名称可以省略掉,为了空间内存对齐而存在的
};
/*
1. 位域的大小不能超出本来数据类型大小。
2. 位域的名称可以省略掉,为了空间内存对齐而存在的
3. 位域的成员无法取地址操作
*/

int main()
{
struct app data;
//data.c=2; 错误 超出范围 只能存放0~1
//data.b=65535; 错误 超出范围 只能存放0~65535
// data.a=4096; 错误 超出范围 只能存放0~65535
//printf("%d\n",data.c);
// printf("%d\n",data.b);
//printf("%d\n",data.a);

//printf("%d\n",&data.a); //错误 位域的成员无法取地址操作

data.c=1;
data.b=555; //只能存放0~65535
data.a=888; //只能存放0~65535
printf("%d\n",data.c);
printf("%d\n",data.b);
printf("%d\n",data.a);
return 0;
}
  1. 结构体的内存对齐

9.1 示例1: 计算结构体内存对齐

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
cpp复制代码#include <stdio.h>
struct app
{
int a1;
char a2;
char a3;
char a4;
char a5;
char a6;
char a7;
};
/*
目前32位系统里,使用的是gcc编译器。
开空间的对齐原理:以结构体里出现的最大数据类型的倍数开空间,最大是4个字节。
*/
int main()
{
struct app data;
printf("空间大小:%d 字节\n",sizeof(struct app)); //8
return 0;
}

//func("1",1123,45,"45",123.45,'A');
void func(char *p,...)
{

}

9.2 示例2: 计算结构体内存对齐

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
cpp复制代码#include <stdio.h>
#if 0
struct app
{
char a1; //1
short a2; //2
};
最终占用空间大小4个字节
#endif

#if 0
struct app
{
int a1[10]; //4*10=40
char a2[10]; //12
int a3; //4
float a4; //4
char a5; //4
};
//最终占用空间大小64个字节
#endif

#if 1
struct app
{
int a1;
double a2;
};
//最终占用空间大小64个字节
#endif

/*
目前32位系统里,使用的是gcc编译器。
开空间的对齐原理:以结构体里出现的最大数据类型的倍数开空间,最大是4个字节。
*/
int main()
{
struct app data;
printf("空间大小:%d 字节\n",sizeof(struct app)); //8
return 0;
}

//func("1",1123,45,"45",123.45,'A');
void func(char *p,...)
{

}

9.3 输出结构体变量成员的地址,查看空间对齐情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
cpp复制代码#include <stdio.h>

struct app
{
int a1[10]; //4*10=40
char a2[10]; //12
int a3; //4
float a4; //4
char a5; //4
};
//最终占用空间大小64个字节

int main()
{
struct app data;

//输出地址 查看空间对齐原理
printf("%#x\n",data.a1);
printf("%#x\n",data.a2);
printf("%#x\n",&data.a3);
printf("%#x\n",&data.a4);
printf("%#x\n",&data.a5);
return 0;
}

9.4 对齐结构体进行强制对齐

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
cpp复制代码#include <stdio.h>

#pragma pack(1) //1 2 4 8
struct app
{
int a1[10]; //4*10=40
char a2[10]; //1*10=10
int a3; //4
float a4; //4
char a5; //1
};

int main()
{
struct app data;

//输出地址 查看空间对齐原理
printf("%#x\n",data.a1);
printf("%#x\n",data.a2);
printf("%#x\n",&data.a3);
printf("%#x\n",&data.a4);
printf("%#x\n",&data.a5);
printf("%d\n",sizeof(struct app));
return 0;
}

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%