我正在尝试使用链接列表在C上编写堆栈。我有CreateStack功能的问题。当我创建一个堆栈但是当我尝试创建另一个堆栈时,一切似乎都很好,程序就崩溃了。这是我的代码的一部分
#include <stdio.h>
#include <stdlib.h>
struct StackData{
int data;
struct StackData* prev;
struct StackPoint* point;
};
struct StackPoint{
struct StackData* basePointer;
struct StackData* stackPointer;
char exists;
};
int CreateNewStack(struct StackData** newPointer){
if((*newPointer)->point->exists=='Y') //i'm trying to check whether the list with the same adress has been already created and i think this is the part which causes error
return 1; //if error
else{
(*newPointer)=(struct StackData*)malloc(sizeof(struct StackData));
(*newPointer)->data=NULL;
(*newPointer)->prev=NULL;
(*newPointer)->point=(struct StackPoint*)malloc(sizeof(struct StackPoint));
(*newPointer)->point->basePointer=newPointer;
(*newPointer)->point->stackPointer=newPointer;
(*newPointer)->point->exists='Y';
return 0;
}
}
int main()
{
struct StackData *pointeris, *temp;
int state;
state=CreateNewStack(&pointeris); //state 0
state=CreateNewStack(&pointeris); //state 1
CreateNewStack(&temp); //crash
return 0;
}
答案 0 :(得分:0)
此代码包含编译器警告。
test.c:21:28: warning: incompatible pointer to integer conversion assigning to 'int' from 'void *'
[-Wint-conversion]
(*newPointer)->data=NULL;
^~~~~
test.c:24:42: warning: incompatible pointer types assigning to 'struct StackData *' from
'struct StackData **'; dereference with * [-Wincompatible-pointer-types]
(*newPointer)->point->basePointer=newPointer;
^~~~~~~~~~~
*
test.c:25:43: warning: incompatible pointer types assigning to 'struct StackData *' from
'struct StackData **'; dereference with * [-Wincompatible-pointer-types]
(*newPointer)->point->stackPointer=newPointer;
^~~~~~~~~~~
*
解决了这些问题后,立即解决了这个问题:
if((*newPointer)->point->exists=='Y')
*newPointer
可能为null。 *newPointer->point
可能是垃圾。 *newPointer->point->exists
可能是垃圾。
部分问题是CreateNewStack
实际上“如果堆栈尚不存在,可能会创建一个新堆栈”。如果将“创建新堆栈”与“创建新堆栈(如果它尚不存在”)分开,则代码将更加简单。实际上,每个结构都应该有自己的创建和销毁功能。
我也冒昧地为你的结构添加typedef。我已经从malloc
切换到calloc
以确保在创建时分配的结构为零。这意味着即使您忘记初始化每个成员,结构成员中也不会有任何垃圾。
typedef struct StackData {
int data;
struct StackData* prev;
struct StackPoint* point;
} StackData;
typedef struct StackPoint {
struct StackData* basePointer;
struct StackData* stackPointer;
char exists;
} StackPoint;
StackPoint *CreateStackPoint() {
StackPoint *point = calloc(1, sizeof(StackPoint));
point->exists = 'Y';
return point;
}
StackData *CreateStackData() {
StackData *data = calloc(1, sizeof(StackData));
data->point = CreateStackPoint();
data->point->basePointer = data;
data->point->stackPointer = data;
return data;
}
现在CreateNewStack
变为MaybeCreateStackData
并且更加简单。
int MaybeCreateStackData(StackData **maybeStack_p) {
if( maybeStack_p == NULL ) {
fprintf(stderr, "The stack double pointer cannot be null");
exit(1);
}
StackData *maybeStack = *maybeStack_p;
if( maybeStack && maybeStack->point && maybeStack->point->exists == 'Y' ) {
return 1;
}
else {
*maybeStack_p = CreateStackData();
return 0;
}
}
老实说,这个计划过于复杂。在C中,很难知道指针何时被正确初始化而不是指向随机存储器。您的exists
成员尝试解决此问题,但垃圾仍然可能会出现Y
。
相反,我放弃了整个想法,让调用者决定他们是否有一个有效的结构。现在您已经拥有了可靠的初始化函数,但是很少有人会初始化指针。