一、双重身份

如下定义了一个 School 结构体:

typedef struct School
{
int a;
int b;
}SCHOOL_S; SCHOOL_S stSch;

下面我们来输出一下 stSch 以及成员变量 a 和 b 的地址:

int main()
{
printf("stSch 的地址[%p]\n", &stSch);
printf(" a 的地址[%p]\n", &stSch.a);
printf(" b 的地址[%p]\n", &stSch.b); return 0;
}

输出结果如下:

有没有发现什么不得了的事情——结构体 school 的地址与第一个成员变量 a 的地址相同,也就是说变量 a 的地址既是 school * 类型,又是 int * 类型。脑海中突然冒出一个大胆的想法,如果我将 a 的地址强制类型转化为 SCHOOL_S * 类型呢:

int main()
{
stSch.a = 10;
stSch.b = 20; SCHOOL_S *pstSch = (SCHOOL_S *)&stSch.a;
printf("a = %d\n", pstSch->a);
printf("b = %d\n", pstSch->b); return 0;
}

输出结果如下:

Amazing~

二、妙用

通过上边的小测试,我们发现了 struct 的第一个成员变量的地址有双重身份,那么该如何使用呢?

对于两个不同的结构体:

typedef struct Teacher
{
char name[10]; /* 姓名 */
int id; /* 职工编号 */
}TEACHER_S; typedef struct School
{
char name[10]; /* 校名 */
int cnt; /* 教职工个数 */
}SCHOOL_S; SCHOOL_S school;
TEACHER_S teacher;
void Init()
{
strncpy(stSchool.name, "School", sizeof(stSchool.name) - 1);
stSchool.cnt = 1; strncpy(stTeacher.name, "Teacher", sizeof(stTeacher.name));
stTeacher.id = 1;
}

如何在得知 school 的情况下得到 teacher 的信息呢?你或许可以这么做:在 School 中新增 Teacher 的指针变量,使其指向 teacher。

typedef struct School
{
char name[10]; /* 校名 */
int cnt; /* 教职工个数 */
struct Teacher *pstTeacher; /* 【Add】指向 Teacher 的指针变量 */
}SCHOOL_S;
int main()
{
Init();
stSchool.pstTeacher = &stTeacher;
}

这也不失为一种方法,但怎么样才能用到第一个成员变量的「双重身份」这个信息呢?

下面让我们对结构体 School 和 Teacher 做个简单修改:

typedef struct List
{
struct List *next;
}LIST_S; typedef struct Teacher
{
LIST_S head; /* 【Add】单链表头结点 */
char name[10]; /* 姓名 */
int id; /* 职工编号 */
}TEACHER_S; typedef struct School
{
LIST_S head; /* 【Add】单链表头结点 */
char name[10]; /* 校名 */
int cnt; /* 教职工个数 */
}SCHOOL_S;
int main()
{
Init();
stSchool.head.next = &stTeacher.head; TEACHER_S *pstTeacher = (TEACHER_S *)stSchool.head.next; printf(" stTeacher 的地址为[%p]\n", &stTeacher);
printf("pstTeacher 的地址为[%p]\n", pstTeacher); return 0;
}

输出结果如下:

是不是很神奇~

