栈数据结构一般有三个属性,
typedef struct __stack{
stackItem *bottom; 栈底指针
stackItem *top; 栈顶指针(指向栈顶元素的下一个元素,地址已经在栈外)
int stackLength; 最大栈元素个数(分配栈空间使用)
}stack;
栈包含init,push,pop,getTop,destroy等几个操作
1、init过程
这个过程是建立空栈的过程,这里给栈底指针分配内存,然后使栈顶指针也指向这个地址,这样就建立了一个空栈。这同时也暗示,如何判断一个栈是否为空,只要判断s->bottom == s->top(s表示栈指针,即stack *s, 下同)即可。
2、push过程
把元素push进栈中,需要注意栈的上溢问题,即栈已经满的情况下,必须要重新分配内存,才可以进行push行为。
这里需要调用realloc函数给s->bottom重新分配内存。这里要注意realloc函数的使用,以下摘自C Library:
2.13.3.4 realloc
Declaration:
void *realloc(void *
ptr, size_t
size);
Attempts to resize the memory block pointed to by ptr that was previously allocated with a call to malloc
or calloc
. The contents pointed to by ptr are unchanged. If the value of size is greater than the previous size of the block, then the additional bytes have an undeterminate value. If the value of size is less than the previous size of the block, then the difference of bytes at the end of the block are freed. If ptr is null, then it behaves like malloc
. If ptr points to a memory block that was not allocated with calloc
or malloc
, or is a space that has been deallocated, then the result is undefined. If the new space cannot be allocated, then the contents pointed to by ptr are unchanged. If size is zero, then the memory block is completely freed.
On success a pointer to the memory block is returned (which may be in a different location as before). On failure or if size is zero, a null pointer is returned.
我们需要更大的内存,在调用realloc分配的过程中,如果系统在原来内存开始地址基础上,无法找到更大的连续内存,则会重新开辟一块内存,把现在内存里的东西复制过去,然后释放掉现在的内存,所以s->bottom的地址很可能会改变,所以需要先设一个变量
int distance = s->top - s->bottom;
来记住s->top相对于s->bottom的偏移量,然后重新分配后,再重新计算s->top的值。
同时记住,重新分配内存后,栈的属性stackLength也改变了。
3、pop过程
注意栈的下溢问题,即如果栈为空,则无法pop任何栈元素。
4、getTop
返回栈顶元素,注意s->top并非指向栈顶元素,s->top-1才指向栈顶元素。
5、destroy过程
只要将开辟的内存释放掉即可,实际上只要调用
free(s->bottom);
即可。不要犯下面的错误:
void destroy(stack *s){
stackItem *p = NULL;
printf("Begin to destroy stack.../n");
s->top = s->bottom + s->stackSize;
if(s->top != NULL){
p = s->top;
s->top--;
free(p);
p=NULL;
}
if(s->bottom != NULL)
free(s->bottom);
s->bottom = NULL;
s->top = NULL;
}
这里是想把栈的元素一个一个分别得释放掉,这有点类似销毁链表的思路,但是注意,链表结点的内存是分别开辟的,所以释放时,也需要分别释放,但是栈不同,它是一次性开辟,不够再重新开辟,而每次开辟就是一大块,可以容纳不止一个元素,所以注意区别。同时,也研究一下C Library对free函数的说明:
2.13.3.2 free
Declaration:
void free(void *ptr);
Deallocates the memory previously allocated by a call to calloc, malloc, or realloc.
The argument ptr points to the space that was previously allocated.
If ptr points to a memory block that was not allocated with calloc, malloc, or realloc,
or is a space that has been deallocated, then the result is undefined.
No value is returned.
所以free函数只能释放calloc, malloc或者realloc开辟的内存,其他形式开辟的内存无法通过free函数释放,所以上面的代码必将导致内存异常!
下面是实现代码:
以下是输出结果:
Traverse the stack from the top...
Stack is empty
Traverse the stack from the top...
19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Traversal is over
Top element is : 19
Traverse the stack from the top...
16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Traversal is over
Top element is : 16
Traverse the stack from the top...
-5 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Traversal is over
Top element is : -5
Begin to destroy stack...
succeed to destroy stack
Stack is empty
Press any key to continue