我试图使用链表实现堆栈。我的堆栈构造函数createStack()
创建一个空(虚拟)Element
并返回一个指向该元素的双指针(堆栈顶部)。我的push()
方法检查堆栈是否有虚拟元素;如果是,它填充虚拟并返回,否则它为新元素分配内存并执行必要的指针更新。
我遇到的问题是我的*stack->next
指针显然指向了NULL (0x0)
,然后两行后它不等于NULL (0x17)
但是以某种方式通过了NULL
{1}}测试。在推送它的调用内部再次等于(0x17)
,但这次它未能通过NULL
测试。
所以我的问题是,这个指针到底发生了什么?它是如何/为何从(0x0)
更改为(0x17)
,如果它等于(0x17)
它是如何通过==NULL
测试的?
//main.c
int main () {
struct Element **stack;
stack = createStack();
printf("stack: %p\n", stack );
printf("*stack->next: %p\n", (*stack)->next );
if ( (*stack)->next == NULL )
printf("yes the pointer is null\n" );
printf("*stack->next: %p\n", (*stack)->next );
if ( (*stack)->next == NULL )
printf("yes the pointer is null\n" );
push ( stack, 1000 );
//stack.c
struct Element {
int value;
struct Element *next;
};
int push ( struct Element **stack, int el ) {
if ( (*stack)->next == NULL) {
// first element, fill dummy element and return
printf("first value: %i !", el);
(*stack)->value = el;
return 1;
}
printf("the pointer is not null\n");
struct Element *newElement = malloc( sizeof( struct Element ) );
if ( !newElement )
return -1;
newElement->value = el;
//add element to front of list
newElement->next = *stack;
//update pointer to new first element
*stack = newElement;
return 1;
}
struct Element** createStack() {
struct Element *dummy = malloc( sizeof( struct Element ) );
if (dummy == NULL )
printf("malloc failed...");
dummy->value = 99;
dummy->next = NULL;
struct Element **stack;
stack = &dummy;
return stack;
}
上面的代码产生以下输出:
stack: 0x7fff6c385ba8
*stack->next: 0x0
yes the pointer is null
*stack->next: 0x17
yes the pointer is null
the pointer is not null
答案 0 :(得分:3)
暂时忘记你正在使用指针和指针指向,并假设你的createStack()
例程看起来像这样:
int *createInt() {
int dummy = 1;
return &dummy;
}
该函数在堆栈上为局部变量dummy
分配(临时)空间,为其赋值,然后返回指向它的指针。这正是您的createStack()
所做的,只是您的dummy
恰好是更复杂的数据类型。
问题是当函数返回并从堆栈中弹出其局部变量时,释放分配给dummy
本身的内存。因此该函数返回一个指向可重用的内存的指针。然后它可以(并且确实)在后续函数调用期间从堆栈中推送和弹出数据时进行更改。
答案 1 :(得分:0)
当该函数返回时,dummy
中的变量createStack()
不再存在 - 因此您返回的指针指向一个不再存在的变量。
这就是为什么你看到奇怪的行为 - printf()
可能正在写入以前包含dummy
的内存,所以当你试图通过你的悬空指针检查那个内存时,你会看到它意外地改变了
您可以通过更改createStack()
以返回struct Element *
值来修复代码:
struct Element *createStack(void)
{
struct Element *dummy = malloc( sizeof( struct Element ) );
if (dummy == NULL )
printf("malloc failed...");
else {
dummy->value = 99;
dummy->next = NULL;
}
return dummy;
}
并将main()
更改为适合(push()
可以保持不变):
int main ()
{
struct Element *stack;
stack = createStack();
printf("stack: %p\n", stack );
printf("stack->next: %p\n", stack->next );
if ( stack->next == NULL )
printf("yes the pointer is null\n" );
printf("stack->next: %p\n", stack->next );
if ( stack->next == NULL )
printf("yes the pointer is null\n" );
push ( &stack, 1000 );
答案 2 :(得分:0)
在createStack
函数中,您将返回导致未定义行为的局部变量的地址:
struct Element** createStack() {
struct Element *dummy = malloc( sizeof( struct Element ) );
...
struct Element **stack;
stack = &dummy;
return stack;
}
相反,你可以在main中有一个指向struct Element
的指针,并从createStack
函数返回指向新创建的节点的指针:
struct Element *stack = createStack();
并将指针stack
的地址传递给ush
函数:
push ( &stack, 1000 );