C 语言 struct 第一个成员变量的妙用的更多相关文章

  1. C语言根据结构体成员变量的地址,得到结构体的地址

    看nginx代码时发现双链表使用的是这种方法,记录一下 给出一个实例来说明 struct father_t {    int a;    char *b;    double c;}f;char *p ...

  2. R语言学习 第一篇:变量和向量

    R是向量化的语言,最突出的特点是对向量的运算不需要显式编写循环语句,它会自动地应用于向量的每一个元素.对象是R中存储数据的数据结构,存储在内存中,通过名称或符号访问.对象的名称由大小写字母.数字0-9 ...

  3. Objective-C类成员变量深度剖析

    目录 Non Fragile ivars 为什么Non Fragile ivars很关键 如何寻址类成员变量 真正的“如何寻址类成员变量” Non Fragile ivars布局调整 为什么Objec ...

  4. Objective-C类成员变量深度剖析--oc对象内存模型

    目录 Non Fragile ivars 为什么Non Fragile ivars很关键 如何寻址类成员变量 真正的“如何寻址类成员变量” Non Fragile ivars布局调整 为什么Objec ...

  5. 【IOS 开发】Object - C 面向对象 - 类 , 对象 , 成员变量 , 成员方法

    . 一. 类定义 类定义需要实现两部分 : -- 接口部分 : 定义类的成员变量和方法, 方法是抽象的, 在头文件中定义; -- 实现部分 : 引入接口部分的头文件, 实现抽象方法; 1. 接口部分定 ...

  6. Java语言基础(六)char成员变量默认初始值 最简单的Java源文件 Java的main()方法

    ①char成员变量的初始值是:'\u0000' ②package用来指定该文件所处的包的名称,必须位于源文件的顶端. import java.util.*; package com.hyy.test; ...

  7. C语言中 struct成员变量顺序对内存的占用

    在C语言的结构体中,是会按照其变量类型来进行分配内存大小的.但是对于不同的编译器,结果是不同的,在VC++6.0中是怎么个分配情况呢?用一下C中的关键字sizeof()来测试下,注意sizeof()不 ...

  8. 【C语言探索之旅】 第一部分第四课第一章:变量的世界之内存那档事

    内容简介 1.课程大纲 2.第一部分第四课第一章:变量的世界之内存那档事 3.第一部分第四课第二章预告:变量的世界之声明变量 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答 ...

  9. java类中,成员变量赋值第一个进行,其次是静态构造函数,再次是构造函数

    如题是结论,如果有人问你Java类的成员初始化顺序和初始化块知识就这样回答他.下面是代码: package com.test; public class TestClass{ // 成员变量赋值第一个 ...

随机推荐

  1. openssl客户端编程:一个不起眼的函数导致的SSL会话失败问题

    我们目前大部分使用的openssl库还是基于TLS1.2协议的1.0.2版本系列,如果要支持更高的TLS1.3协议,就必须使用openssl的1.1.1版本或3.0版本.升级openssl库有可能会导 ...

  2. HMS Core音频编辑服务3D音频技术,助力打造沉浸式听觉盛宴

    2022年6月28日,HDD·HMS Core.Sparkle影音娱乐沙龙在线上与开发者们见面.HMS Core音频编辑服务(Audio Editor Kit)专家为大家详细分享了基于分离的3D音乐创 ...

  3. 多校联训 DP 专题

    [UR #20]跳蚤电话 将加边变为加点,方案数为 \((n-1)!\) 除以一个数,\(dp\) 每种方案要除的数之和即可. 点击查看代码 #include<bits/stdc++.h> ...

  4. pip安装报错Could not install packages due to an EnvironmentError: Missing dependencies for SOCK

    unset all_proxy && unset ALL_PROXY

  5. 使用OpenCv+Arduino实现挂机自动打怪

    使用OpenCv+Arduino实现挂机自动打怪 最近在玩某网游,练级十分枯燥和缓慢,就是挂机刷刷刷,所以研究一下自动化,找了个可以原地挂机刷怪的职业,然后用OpenCv检测技能冷却,冷却好了通过串口 ...

  6. [mybatis]mybatis日志的使用和分页功能的实现

    日志 Mybatis 通过使用内置的日志工厂提供日志功能.内置日志工厂将会把日志工作委托给下面的实现之一: SLF4J Apache Commons Logging Log4j 2 Log4j JDK ...

  7. Mybatis源码解读-SpringBoot中配置加载和Mapper的生成

    本文mybatis-spring-boot探讨在springboot工程中mybatis相关对象的注册与加载. 建议先了解mybatis在spring中的使用和springboot自动装载机制,再看此 ...

  8. 获取某个html元素相对于视窗的位置集合

    getBoundingClientRect() getBoundingClientRect()获取元素位置,这个方法没有参数 getBoundingClientRect()用于获得页面中某个元素的左, ...

  9. Java---注解与反射

    前言 近期在学习SSM框架的过程中发现在SSM框架中大量用到了反射与注解的知识,要想学好SSM框架,必须将注解与反射熟记于心,尤其是对Java反射机制的理解. 对于我这种记性不好的人来说"基 ...

  10. GP查询表状态常用SQL