本篇文章主要起到引子的做用,而并不是去研究栈结构、或者说堆栈在操做系统内部的机制。
学习好久的栈,经过汇编语言来学习栈、C数据结构去实现的栈,正由于感受栈太过于深秒,没法表述更好,因此只是一个导论,说说学习心得。
栈的特色:后进先出(Last in first out),这就是栈的精髓,咱们知道在内存中其实都是线性存储,他能够是栈段,也能够是数据段,更能够是其他的内存空间。
以8086CPU(16位)举列说明,只要是被ss:sp(基础段寄存器+偏移地址)所指向的地址,这就是栈内存,那么经过上面叙述咱们应该考虑,居然没有具体的告诉那是栈内存,那不是无限大?你能够这样理解,凡是电脑可以寻址到的内存空间(必须是段寄存器ss+偏移地址)就能够认为是栈内存,那么栈溢出,栈下线等问题就成了安全的重要话题。
CPU是如何来进行入栈、出栈等操做呢? 首先栈底、栈顶两个概念。栈底也就是栈的底部,栈顶也就是栈的最高点,都说了内存中没有说哪个空间是栈的空间,何来的栈顶与栈底呢?其实就是咱们人为设置的,你们想象出来的,这一点与先进后出的思想大同小异,更是栈的思想,只要让这些数据遵循着这些规则,那么就是栈。初始化栈咱们通常认为都是把指针指向栈底,其实否则在内存中寄存器会指向栈底的下一个单元,为何?
一、Push操做,内存中高地址在下,低地址在上面(竖线),首先入栈操做首先会sp(依靠偏移地址来寻址)减偏移地址,为何是减,由于压栈的元素是压栈到栈底,下面是高地址!
二、Pop操做,原理相同,出栈操做,就是把里面的数据从上往外拿,后进先出嘛,因此空间是指针是来下面移动的(这个好像,那个纸画一画就出来了),sp就要+2,正好与压栈相反。
固然这些操做都要认为的去边界定义和代码中作一些处理机制。
注意:任意时刻,ss:sp都是指向栈顶(栈底只是咱们想象出的一个栈段,其实不存在)
说了那么多关于内存中栈的知识,仍是叫汇编知识吧,说一说C语言中数据结构,过程语言也好高级语言也好,其实都必须遵照后进先出的思想,才能够叫作栈,C或者高级语言就能够进行越界的限制(内存申请及条件判断等)。
栈能够干些什么?能够干不少事,每一个函数调用基本都会用到栈、当转移指令的时候,也都会把IP保存到栈中(call,ret等指令),逆波兰、二进制转换、加密、递归等等均可以用栈数据结构高效、便捷的去实现。
栈的基本操做无非,初始化、压栈(Push)、出栈(Pop)、遍历栈、清空栈、销毁栈(与清空栈不是一个概念),清空栈就像欺骗内存,并不是数据都给从内存清理,相似于格式化磁盘这样,让操做系统感受这块内存没有数据,其实写入数据覆盖原来数据。
也能够分为静态栈、动态栈,怎么叫都行。用数组就是静态,用链表就是动态,不过注意: 必定都要遵循后进先出的原则,不然就算写的特别灵活,出栈直接越太低位取高位,那样就违背栈的意愿,就算不上栈了!
下面是一段二进制转换代码(学习中的小练题颇有意思,分享给你们),基本栈操做就不分享了,你们代码大同小异,网上有更多前辈写的高质量代码值得你们参考数组
#include <stdio.h> #include <stdlib.h> #include <math.h> #define STACK_INIT_SIZE 20 #define STACKINCREMENT 0 typedef char ElemType; typedef struct { ElemType *top; ElemType *bottom; int stackSize; }sqStack; void Init_stack(sqStack *s); void Push_stack(sqStack *s, ElemType e); void Pop(sqStack *s, ElemType *e); int StackLength(sqStack s); int main(void) { ElemType c; sqStack s; int len, i, sum = 0; Init_stack(&s); printf("请输入二进制数,输入#符号表示结束!\n"); scanf("%c", &c); while ( c != '#' ) { Push_stack(&s, c); scanf("%c", &c); } getchar(); len = StackLength(s); printf("栈的当前容量是: %d\n",len); for(i = 0; i < len; i++) { Pop(&s, &c); sum = sum + (c-48) * pow(2, i); } printf("二进制转换10进制以后数值: %d\n",sum); return 0; } void Init_stack(sqStack *s) { s->bottom = (ElemType *)malloc(STACK_INIT_SIZE * sizeof(ElemType)); if( !s->bottom ) { exit(-1); } s->top = s->bottom; s->stackSize = STACK_INIT_SIZE; //最大容量 } void Push_stack(sqStack *s, ElemType e) { if( s->top - s->bottom >= s->stackSize ) { s->bottom = (ElemType *)realloc(s->bottom, (s->stackSize + STACKINCREMENT) * sizeof(ElemType)); if( !s->bottom ) { exit(-1); } } *(s->top) = e; s->top++; } void Pop(sqStack *s, ElemType *e) { if( s->top == s->bottom ) { return; } *e = *--(s->top); } int StackLength(sqStack s) { return (s.top - s.bottom); }
思想才是王道,语言是用来实现思想的价值,一体一用。安全