我完全失去了。我觉得这里肯定会有一些明显的,愚蠢的错误,我的眼睛太累了,看不到它。我真的很感激任何帮助。
当我运行testProb2时,程序打印“Pushing:”然后在下一行“Segmentation fault”。我觉得这很奇怪,因为接下来就是printf(“Pushing:\ n”);是对printf的另一个调用,只传递了一个静态参数,没有任何动态可以在其他方法中做出奇怪的疯狂事情,但是“1”却没有打印出来。
我将printf的调用1和2放在那里作为测试,因为我最初认为问题可能出现在我的第一个for循环中,现在已经注释掉了,但事实并非如此。正如我所说的,我认为问题出现在testProb2.c中,但我在其下面包含了stackli.h和stackli.c以防万一。我用“gcc -ansi stackli.c testProb2.c -o testProb2”编译它。
/* testProb2
*
* Demonstrates a stack implementation that allocates a number of nodes at creation of the stack
* rather than on each call to Push. All methods are O(1) except for GrowFreeList, which is O(n),
* and CreateStack, which is O(n) because it calls GrowFreeList, and possibly Push, which will be
* O(1) when called while there are empty nodes, but O(n) when called if there are not empty nodes.
*/
#include "stackli.h"
#include <stdio.h>
int main(void) {
Stack S;
int i;
S = CreateStack(8);
printf("Pushing:\n");
printf("1 ");
Push(1, S);
printf("2\n");
Push(2, S);
/*
for (i = 0; i < 10; i++) {
printf("%d...", i);
Push(i, S);
}
printf("]\n");
*/
printf("Popping:\n");
while (!IsEmpty(S)) {
printf("%d...", Top(S));
Pop(S);
}
printf("]");
DisposeStack(S);
}
/* stackli.h */
typedef int ElementType;
#ifndef _Stack_h
#define _Stack_h
struct Node;
struct StackRecord;
typedef struct Node *PtrToNode;
typedef struct StackRecord *Stack;
Stack CreateStack( int initialSize );
void GrowFreeList( Stack S );
int IsEmpty( Stack S );
int IsFull( Stack S ) ;
void MakeEmpty( Stack S );
void DisposeStack( Stack S );
void Push( ElementType X, Stack S );
ElementType Top( Stack S );
void Pop( Stack S );
#endif /* _Stack_h */
/* stackli.c */
#include "stackli.h"
#include "fatal.h"
#include <stdlib.h>
struct StackRecord {
PtrToNode ThisStack;
PtrToNode FreeNodes;
int Size;
};
struct Node {
ElementType Element;
PtrToNode Next;
};
/* O(n) instead of O(1) because it calls GrowFreeList which is O(n) */
Stack CreateStack(int initialSize) {
Stack S;
S = malloc( sizeof( struct StackRecord ) );
S->ThisStack = NULL;
S->FreeNodes = NULL;
S->Size = initialSize;
GrowFreeList(S);
return S;
}
/* O(n) function */
void GrowFreeList(Stack S) {
int i;
PtrToNode temp;
for (i = 0; i < S->Size; i++) {
temp = malloc( sizeof( struct Node) );
if (temp == NULL)
FatalError("Out of space!!");
temp->Next = S->FreeNodes;
S->FreeNodes = temp;
}
S->Size = S->Size * 2;
}
答案 0 :(得分:4)
问题出现在Push
的最后两行:
void Push( ElementType X, Stack S ) {
PtrToNode temp;
...
temp->Next = S->ThisStack->Next;
S->ThisStack = temp;
}
当您第一次拨打Push
时,ThisStack
字段为空。当您尝试取消引用它以访问其Next
字段时,您将遇到段错误。但是,由于堆栈的顶部位于ThisStack
,而不是ThisStack->next
,因此修复该问题将消除段错误。
void Push( ElementType X, Stack S ) {
PtrToNode temp;
...
temp->Next = S->ThisStack;
S->ThisStack = temp;
}
你在Pop
犯了同样的错误,这会导致你完全跳过第一个元素。 temp
的分配应该是这样的:
temp = S->ThisStack;
最后,您的Size
字段始终是错误的。似乎GrowFreeList
在调用时应该使堆栈的大小加倍,但是当您从CreateStack
调用它时,尽管Size
字段为8,但堆栈的实际大小为0 (在你的例子中)。结果是堆栈包含8个空闲节点,但其Size
字段为16.实际上,Size
字段将始终比初始大小的实际大小大。这不会导致任何问题,因为它仅用于确定要添加的数量,但修复很简单:从Size
调用GrowFreeList
后重置CreateStack
字段:< / p>
Stack CreateStack(int initialSize) {
Stack S;
...
S->Size = initialSize;
GrowFreeList(S);
S->Size = initialSize; // Reset size, since GrowFreeList changed it
return S;
}
答案 1 :(得分:2)
Okey doke ......我们走了:
您使用Stack S
初始化CreateStack(8)
。这会在结构中将ThisStack
设置为NULL
。那么你要做的第一件事就是调用Push(1,S)
来做...
temp->Next = S->ThisStack->Next;
KABOOM。您刚刚取消引用NULL
指针。
理想情况下,您希望熟悉使用调试器(gdb
)。这将让您逐步执行代码,看看它到底在哪里爆炸。
答案 2 :(得分:2)
正如其他人所说,您应该使用fprintf(stderr,...)
来打印调试消息。
您可以使用gdb查看问题所在,并查看内存中发生的情况。在编译时添加标志-g
以帮助在gdb中进行调试。
这是gdb给我的输出:
(gdb) r
Starting program: .../test
Pushing:
1 2
2
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400873 in Push (X=1, S=0x601010) at stackli.c:81
81 temp->Next = S->ThisStack->Next;
(gdb) bt
#0 0x0000000000400873 in Push (X=1, S=0x601010) at stackli.c:81
#1 0x0000000000400627 in main () at testprob2.c:20
(gdb) print temp
$1 = (PtrToNode) 0x601110
(gdb) print S->ThisStack
$2 = (PtrToNode) 0x0
错误发生在void Push( ElementType X, Stack S )
。
正如您在我们打印S->ThisStack
时所看到的那样,我们得到0x0
,即。 S->ThisStack
指向NULL
。当您取消引用S->ThisStack
以转到S->ThisStack->Next
时,您将遇到分段错误。
您可以为if (S->ThisStack == NULL)
添加支票。我不太确定你要创建堆栈结构的方式。
另请注意,这只是您的代码的一个问题,可能(并且很可能)有更多问题,但是您应该能够使用backtrace
({{1}使用gdb缩小它们的范围。命令,并打印到bt
而不是stderr
,以便您的输出不被缓冲。我不想为你做功课。
答案 3 :(得分:1)
关于冲洗的评论是正确的。问题出现在Push
的倒数第二行。您从未初始化ThisStack
,因此当您尝试访问其next
元素时,您会遇到段错误。顺便提一下,你的尺寸是关闭的,因为你在第一次填充它后加倍。最后,您应该尽量避免typedef
远离指针。很容易忘记什么是指针,什么不是。使堆栈成为完整的结构并声明指向它的指针。