C语言中&与*运算符使fread()成功的原因及报错疑问
问题解析:为什么
&(*list)->books正常,list->books报错? 这个问题的核心是运算符优先级和指针层级的混淆,咱们一步步拆解:
1. 先明确你的类型定义
根据错误提示,LISTNODEPTR是struct listnode *的别名,我推测你的代码里list是一个二级指针(也就是LISTNODEPTR *,等价于struct listnode **)——这在链表操作里很常见,比如传入头指针的指针来修改链表头部。
2. 分析第一个正确的代码:&(*list)->books
咱们按运算符优先级来拆解执行顺序:
- 优先级从高到低:
()>->>*>& - 第一步:
*list——解引用二级指针list,得到struct listnode *(也就是LISTNODEPTR类型的指针,指向实际的结构体节点)。 - 第二步:
(*list)->books——通过->访问这个结构体节点的books成员(->的左边是合法的结构体指针,完全符合语法要求)。 - 第三步:
&(*list)->books——取books成员的地址,作为fread的第一个参数(fread需要void*类型的目标地址,完全匹配)。
这里你觉得*和&会相互抵消是误解,它们作用在不同的层级:*是解引用二级指针得到结构体指针,&是取结构体成员的地址,两者没有抵消关系。
3. 分析报错的代码:list->books
同样看运算符优先级:->的优先级远高于*(但这里你没写*),编译器会直接解析:
list的类型是LISTNODEPTR *(struct listnode **),也就是一个指向结构体指针的指针。- 当你写
list->books时,编译器认为你要通过->访问list所指向对象的books成员,但list指向的是struct listnode *(一个纯指针),而指针类型不是结构体或 union,自然无法用->访问成员——这就是错误提示的含义:Member reference base type 'LISTNODEPTR' (aka 'struct listnode *') is not a structure or union.
4. 怎么简化写法?
如果你想简化第一个代码,正确的等价写法是:
// 利用 (*ptr).member 和 ptr->member 等价的特性 fread(&((*list).books), sizeof(struct NOVEL), 1, fpread);
如果books本身是指针类型(比如struct NOVEL *books;),那你可能不需要&,但根据你的第一个代码正常运行,说明books是struct NOVEL类型,所以必须传递它的地址给fread。
总结一下:别被*和&的表面关系迷惑,重点看运算符优先级和指针的层级——二级指针必须先解引用得到结构体指针,才能用->访问结构体成员。
内容的提问来源于stack exchange,提问作者Dylan N.
相关产品推荐
相关产品推荐

