本篇文章主要起到引子的做用,而並不是去研究棧結構、或者說堆棧在操做系統內部的機制。
學習好久的棧,經過彙編語言來學習棧、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); }
思想纔是王道,語言是用來實現思想的價值,一體一用。安全