最近,我在看linux的内核源码,里面使用大量的结构体类型定义、结构体类型变量定义、结构体指针变量、结构体内部成员等元素。其中,大量使用了结构体指针变量访问结构体内部成员的"箭头运算符->",以及使用结构体变量名访问结构体内部成员的"点号运算符."。两者的相似点:都是实现了结构体变量内部成员的读写访问。不知道大家有没有这样的疑问,利用指针变量解引用符号"*"和"点号"运算符就能实现结构体变量内部成员的读写访问,为什么还要发明一个"箭头符号->"呢?
也就是说:
p->member;不是应该写成(*p).member吗,为什么还要发明箭头运算符"->"呢?
答案:
(1)p->member等效于(*p).member,两者是完全一致的,也就说箭头运算符->等效于解引用+点号运算符。
(2)c语言之所以发明"->"箭头运算法是为了让代码看以来更简便,更易读,避免了括号()加解引用运算符(*)的使用繁琐。
(3)箭头运算符"->"本身就有指针指向的含义,左侧的变量值表示首地址,右侧的变量表示要访问的结构体成员变量,"箭头运算法"本身代表"指针(地址)寻址思想"。点号运算符"."在汉语中有"的"含义,本身符合结构体这个大内存格子变量内部包含小内存格子结构体成员的含义,点号运算符左侧的变量为结构体变量,点号运算符右侧的变量为结构体成员变量,"点号运算符"本身代表父与子的关系。
扩展:暗含的索引思想
p->member;
str.member;
以上两种方式都是实现了结构体变量内部成员的读写访问,都暗含了一个非常重要的变成思维就是"线索或者索引"的概念。
无论是多么复杂的数据结构,都是从结构体的地址(其实暗含了结构体首元素的首地址,双首地址思想)为起始开始的。也就是俗称的"从头开始捋清楚"。只要是找到了这个地址"线头"就可以一步步使用"箭头运算法"或者"单号运算符"完成结构体内部成员的访问。
这种情况尤其是父结构体内部包含子结构体,子结构体又包含孙结构体, ...的情况,无论包含多少层结构体,都是从最外层父结构体或者结构体指针开始像"剥洋葱"一样一层一层的倒找内部成员,也暗含了"无法从内部结构体开始为"线索"实现结构体内部成员的访问"。