结构体的基本概念
int main(int argc, const char * argv[]) {
/*
基本数据类型: int double float char
构造类型: 数组/ 结构体
人:
姓名: // char *
年龄: // int
身高: // double
狗:
姓名 :
年龄 :
身长 :
体重 :
几只眼睛 :
几条腿 :
数组: 是用于保存一组相同类型的数据
结构体: 是用于保存一组不同类型的数据
要想保存人得数据, 就必须先定义变量
数据类型 变量名称;
如何定义一个结构体变量
1.定义结构体类型
2.根据结构体类型, 定义结构体变量
定义结构体类型的格式:
struct 结构体类型名称
{
属性;
};
*/
// int Person[] = {"lnj", 30, 1.75};
// printf("name = %s\n", Person[0]);
// 1.定义结构体类型
struct Person
{
// char name[20];
char *name;
int age;
double height;
};
// 2.定义结构体变量
// int num;
struct Person p;
// 注意: 数组不能先定义再进行一次性的初始化, 所有下面的写法是错误的
// p.name = "lnj"; // name = {'l', 'n', 'j', '\0'};
// 可以使用 结构体变量名称.属性的方式给结构体变量赋值
p.name = "lnj";
p.age = 30;
p.height = 1.75;
/*
int nums[3];
nums[0] = 998;
nums[1] = 887;
nums[2] = 789;
*/
// int nums[3];
// nums = {1, 3, 5};
return 0;
}
结构体初始化
int main(int argc, const char * argv[]) {
/*
int nums[] = {1, 3, 5};
int nums[3];
nums[0] = 1;
nums[1] = 3;
nums[2] = 5;
int nums[3];
nums = {1, 3, 5}; // 错误
int nums[3] = {[1] = 2};
printf("nums[0] = %i\n", nums[0]);
*/
struct Dog
{
char *name;
int age;
double height;
};
// 1.定义的同时初始化
struct Dog sd = {"wc", 13, 5.0};
// 2.先定义再初始化(逐个初始化)
struct Dog sd1;
sd1.name = "ww";
sd1.age = 5;
sd1.height = 10.9;
// 3.先定义再初始化(一次性初始化)
struct Dog sd2;
// 特别注意: 结构体和数组有一点区别, 数组不能先定义再进行一次性的初始化, 而结构体可以
// 只不过需要明确的告诉系统{}中是一个结构体
sd2 = (struct Dog){"xq", 8, 8.8}; // 数组? 结构体?
// 4.指定将数据赋值给指定的属性
struct Dog sd3 = {.height = 1.77, .name = "ww", .age = 33};
printf("name = %s, age = %i, height = %lf\n", sd3.name, sd3.age, sd3.height);
return 0;
}
结构体的内存存储细节
int main(int argc, const char * argv[]) {
/*
// 1.定义结构体类型并不会分配存储空间
struct Person{
int age; // 4
int height; // 4
int width; // 4
};
// 2.只有定义结构体变量才会真正的分配存储空间
struct Person sp = {30, 1, 1};
// 结构体第0个属性的地址就是结构体的地址
printf("&sp = %p\n", &sp);
printf("age = %p\n", &sp.age);
printf("size = %lu\n", sizeof(sp));
// int nums[3] = {1, 3, 5};
// nums == &nums == &nums[0]
// 和数组一样, 结构体内存寻址从大到小, 存储数组是从小到大(先存储第0个属性, 再一次存储其它属性)
printf("height = %p\n", &sp.height);
printf("width = %p\n", &sp.width);
*/
/*
结构体如何开辟存储空间
看上去, 结构体分配存储空间是将所有属性占用的存储空间的总和加在一起后再分配
注意:
其实结构体分配存储空间本质上并不是将所有属性占用的存储空间的总和加在一起后再分配
而是会获取结构体类型中占用内存最大的属性的大小, 然后取该大小的倍数
特例:
如果剩余的存储空间"不够"存储将要存储的数据, 那么就会重新开辟8个字节的存储空间, 并且将需要存储的数据放到新开辟的存储空间中
如果剩余的存储空间"够"存储将要存储的数据, 那么就不会开辟了
*/
struct Person{
// double height; // 8
int age; // 4
// int heigth; // 4
double height; // 8
char c; // 1
// char *name; // 8
};
struct Person sp;
printf("size = %lu\n", sizeof(sp));
return 0;
}
结构体定义的方式
int main(int argc, const char * argv[]) {
// 1.先定义结构体类型, 在定义结构体变量
/*
struct Person
{
int age;
char *name;
double height;
};
struct Person sp;
*/
/*************************华丽的分割线*******************************/
// 2.定义结构体类型的同时定义结构体变量
/*
struct Person
{
int age;
char *name;
double height;
} sp;
// 数据类型 变量名称
sp.age = 30;
printf("age = %i\n", sp.age);
struct Person sp1;
sp1.name = "lnj";
printf("name = %s\n", sp1.name);
*/
/*************************华丽的分割线*******************************/
// 3.定义结构体类型的同时定义结构体变量, 并且省略结构体名称
// 如果在定义结构体类型的同时定义结构体变量, 那么可以省略结构体类型名称
// 弊端: 由于结构体类型没有名称, 所以以后就不能使用该结构体类型
// 优点: 如果结构体类型只需要使用一次, 那么可以使用该方式
struct
{
int age;
char *name;
double height;
} sp;
sp.age = 55;
printf("age = %i\n", sp.age);
return 0;
}
结构体类型的作用域
void test();
// 如果将变量写到函数或者代码块外面, 那么就不是局部变量, 而是全局变量
// 全局变量的作用域是从定义的那一行开始, 直到文件末尾 (暂时这样理解)
int num;
// 如果将结构体类型写在函数或者代码块外面, 那么结构体类型的作用域和全局变量一样, 从定义的那一行开始一直直到文件末尾
// 相同作用域不能有同名的结构体类型
struct Person
{
int age;
char *name;
double height;
};
int main(int argc, const char * argv[]) {
// int num = 10;
num = 10;
struct Person sp;
return 0;
}
void test()
{
num = 55;
struct Person sp1;
// num = 20;
}
/*
void demo()
{
struct Person
{
int age;
char *name;
double height;
};
int num = 10;
{
struct Dog
{
int age;
char *name;
};
struct Dog sd;
// 在不同的作用域中可以有同名的局部变量, 如果访问采用就近原则
int num = 50;
printf("num = %i\n", num);
// 在不同的作用域中可以定义同名的结构体类型 , 如果使用同名的结构体类型定义结构体变量, 采用就近原则
struct Person
{
int age;
char *name;
double height;
};
struct Person sp = {30, "lnj", 1.75};
}
// num = 55;
// struct Dog sd1;
struct Person sp;
}
void test()
{
// 1.如果结构体定义在函数或者代码块中, 那么结构体类型的作用域和变量的作用域一样, 从定义的那一行开始, 一直到函数结束或者到代码块结束
struct Person sp;
}
*/
指向结构体的指针
int main(int argc, const char * argv[]) {
struct Person
{
int age;
char *name;
double height;
};
struct Person sp = {30, "lnj", 1.75};
sp.name = "lnj";
sp.age = 30;
sp.height = 1.75;
// 定义了一个指向结构体的指针
// *sip == sp
struct Person *sip;
sip = &sp;
/*
// 注意: 报错的原因是因为.运算符的优先级比*高
(*sip).name = "xxx";
(*sip).age = 88;
(*sip).height = 1.95;
printf("age = %i, name = %s, height = %lf\n", (*sip).age, (*sip).name, (*sip).height);
*/
/*
sip->age = 99;
sip->name = "oooo";
sip->height = 2.1;
printf("age = %i, name = %s, height = %lf\n", sip->age, sip->name, sip->height);
*/
/*
如何定义指向结构体变量的指针
1.拷贝结构体类型 和 结构体变量名称
2.在类型和名称中间加上一颗心
当指针指向结构体之后如何利用指针访问结构体
结构体变量名称.属性;
(*结构体指针变量名称).属性;
结构体指针变量名称->属性;
*/
return 0;
}
结构体数组
int main(int argc, const char * argv[]) {
// 要求定义变量保存公司中所有部门的绩效
struct Bumen
{
char *name;
int count;
double kpi;
};
struct Bumen ios = {"iOS", 20, 100.0};
struct Bumen andorid = {"Andoird", 10, 99.0};
struct Bumen php = {"php", 500, 88.0};
// 元素类型 数组名称[元素个数];
struct Bumen bumens[3] =
{
{"iOS", 20, 100.0}, // 0
{"Andoird", 10, 99.0},
{"php", 500, 88.0}
};
// bumens[0] == ios
bumens[0].name = "iOSv587";
bumens[0].count = 99;
bumens[0].kpi = 100.0;
printf("name = %s, count = %i, kpi = %lf\n", bumens[0].name, bumens[0].count, bumens[0].kpi);
return 0;
}
结构体的嵌套定义
int main(int argc, const char * argv[]) {
/*
struct Person
{
int age; // 年龄
char *name; // 姓名
// 出生日期
int year;
int month;
int day;
// 初始化时晨
int HH; // 24小时
int mm; // 分钟
int ss; // 秒钟
// 入学时间
int year2;
int month2;
int day2;
// 毕业时间
int year3;
int month3;
int day3;
};
struct Person sp = {30, "lnj", 1986, 1, 15 , 15, 20, 8};
*/
// 定义一个时间结构体类型
struct Time
{
int HH;
int mm;
int ss;
};
struct Date
{
int year;
int month;
int day;
struct Time time;
};
struct Person
{
int age;
char *name;
// 出生日期
struct Date birth;
// 出生时间
// struct Date time;
// struct Time shic;
// 小学入学时间
struct Date ruxue;
// 小学毕业时间
struct Date biye;
// ....
};
struct Person sp =
{
30,
"lnj",
{
1980,
1,
15,
{
15,
12,
8
}
},
{
1990,
6,
9
},
{
1996,
9,
5
}
};
// 注意: 如果结构体的属性又是一个结构体, 那么可以通过连续.的方式, 访问结构体属性中的属性
// 如果结构体类型中的属性又是一个结构体, 那么赋值时候通过{}赋值
printf("year = %i, month = %i, day = %i\n", sp.birth.year, sp.birth.month, sp.birth.day);
return 0;
}