目录
一、结构体的基本概念
举个例子
二、结构体变量
三、结构体占用的内存情况
举个例子
运行效果
再次运行
四、结构体的变量名
五、结构体初始化
五、结构体初始化
举个例子
运行效果
六、结构体成员的访问
举个例子
运行效果
八、结构体指针
举个例子
运行效果
九、结构体的赋值
举个例子
运行效果
十、结构体作为函数的参数
举个例子
运行效果
一、结构体的基本概念
结构体(struct)就是用来存放一组不同类型的数据的,语法如下:
struct 结构体名
{结构体成员变量一的声明;结构体成员变量二的声明;结构体成员变量三的声明;......结构体成员变量四的声明;
}; // 分号不要忘记
结构体是一个集合,是一种构造的数据类型,为了描述一个数据集自己定义出来的数据类型。结构体的成员(member)可以是任意类型的变量,也可以是结构体变量。
举个例子
struct boy
{char name[51]; // 姓名int age; // 年龄int height; // 身高int weight; // 体重char figure[31]; // 身材char face[31]; // 颜值
}; //记得加分号
二、结构体变量
结构体是一种自定义的数据类型,是模板,可以用它来定义变量。例如:
struct boy xiaoqiu1, xiaoqiu2, xiaoqiu3;
三、结构体占用的内存情况
理论上讲结构体的各个成员在内存中是连续存放的,和数组非常类似,但是,结构体的占用内存的总大小不一定等于全部成员变量占用内存大小之和。在编译器的具体实现中,为了提高内存寻址的效率,各个成员之间可能会存在缝隙。用sizeof可以得到结构体占用内存在总大小,sizeof(结构体名)或 sizeof(结构体变量名)都OK
举个例子
#include <stdio.h>
#include <string.h>// 定义结构体
struct boy
{char name[50]; // 姓名int age; // 年龄int height; // 身高char figure[30]; // 身材char face[30]; // 颜值
};int main()
{// 定义结构体变量struct boy xiaoqiu;printf("sizeof(struct boy) = %d\n",sizeof(struct boy));printf("sizeof(xiaoqiu) = %d\n",sizeof(xiaoqiu));return 0;
}
运行效果
从上面的例子可以看出,struct boy 全部成员变量占用的内存是50+4+4+30+30=118,但是结构体占用的内存却是 120
C语言提供了结构体成员内存对齐的方法,在定义结构体之前,增加以下代码可以使结构体成员变量之间的内存没有空隙
#pragma pack(1) // 在头文件添加
再次运行
四、结构体的变量名
和数组不一样,结构体变量名不是结构体变量的地址,结构体变量名就是变量名,就象 int a一样,只是不能直接输出,直接输出没有任何意义。取地址要用&。
struct boy xiaoqiu1;printf("%d\n",xiaoqiu1); // 没有意义printf("%p\n",xiaoqiu1); // 没有意义,结构体变量名不是结构体变量的地址。printf("%p\n",&xiaoqiu1); // 这才是结构体的地址
五、结构体初始化
采用memset函数初始化结构体,全部成员变量的值清零。
memset(&queen,0,sizeof(struct st_girl));
或
memset(&queen,0,sizeof(queen));
注意事项,如果把一个结构体的地址传给子函数,子函数用一个结构体指针(如struct st_girl *pst)来存放传入的结构体的地址,那么,在子函数中只能用以下方法来初始化结构体:
memset(pst,0,sizeof(struct st_girl));
不能用以下方法来初始化结构体:
memset(pst,0,sizeof(pst));
因为子函数中用sizeof(pst),得到的不是结构体占用内存的字节数,而是结构体指针变量占用内存的字节数(8字节)。
五、结构体初始化
采用memset函数初始化结构体,全部成员变量的值清零
memset(&xiaoqiu1,0,sizeof(struct boy));
或者
memset(&xiaoqiu1,0,sizeof(xiaoqiu1));
注意事项,如果把一个结构体的地址传给子函数,子函数用一个结构体指针(如struct boy *pst)来存放传入的结构体的地址,那么,在子函数中只能用以下方法来初始化结构体:
memset(pst,0,sizeof(struct boy));
不能用以下方法来初始化结构体:
memset(pst,0,sizeof(pst));//错误案例
因为子函数中用sizeof(pst),得到的不是结构体占用内存的字节数,而是结构体指针变量占用内存的字节数(8字节)
举个例子
#include<stdio.h>
#include<string.h>
#pragma pack(1)struct boy
{char name[50];int age;int height;char figure[30];char face[30];
};void func(struct boy *pst)
{ memset(pst,0,sizeof(pst)); memset(pst,0,sizeof(struct boy));printf("sizeof(pst) = %d\n",sizeof(pst)); // 得到的是指针变量的字节数(8字节)printf("sizeof(pst) = %d\n",sizeof(struct boy));
}int main()
{struct boy xiaoqiu;memset(&xiaoqiu,0,sizeof(xiaoqiu));memset(&xiaoqiu,0,sizeof(struct boy));func(&xiaoqiu);printf("sizeof(xiaoqiu) = %d\n",sizeof(xiaoqiu));printf("sizeof(struct boy) = %d\n",sizeof(struct boy));return 0;
}
运行效果
六、结构体成员的访问
采用圆点 . 运算符可以访问(使用)结构的成员,结构体成员变量的使用与普通变量的使用相同
举个例子
#include<stdio.h>
#include<string.h>
#pragma pack(1)// 定义一个结构体
struct boy
{char name[50];int age;int height;
};int main()
{// 定义一个结构体变量struct boy xiaoqiu;memset(&xiaoqiu,0,sizeof(struct boy));//初始化strcpy(xiaoqiu.name,"小酋");xiaoqiu.age = 20;xiaoqiu.height = 168;printf("名字: %s\n",xiaoqiu.name);printf("年龄: %d\n",xiaoqiu.age);printf("身高: %d\n",xiaoqiu.height);return 0;
}
运行效果
八、结构体指针
- 结构体是一种自定义的数据类型,结构体变量是内存变量,有内存地址,也就有结构体指针
- 在指针章节中我们已经知道,采用不同数据类型的指针指向不同数据类型的变量的地址,这一规则也适用于结构体
如下:
struct boy xiaoqiu;struct boy *pst = &xiaoqiu;
通过结构体指针可以使用结构体成员,一般形式为:
(*pst).memberName
或者:
pst->memberName
两种写法都可以,看你个人喜欢,大多人喜欢用后者。
举个例子
#include<stdio.h>
#include<string.h>
#pragma pack(1)// 定义一个结构体
struct boy
{char name[50];int age;
};int main()
{// 定义一个结构体变量struct boy *pst,xiaoqiu;memset(&xiaoqiu,0,sizeof(struct boy));//初始化pst = &xiaoqiu;strcpy(pst->name,"小酋");pst->age = 20;printf("名字: %s\n",pst->name);printf("年龄: %d\n",pst->age);return 0;
}
运行效果
九、结构体的赋值
结构体的成员如果是基本数据类型(int、char、double)可以用=号赋值,如果是字符串,字符串不是基本数据类型,可以用 strcpy 函数赋值,如果要把结构体变量的值赋给另一个结构体变量,可以使用 memcpy 函数
函数声明:
void *memcpy(void *dest, const void *src, size_t n);
参数说明:
- src 源内存变量的起始地址
- dest 目的内存变量的起始地址
- n 需要复制内容的字节数
举个例子
#include<stdio.h>
#include<string.h>
#pragma pack(1)// 定义一个结构体
struct boy
{char name[50];int age;
};int main()
{// 定义一个结构体变量struct boy xiaoqiu1,xiaoqiu2;memset(&xiaoqiu1,0,sizeof(struct boy));//初始化memset(&xiaoqiu2,0,sizeof(struct boy));//初始化strcpy(xiaoqiu1.name,"小酋");xiaoqiu1.age = 20;memcpy(&xiaoqiu2,&xiaoqiu1,sizeof(struct boy));printf("名字:%s 年龄: %d\n",xiaoqiu1.name,xiaoqiu1.age);printf("名字:%s 年龄: %d\n",xiaoqiu2.name,xiaoqiu2.age);return 0;
}
运行效果
十、结构体作为函数的参数
结构体是多个变量集合,作为函数参数时就可以传递整个集合,也就是所有成员。如果结构体成员较多,函数参数的初始化和赋值的内存开销会很大,影响程序的运行效率。所以最好的办法就是传递结构体变量的地址
举个例子
#include<stdio.h>
#include<string.h>
#pragma pack(1)// 定义一个结构体
struct boy
{ char name[50];int age;
};// 给结构体赋值的函数
void setvalue(struct boy *pst)
{strcpy(pst->name,"小酋");pst->age = 20;
}int main()
{// 定义一个结构体变量struct boy xiaoqiu1;memset(&xiaoqiu1,0,sizeof(struct boy));setvalue(&xiaoqiu1);printf("名字:%s 年龄: %d\n",xiaoqiu1.name,xiaoqiu1.age);return 0;
}
运行效果