爬爬爬之路:C语言(九) 结构体指针与预编译指令

结构体指针

结构体是一种自定义的数据类型
结构体的指针和基础数据类型差不多 结构体变量名不能当成它的首元素地址 需要用取地址符获得结构体变量的地址, 但是结构变量的地址就相当于指向结构体变量的第一个成员变量的地址

如以下代码演示:

typedef struct {
     char name[50];
     char gender[10];
     int age;
     float score;
} Student;
Student student = {“xiaoming”, “nan”, 10, 55.0};
Student *p = &student;

用结构体获取成员变量的方法:(点方法)
student.name

用指针获取结构体变量里的成员变量方法(常规)
(*p).name

结构体指针特有的取成员变量方法( -> 指向符)
p -> name // 地址指向成员变量

结构体指针加一, 相当于加了一个整个的结构体的字节数


结构体数组与指针

先创建一个结构体数组

Student stus[3] = {0};
Student *p = suts;
printf(“%p\n”, p);
printf(“%p\n”, &stus[0]);

结构体指针指向结构体数组, 就相当于指向结构体数组的首元素

如何利用指针 取出数组中的元素?
请看以下代码:

void printStudent(Student *stu) {
    printf("姓名:%s\n", stu->name);
    printf("性别:%s\n", stu->gender);
    printf("年龄:%d\n", stu->age);
    printf("成绩:%.2f\n", stu->score);
}
void printStudents(Student *stu, int count) {
    for (int i = 0; i < count; i++) {
        printStudent(stu + i);
        printf("\n");
    }
}

在main函数中调用如下:

Student stu1 = {"zhangsan", "nan", 18, 88.0};
    Student stu2 = {"xiaoming", "nv", 19, 90.0};
    Student stu3 = {"lisi", "nan", 22, 60.0};
    Student stus[] = {stu1, stu2, stu3};
    Student *s = stus;
    printStudents(s, 3);

定义一个指针指向结构体数组的地址, 通过 s + i 可以实现指向数组第i个元素
使用语法 *(s + i)可以将数组第i个元素取出


预编译指令

1. 宏定义

宏定义是替换的过程
#define 替换前的名字 替换后的名字 (把前者替换成后者)
比如代码#define PI 3.14
作用是将代码中所有的PI 替换成 浮点数3.14

2. 带参数的宏定义

#define MaxValue(A,B) A > B ? A : B
比如此段代码就是一个典型的带参数的宏定义, 作用是计算两个数之间的最大值. 值得注意的是, 这么写可以使得替换语句 A > B ? A : B中的变量A,B随着参数中的A,B一同被替换,替换的元素为主函数中输入的实参

  • 必须得注意形参 和替换语句中的变量名必须相同, 否则起不到一同替换的作用.
    比如写成
    #define MaxValue(A,B) a > b ? a : b
    就会可能导致程序出现错误
    这时替换语句中的变量不会随着形参A,B一同被替换, 而是永远被替换成
    a > b ? a : b
    若此时主程序中的变量名不是a, b则会导致程序报错

  • 这里还值得注意的一点是:宏定义是一个替换的过程.它没有函数那么”智能”, 它只会生硬的替换出现的元素.
    比如说, 预编译这段代码
    #define MulValue(A,B) A * B
    若是在主程序中这么调用:
    MulValue(3 + 5, 6)
    那么会被系统替换成 3 + 5 * 6
    结果计算为33
    显然结果并不是我们想要的48.
    所以得注意, 此时需要加上一个括号:
    MulValue((3 + 5), 6)
    这样结果就被替换成 (3 + 5) * 6
    结果计算为48.

  • 宏定义的通用命名规范:

    1. 命名宏定义的时候, 在前面加一个小写字母k, 后面用驼峰命名法命名宏定义
      #define kMaxValue(A,B) A > B ? A : B
      这么写可以让你在代码提示中快速找到自己宏定义的代码.
    2. 全部大写
      #define self.window.size.bounds.height HEIGHT
    3. 以上两种宏定义的方式均有利于快速查找代码

3. 条件编译 (写在main函数里的)

  • 条件编译模式1
#ifdef XY
    printf("XY这个宏定义, 已经定义了")
#else
    printf(“XY这个宏定义 还没定义");
#endif

应用场景

#ifdef PI  // 如果定义过PI
#define AERS(R) PI*(R)*(R)  // 进行宏替换
#else // 如果没有定义过`
#define AERS(R) 3.14*(R)*(R) // 用另一种宏替换
#endif
  • 条件编译模式2
#ifndef PI
    printf("这个PI, 还没定义过")
#else
    printf(“这个PI, 已经定义过了");
#endif

与条件编译模式1的意思正好相反

  • 条件编译模式3
#if 常量表达式
    代码段1
#else
    代码段2
#endif

如果常量表达式结果非0 编译器编译代码段1, 否则编译代码段2
在上线和测试两个阶段切换的时候会经常用到

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值