C 奇数空指针行为
我正在尝试使用链表实现堆栈。我的堆栈构造函数C 奇数空指针行为,c,pointers,linked-list,C,Pointers,Linked List,我正在尝试使用链表实现堆栈。我的堆栈构造函数createStack()创建一个空(虚拟)元素,并返回指向该元素(堆栈顶部)的双指针。我的push()方法检查堆栈是否有伪元素;如果它这样做,它将填充虚拟对象并返回,否则它将为新元素分配内存并执行必要的指针更新 我的问题是,我的*堆栈->下一个指针显然指向了NULL(0x0),两行之后它不等于NULL(0x17),但不知何故通过了NULL测试。在调用内部,它再次等于(0x17),但这次它没有通过NULL测试,这是应该的 所以我的问题是,这个指针到底是
createStack()
创建一个空(虚拟)元素
,并返回指向该元素(堆栈顶部)的双指针。我的push()
方法检查堆栈是否有伪元素;如果它这样做,它将填充虚拟对象并返回,否则它将为新元素分配内存并执行必要的指针更新
我的问题是,我的*堆栈->下一个指针显然指向了NULL(0x0)
,两行之后它不等于NULL(0x17)
,但不知何故通过了NULL
测试。在调用内部,它再次等于(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
暂时忘记您正在使用指针和指向指针的指针,假设您的createStack()
例程如下所示:
int *createInt() {
int dummy = 1;
return &dummy;
}
函数在堆栈上为局部变量dummy
分配(临时)空间,为其赋值,然后返回指向它的指针。这正是createStack()
所做的,只是dummy
恰好是一种更复杂的数据类型
问题在于,当函数返回并从堆栈中弹出其局部变量时,分配给dummy
本身的内存被释放。因此,该函数返回一个指向可重用内存的指针。然后,当数据在后续函数调用期间从堆栈中推送和弹出时,它可以(并且确实)更改。当该函数返回时,createStack()
中的变量dummy
不再存在-因此返回的指针指向不再存在的变量
这就是为什么您会看到奇怪的行为-printf()
很可能在以前包含dummy
的内存上进行写入,因此当您尝试通过悬挂指针检查该内存时,您会看到它意外地改变
您可以通过更改createStack()
以返回struct元素*
值来修复代码:
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()
可以保持不变):
在createStack
函数中,您将返回导致未定义行为的局部变量的地址:
struct Element** createStack() {
struct Element *dummy = malloc( sizeof( struct Element ) );
...
struct Element **stack;
stack = &dummy;
return stack;
}
相反,您只需在main中有一个指向struct元素的指针
,并从createStack
函数返回指向新创建节点的指针:
struct Element *stack = createStack();
push ( &stack, 1000 );
并将指针堆栈的地址传递给ush
函数:
struct Element *stack = createStack();
push ( &stack, 1000 );