使用结构体实现栈时出现C语言不兼容指针赋值错误
问题场景
用结构体实现栈时,出现一处不兼容指针类型赋值警告,提示:
Problem1.c:63:14: warning: assignment to ‘StackNode ’ from incompatible pointer type ‘StackNode * ()(int)’ [-Wincompatible-pointer-types]
63 | root = newNode;//inserting at the front of the stack, so make sure to set our root node to point to newNode
同时实际运行时,栈的压入、弹出操作都无法正常工作。
错误原因拆解
1. 变量与函数同名导致类型匹配错误
在newNode函数中,你定义了一个和函数名完全一样的局部变量StackNode* newNode。编译器在push函数的root = newNode;这行代码里,会优先把newNode解析成函数指针(类型是StackNode * (*)(int),即指向接收int参数、返回StackNode指针的函数的指针),而不是你刚创建的节点变量,这直接触发了类型不兼容的警告。
2. 指针值传递无法修改外部栈顶
push和pop函数的参数root是值传递,函数内部对root的修改只会作用于局部变量,不会影响main函数里的root指针。这就导致你压入的节点根本没被关联到栈上,弹出操作也无法改变栈的结构。
修复步骤
第一步:修正变量名冲突
把newNode函数里的局部变量改名,避免和函数名重复,同时修正push里的错误赋值:
// 修正后的newNode函数 StackNode* newNode(int data){ StackNode* node = (StackNode*)malloc(sizeof(StackNode)); // 变量名改为node if(node == NULL){ // 新增内存分配失败检查 printf("内存分配失败\n"); exit(EXIT_FAILURE); } node->data = data; node->next = NULL; return node; } // 修正后的push函数(先改变量名,后续再处理指针传递问题) void push(StackNode* root, int data){ StackNode* node = newNode(data); node->next = root; root = node; // 现在node是正确的节点指针,不会再和函数名混淆 }
第二步:用双重指针传递栈顶指针
要让函数能修改外部的root指针,必须把参数改成StackNode** root(指针的指针),这样函数内部可以直接操作外部指针的指向:
最终版push函数
void push(StackNode** root, int data){ StackNode* node = newNode(data); node->next = *root; // 新节点指向原来的栈顶 *root = node; // 修改外部的root指针,让它指向新栈顶 }
最终版pop函数
int pop(StackNode** root){ if(isEmpty(*root)){ return INT_MIN; } StackNode* temp = *root; int poppedData = temp->data; *root = (*root)->next; // 让外部root指向下一个节点,完成弹出 free(temp); // 释放旧栈顶内存 return poppedData; }
修改main函数中的调用
调用push和pop时,传入root的地址:
// 压入操作 push(&root, userInput); // 弹出操作循环修改为: while(root!=NULL){ printf("%d 已从栈中弹出\n", pop(&root)); }
完整修复后的代码
#include <stdio.h> #include <stdlib.h> #include <limits.h> //栈中每个节点的类型定义 typedef struct StackNode{ int data; struct StackNode* next; }StackNode; //函数原型声明 int isEmpty(StackNode*); int peek(StackNode*); int pop(StackNode**); void push(StackNode**, int); StackNode* newNode(int data); int main(){ int userInput = 0; int validInput = 1; StackNode *root = NULL; while(validInput){ printf("请输入要压入栈的值:"); scanf("%d", &userInput); if(userInput>=0){ push(&root, userInput); printf("%d 已压入栈\n", userInput);//打印压入栈的数据 }else{ break; } } while(root!=NULL){ printf("%d 已从栈中弹出\n", pop(&root)); } return 0; } int isEmpty(StackNode* root){ return !root; //NULL视为假,因此返回栈是否为空的结果 } //通过传入数据调用newNode函数创建新节点,将其压入栈顶 //传入根节点指针的指针以调整栈结构 void push(StackNode** root, int data){ StackNode* node = newNode(data); //根据数据创建新节点 node->next = *root;//在栈顶插入,使新节点指向原根节点 *root = node;//在栈顶插入,需将根节点指向新节点 } //移除栈顶节点并返回其存储的值,同时释放根节点内存 //传入根节点指针的指针以修改外部栈顶 int pop(StackNode** root){ if(isEmpty(*root)){ return INT_MIN; //因根节点不存在,返回最小整数 } StackNode* temp = *root; //创建临时节点指向根节点,以便后续释放 int poppedData = temp->data;//获取根节点存储的数据 *root = (*root)->next;//将根节点指向下一个节点 free(temp); //释放原根节点的内存 return poppedData; //返回弹出的数据 } //查看栈顶节点存储的数据但不移除该节点,传入根节点指针 int peek(StackNode *root){ if(isEmpty(root)){ return INT_MIN; //因根节点不存在,返回最小整数 } return root->data; //返回栈顶节点的数据 } //该函数根据传入的数据创建一个新的StackNode结构体,并返回指向该节点的指针 StackNode* newNode(int data){ StackNode* node = (StackNode*)malloc(sizeof(StackNode)); //为新栈节点分配内存 if(node == NULL){ printf("内存分配失败\n"); exit(EXIT_FAILURE); } node->data = data; //设置数据 node->next = NULL; //将下一个节点设为NULL return node; }
内容的提问来源于stack exchange,提问作者akaBryan

