C语言 结构体指针强制转换
来源:互联网 发布:原装ubuntu的电脑 编辑:程序博客网 时间:2024/06/05 05:51
最近写c程序遇到的结构体指针强转的坑,记录一下.
是一个简单的菜单程序,程序用到链表,表中存储了9个不同命令.每次将用户输入的命令与表中存储的命令名作对比(遍历查询),然后执行相应功能.
总体结构:
linktable.h:定义通用模块化链表数据结构,以及相关操作linktable.c:实现头文件中定义的链表操作main.c:主函数
通用链表节点:(抽象定义)
typedef struct LinkTableNode{ struct LinkTableNode *pNext;//只有后继指针}tLinkTableNode;
链表:
typedef struct LinkTable{ tLinkTableNode *pHead;//表头 tLinkTableNode *pTail;//表尾 int SumOfNode;//节点数 pthread_mutex_t mutex;//互斥锁}tLinkTable;
数据节点:(通用链表的具体化)
typedef struct DataNode{ char* cmd;//命令名 char* desc;//命令描述 int (*handler)();//函数指针,指向具体功能函数 struct DataNode *pNext;//后继指针}tDataNode;
main.c片段:
tDataNode * FindCmd(tLinkTable *head, char *cmd)//函数:遍历链表head,查找与cmd符合的命令并返回该数据节点{ tDataNode *pNode = (tDataNode*)getLinkTableHead(head); while(pNode != NULL) { if(strcmp(pNode->cmd, cmd) == 0) { return pNode; } pNode = (tDataNode*)getNextLinkTableNode(head, (tLinkTableNode*)pNode); } return NULL;}//对数据节点赋值,注意每个字段的摆放顺序要与定义的格式相匹配static tDataNode menu[] = { {"version", "menu program v2.5",NULL,(tLinkTableNode*)&menu[1]}, {"help", "this is help cmd!", Help,(tLinkTableNode*)&menu[2]}, {"add", "this is add cmd!", Add, (tLinkTableNode*)&menu[3]}, {"sub", "this is sub cmd!", Sub, (tLinkTableNode*)&menu[4]}, {"mul", "this is multi cmd!", Multi, (tLinkTableNode*)&menu[5]}, {"div", "this is divide cmd!", Divide, (tLinkTableNode*)&menu[6]}, {"pow", "this is power cmd!", Power, (tLinkTableNode*)&menu[7]}, {"time", "this is time cmd!", Time, (tLinkTableNode*)&menu[8]}, {"quit", "this is quit cmd", Quit, (tLinkTableNode*)NULL} };//初始化,创建链表体,并把头尾分别指向menu[0]和menu[8]int InitMenuData(tLinkTable **ppLinkTable){ *ppLinkTable = CreateLinkTable(); (*ppLinkTable)->pHead = (tLinkTableNode*)&menu[0]; (*ppLinkTable)->pTail = (tLinkTableNode*)&menu[8]; (*ppLinkTable)->SumOfNode = 9; return SUCCESS;}tLinkTable *head = NULL;int main(){ InitMenuData(&head);//将链表体指针head初始化 printf("Welcome!Use 'help' to get how to use this system.\n"); while(1)//无限循环 { char cmd[CMD_MAX_LEN]; printf("input a cmd >"); scanf("%s", cmd);//读取用户输入命令 tDataNode *p = FindCmd(head, cmd);//查找 if(p == NULL)//若找不到,提示错误 { printf("Wrong cmd!Use 'help' to get how to use this system.\n"); continue; } printf("%s ---- %s\n", p->cmd, p->desc);//输出该命令信息 if(p->handler != NULL) { p->handler();//调用该命令的功能函数 } }}
看起来没有什么问题,运行,崩溃.进入调试,发现原因在于main片段的第11行
pNode = (tDataNode*)getNextLinkTableNode(head, (tLinkTableNode*)pNode);
getNextLinkTableNode的功能是返回链表head中pNode节点的下一个节点.这里对参数pNode(第4行创建为tDataNode*类型)进行强制转换成tLinkTableNode *类型.
然而我们知道,强制转换是有可能出问题的,这就是问题所在.tLinkTableNode是一个通用的链表节点类型,其中只包含一个后继域 pNext,而tDataNode包含了四个成员:两个char数组指针cmd和desc,还有函数指针handler和后继pNext.如此一来强转必然出问题.
执行第11行前,调试的信息如图所示:
pNode的类型为tDataNode*,其cmd字段为0x406070(“version”),pNext字段为0x405030
进入11行后,调试信息发生如下变化:
pNext类型为tLinkTableNode*,其中pNext字段为0x406070.是不是很熟悉?没错,就是强制转换之前的cmd字段内容.也就是说,pNext本该指向0x405030,却因为强制转换而变成了0x406070.而这是一个未知的地址,也就是常说的”指针乱指”,如此一来发生错误是必然的!
可以看到,结构体数组的地址都是非常规整的,他们彼此相邻,每个结构体占0x10的地址空间,然而由于指针乱指到未知的地址0x406070,进入该地址后,pNext继续乱指到0x73726576.再进入这个地址,读取其cmd字段,系统报告发生段错误,程序终止.
那么正确的做法是什么呢?观察强制转换的内容,可以发现强转成tLinkTableNode*后,pNext的内容为tDataNode *的cmd内容,也就是定义结构体中的第一个字段,要想保持强转后不丢失后继指针,只有在定义结构体时将后继指针调整到第一个字段:
typedef struct DataNode{ struct DataNode *pNext; char* cmd; char* desc; int (*handler)();}tDataNode;
同时对结构体数组赋值时也要注意顺序的调整,把后继指针的赋值放在第一位:
static tDataNode menu[] = { {(tLinkTableNode*)&menu[1],"version", "menu program v2.5",NULL}, {(tLinkTableNode*)&menu[2],"help", "this is help cmd!", Help}, {(tLinkTableNode*)&menu[3],"add", "this is add cmd!", Add}, {(tLinkTableNode*)&menu[4],"sub", "this is sub cmd!", Sub}, {(tLinkTableNode*)&menu[5],"mul", "this is multi cmd!", Multi}, {(tLinkTableNode*)&menu[6],"div", "this is divide cmd!", Divide}, {(tLinkTableNode*)&menu[7],"pow", "this is power cmd!", Power}, {(tLinkTableNode*)&menu[8],"time", "this is time cmd!", Time}, {(tLinkTableNode*)NULL,"quit", "this is quit cmd", Quit} };
这样程序才能正常运行
- C语言 结构体指针强制转换
- c语言结构体强制转换
- C语言中不同的结构体类型的指针间的强制转换详解
- C语言中不同的结构体类型的指针间的强制转换详解
- C语言中不同类型的结构体的指针间可以强制转换
- c中结构体指针的强制类型转换
- C语言指针强制类型转换
- C语言指针强制类型转换
- C语言指针强制类型转换
- C语言指针强制类型转换
- c语言指针的强制转换
- C语言指针强制类型转换
- C语言: 指针强制类型转换
- C语言指针强制类型转换
- C语言指针强制类型转换
- C语言指针强制类型转换
- C语言指针强制类型转换
- C语言指针强制类型转换
- 1091 线段的重叠
- 详解C语言中的stdin,stdout,stderr
- 探讨世界的本原是什么
- Servlet入门经验
- Warm up 【tarjan 求EBC+求桥+缩点+树的直径】
- C语言 结构体指针强制转换
- JDBC
- Vue---组件 初步
- Python Click使用命令行短参数(short option)
- Android 自定义View(一)----------------TabBar 实现
- 实现一个栈,push、pop、求栈中最小值min的时间复杂度为O(1)
- android问题解答
- 一次假装不正经的开始
- php获取浏览器的名称,及版本号