1、结构
结构是一种不同于数组的集合,它可以包含不同类型的数据(成员)且每个结构成员都有自己特定的名字。结构在一些编程语言中也称为记录,把结构的成员称作字段。代码解释格式如下:
struct {
char name[100];
int age;
char sex[10];
};
上面便是一种结构,其包含了姓名、年龄以及性别三个成员。
2、结构变量
2.1 概念
结构变量实质上就是一个指向结构数据的指针,通过该结构变量我们可以对结构的成员进行访问。
2.2 结构变量的声明
结构变量的声明是基于结构的,其声明的语法格式如下:
struct {
char name[100];
int age;
char sex[10];
}teacher1,teacher2;
这里的teacher1和teacher2就是结构变量。
2.3 结构变量的初始化
结构变量可以在声明的同时进行初始化操作,具体是将对应到结构成员的数据以列表的形式准备好并用大括号括起来。代码如下:
2.3.1 非指定初始化:
struct {
char name[100];
int age;
char sex[10];
}teacher1 = {"张三",18,"women"},
teacher2 = {"小明",25,"man"};
注意⚠️:
1、括号中的数据需要和结构中的成员一一对应,不能乱了顺序。
2、用于结构初始化式的表达式必须是常量。
3、初始化时的成员可以少于结构的成员,不足的成员都会以0作为其初始值。特别的剩余的字符数组中的字节数为0,表示空字符串。
2.3.2 指定初始化:
struct {
char name[100];
int age;
char sex[10];
}teacher1 = {.age = 18,.name = "zhangsan",.sex = "man"};
指定初始化时需要对每个成员赋值,但是可以乱序进行初始化。
2.4 对结构的操作
在对结构进行操作时我们必须知道结构变量,再通过点语法对结构的成员进行操作。例如,对于上面的结构,我们可以通过结构变量teacher1对其进行操作。eg:
//打印输出结构数据
NSLog(@"teacher1:\nname:%s\nage:%d\nsex:%s",teacher1.name,teacher1.age,teacher1.sex);
3、结构标记
3.1 概念
结构标记是用于标识某种特定结构的名字,如下面的例子便声明了一个名为student的结构标记:
struct student{
char name[20];
float score;
};
注意这里的标记名称“student”是可以首字母大写的形式的,只不过为了和结构类型区分,标记一般采用小写的形式。
3.2 结构标记的定义、变量声明与初始化
结构标记不同于结构变量,当程序中需要多个相同成员的结构变量时,结构变量必须一次性声明所有变量。结构标记则可以在使用的时候再临时声明并初始化,更加灵活。结构标记的声明和初始化也分为两种方式:
1、定义结构标记时一并声明初始化变量。
2、先定义结构标记,再声明和初始化变量。
如:
//一体
struct student{
char name[20];
float score;
}student1 = {"liming",99};
//使用结构标记临时声明和初始化变量
struct student student2 = {.score = 100,.name = "wanghong"};
4、结构类型
4.1 概念
通过typedef定义具体的类型名
4.2 结构类型的定义以及使用
结构类型的使用类似于结构标记,二者都是为解决结构变量不够灵活而产生的。
4.2.1 结构类型的定义
形如:
//定义了一个名叫Aniaml的结构类型,包含成员:名称、体重、颜色
typedef struct{
char name[20];
int weight;
char color[20];
}Animal;
4.2.2 结构类型的使用
简单使用:
//变量声明和定义
Animal dog = {"小黑",80,"black"};
Animal cat = {"小花",20,"white"};
printf("dogname:%s,weight:%d,color:%s\n",dog.name,dog.weight,dog.color);
printf("catname:%s,weight:%d,color:%s\n",cat.name,cat.weight,cat.color);
结构作为参数和返回值:
定义一个People的结构体
//结构类型
typedef struct{
char name[100];
int age;
char sex[100];
}People;
//作为参数使用
void printStruct(People person){
NSLog(@"name:%s",person.name);
}
//作为返回值使用
People getNewStruct(const char *name,int age,const char *sex){
People person;
strcpy(person.name, name);
strcpy(person.sex, sex);
person.age = age;
return person;
}
5、结构的内存占用
结构体数据存储原则:
原则1. 起始地址为该变量类型所占内存的整数倍,若不足则不足部分用数据填充至所占内存的整数倍。
原则2. 该结构体所占总内存为结构体成员变量中最大数据类型的整数倍。
举例1:
//结构的成员在内存的存储是按照声明的顺序存储的
typedef struct{
int price;
char name[14];
}Computer;
printf("ComputerSize:%lu\n",sizeof(Computer));
分析:
上面计算结果为20,成员price占用内存地址区间0~3,成员name是一个字符串数组,其占用内存地址区间为4~17,满足原则1,为了满足原则2(这里是4的整数倍)我们需要填充至19.所以上面结构体占用内存大小为20。
例子2:
typedef struct{
int price;
char name[14];
double number;
}Computer;
printf("ComputerSize:%lu\n",sizeof(Computer));
计算结果为32,接着上个例分析,name内存地址区间为4~17,此时添加number,其占8个字节,起始地址需要是8的倍数,即从24开始,则18~23便是需要填充的。number地址区间为24~31,所以该结构体总共占用0~31,占用内存32,也符合原则2。
假如我们在该结构体中继续添加一个成员char owner[5]那么内存占用又是多少呢?答案40