2016-02-25 71 views
-2

我想使用链接列表在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

你自己做了什么调试?建议您在调试器中运行程序和/或添加更多调试打印语句以帮助您找到问题。这只是调试101. – kaylum

+0

在初始化之前使用具有自动存储持续时间的对象的值是未定义的行为。 – EOF

+0

此代码有许多编译器警告。打开'-Wall',重新编译并修复它们。然后查看您的问题是否消失或重新发布固定代码。 – Schwern

回答

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可能为空。 *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。相反,我会放弃整个想法,让调用者决定他们是否有一个有效的结构或不。现在你有了可靠的初始化函数,很少有人可能会有一个初始化不好的指针。