假设一个指针linkedList *p,用来指向struct LiskedListNode,怎样用P得到LinkedListNode的指针?谢谢!

2025-02-25 20:42:24
推荐回答(4个)
回答1:

翻译有点问题:p指向一个struct LiskedListNode对象的list数据成员,用p表示这个对象的地址。
首先要求出list在LinkedListNode中的地址偏移量:
(size_t)&(((struct LinkedListNode*)0)->list)
解释下:(struct LinkedListNode*)0)将0强制转化为LinkedListNode类型的指针(实际是NULL),这个LinkedListNode对象就是以0为首地址
(((struct LinkedListNode*)0)->list)就是list成员,加一个&就是list成员的地址,又因为这个对象的首地址为0,所以&(((struct LinkedListNode*)0)->list)也表示list的偏移地址,再转化为size_t,安全存储
size_t在stddef.h头文件中的定义为
typedef unsigned int size_t;
不转换为size_t一般没有问题。
设size_t q = (size_t)&(((struct LinkedListNode*)0)->list);
那么所求的地址为
struct LinkedListNode *r =(struct LinkedListNode*) ((size_t)p-q);
这里解释下,因为p是linkedList类型,那么p-1相当于减去1个单位的linkedList空间
而q是list的绝对偏移量,所以先把p和q的类型一致化。
也可以两步合并,直接求出:
struct LinkedListNode *s =(struct LinkedListNode*) ((size_t)p-(size_t)&(((struct LinkedListNode*)0)->list));

再者:((struct LinkedListNode*)0)->list,编译器不会生成访问list的代码,因此避免了用NULL指针访问内存。
更一般的方法:
(size_t)&(((LinkedListNode*)kkkk)->list) - (size_t)kkkk
这里kkk可以是任意数字,就是在内存的任意地方虚拟出一个对象

回答2:

改变一下定义成员的顺序就可以解决问题!!!

//由于不同编译器可能会有不同字节对齐方式
//所以下面的结构不方便由linkedlist*p 得到LinkedListNode的数据
struct LinkedListNode{
int data_1;
...
struct llinkedlist ist;
...
int data_n;
}

解决方案:

//但如果像这样定义:(这种方式可在一些源代码中见到)
struct LinkedListNode{
struct llinkedlist list; //放在开始 使它的地址等于LinkedListNode对象的地址
int data_1;
...
int data_n;
};

struct LinkedListNode* pNode = (struct LinkedListNode*)p; //是可以容易实现的
//因为list的地址就是LinkedListNode对象的开始地址了!

回答3:

这好像是要用到void指针,我不是很确定,思想差不多
(void *)q->list就是list(指针p)在结构体内的偏移地址(相对结构体的地址),因为void指针的地址为0?
根据大小端不同的存储方式结果如下:
大端:p-(void*)q->list;
小端:p+(void*)q->list;
大小端可能会反掉,我忘了

回答4:

翻译的有点问题,解决方法不一定是绝对的,你可以通过P所指向的地址计算出LinkedListNode的地址。因为像这种结构在分配数据空间的时候使用malloc,放在堆里面,是一段连续的空间(我说的'不一定'就是需要这个前提)。