结构体指针
//定义:指向结构体的指针叫做结构体指针
//定义一个结构体指针变量
Student stu1 = {
"ZSY",
1100322,
25,
98.5
};
//Student * 是结构体指针类型,p是结构体变量名,&stu结构体变量存储的地址
Student *p1 = &stu1;
//p存储的是结构体第一个变量成员的地址
//结构体的空间大小,结构体指针空间大小
printf("stu1 = %lu, *p = %lu", sizeof(stu1), sizeof(p1));
printf("\nstu1 = %p\nstu1.name = %p\nstu1.number = %p\nstu1.age = %p\nstu1.score = %p\n", &stu1, stu1.name, &stu1.number, &stu1.age, &stu1.score);
//结构体指针访问成员
stu1.age = 19;
//(*p)对指针取值后是结构体变量 .age是访问成员变量,使用指针可以直接访问结构体成员,使用->操作
(*p1).age = 17;
//用(*p)形式访问并输出结构体变量成员
printf("age = %d\n", (*p1).age);
p1->age = 117;
printf("age = %d", p1->age);
//通过结构体指针的两种方式访问变量成员
printf("name = %s\nnumber = %d\nage = %d\nscore = %f", (*p1).name, (*p1).number, (*p1).age, (*p1).score);
printf("name = %s\nnumber = %d\nage = %d\nscore = %f\n", p1->name, p1->number, p1->age, p1->score);
//结构体指针p++与++p访问结构体变量成员
printf("%.2f\n", p1->score++);
printf("%.2f\n", ++p1->score);
//定义一个Pointer结构体指针变量
CPoint m = {0.1, 1.5};
CPoint n = {6.0, 8.0};
CPoint *cp1 = &m;
CPoint *cp2 = &n;
//求绝对值函数:fabsf()
float x = fabsf(cp1->x - cp2->x);
float y = fabsf(cp1->y - cp2->y);
//开平方函数:sqrt()
printf("%.2f\n", sqrt(x * x + y * y));
//输出
printf("m = %.2f, n = %.2f, cp1 = %.2f\n", cp1->x, cp1->y, sqrt(cp1->x * cp1->x + cp1->y * cp1->y));
printf("m = %.2f, n = %.2f, cp2 = %.2f\n", cp2->x, cp2->y, sqrt(cp2->x * cp2->x + cp2->y * cp2->y));
练习
//使用结构体指针将结构体变量中的name的首字母变为大写
Student stu = {"lan ou", 110032, 25, 96.5};
Student *p = &stu;
//将name首字母大写
p->name[0] = stu.name[0] - 32;
printf("%s\n", stu.name);
//改空格变_
int i = 0;
while (stu.name[i] != '\0') {
if (stu.name[i] == ' ') {
stu.name[i] = '_';
}
i++;
}
printf("%s\n", stu.name);
结构体数组与指针的关系
//定义一个结构体数组变量stus[3]
Student stus[3] = {
{"ZSY", 'M', 25, 89.5},
{"XDL", 'W', 34, 59.5},
{"YBQ", 'M', 24, 88.0}
};
//定义一个结构体指针*SM,将数组的首地址付给结构体指针变量SM
Student *SM = stus;
//计算结构体指针 结构体数组 结构体数组元素地址
printf("%lu\n", sizeof(stus[0]));
printf("%lu\n", sizeof(SM));
printf("%lu\n", sizeof(*SM));
printf("%lu\n", sizeof(stus));
//观察结构体数组名和结构体第一个元素地址
printf("%p\n", stus);
printf("%p\n", &stus[0]);
//使用结构体指针访问结构体变量只能用 -> 运算符
printf("%s, %c, %d, %.2f\n", SM->name, SM->gender, SM->age, SM->score);
printf("%s, %c, %d, %.2f\n", (SM + 1)->name, (SM + 1)->gender, (SM + 1)->age, (SM + 1)->score);
printf("%s, %c, %d, %.2f\n", (SM + 2)->name, (SM + 2)->gender, (SM + 2)->age, (SM + 2)->score);
//使用数组下标指针访问结构体变量只能使用 . 运算符
printf("\n%s, %c, %d, %.2f\n", SM[0].name, SM[0].gender, SM[0].age, SM[0].score);
printf("%s, %c, %d, %.2f\n", SM[1].name, SM[1].gender, SM[1].age, SM[1].score);
printf("%s, %c, %d, %.2f\n", SM[2].name, SM[2].gender, SM[2].age, SM[2].score);
//输出
printf("%s\n", stus[0].name);
printf("%s\n", stus->name);
printf("%s\n", (*stus).name);
printf("%s\n", SM->name);
printf("%s\n", SM[0].name);
printf("%s\n", (*(SM + 1)).name);
练习
//输出结构体数组中的元素,如果是男性,分数+1, 超过100分的按100分计算
Student stus[3] = {
{"ZSY", 'M', 24, 90.0},
{"XDL", 'W', 34, 59.5},
{"BK", 'M', 23, 95.0}
};
Student *p = stus;
JudgeScore(p);
//JudgeScore.m中实现代码
//输出结构体数组中的元素,如果是男性,分数+1, 超过100分的按100分计算
void JudgeScore(Student *stu) {
for (int i = 0; i < 3; i++) {
//如果为男性
if ((*(stu + i)).gender == 'M') {
(*(stu + i)).score += 10;
}
//如果分数超过100
if ((*(stu + i)).score >= 100) {
//那么标记为100
(*(stu + i)).score = 100;
}
}
//输出
for (int i = 0; i < 3; i++) {
printf("Name = %s, Gender = %c, Age = %d, Score = %.2f\n", (*(stu + i)).name, (*(stu + i)).gender, (*(stu + i)).age, (*(stu + i)).score);
}
}
预编译指令
宏:预编译时进行替换(编译前)
//命名规则:全部大写 或 k + 驼峰
//无参宏
#define PI 3.1415926
//有参宏:多加括号体现优先级
#define SUM(A , B) (A) + (B)
//注意:调用有参宏时候如果不加括号,在算数运算符中不会体现优先级概念
int num = MUL(5 + 1, 2);
printf("%d\n", num);
//宏与函数的区别:
//1.宏会在编译器在对源代码进行编译时进行替换,只是简单的替换,不会进行任何逻辑检测,即简单的代码复制而已,运行速度比函数快。
//2.宏定义时不会考虑参数的类型
//3.参数宏的使用会使具有同一作用的代码块在目标文件中存在多个副本,增加文件大小。
//4.函数只在目标文件存在一处,节省空间
//5.参数宏定义时要多加小心,多加括号
//6.函数的参数存在传值与传址的问题,而宏不存在
条件编译:3种形式
//形式一
#ifdef PI
printf("PI being redefined\n");
#else
printf("PI not being redefined\n");
#endif
//形式二
#ifndef PI
printf("PI not being redefined\n");
#else
printf("PI being redefined\n");
#endif
//形式三
#if 0
printf("Is true\n");
#else
printf("Is fake\n");
#endif