去公司面試時經常會有這樣的問題,雖然和php開發關系不是很密切,但也是基礎知識很重要的一部分。我上次就答了個:“不是很清楚” 暈。。。
一般認為在c中分為這幾個存儲區:
1. 棧 -- 有編譯器自動分配釋放
2. 堆 -- 一般由程序員分配釋放,若程序員不釋放,程序結束時可能由OS回收
3. 全局區(靜態區) -- 全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域,未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域。 程序結束釋放。
4. 另外還有一個專門放常量的地方。 程序結束釋放
在函數體中定義的變量通常是在棧上,用malloc, calloc, realloc等分配內存的函數分配得到的就是在堆上。在所有函數體外定義的是全局量,加了static修飾符後不管在哪裡都存放在全局區(靜態區),在所有函數體外定義的static變量表示在該文件中有效,不能extern到別的文件用,在函數體內定義的static表示只在該函數體內有效。另外,函數中的"adgfdf"這樣的字符串存放在常量區。
比如:
代碼:
[php]int a = 0; //全局初始化區
char *p1; //全局未初始化區
main()
{
int b; //棧
char s[] = "abc"; //棧
char *p2; //棧
char *p3 = "123456"; //123456\0在常量區,p3在棧上。
static int c = 0; //全局(靜態)初始化區
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
//分配得來得10和20字節的區域就在堆區。
strcpy(p1, "123456");
//123456\0放在常量區,編譯器可能會將它與p3所指向的"123456"優化成一塊。
}
[/php]
還有就是函數調用時會在棧上有一系列的保留現場及傳遞參數的操作。
棧的空間大小有限定,vc的缺省是2M。棧不夠用的情況一般是程序中分配了大量數組和遞歸函數層次太深。有一點必須知道,當一個函數調用完返回後它會釋放該函數中所有的棧空間。棧是由編譯器自動管理的,不用你操心。
堆是動態分配內存的,並且你可以分配使用很大的內存。但是用不好會產生內存洩漏。並且頻繁地malloc和free會產生內存碎片(有點類似磁盤碎片),因為c分配動態內存時是尋找匹配的內存的。而用棧則不會產生碎片。
在棧上存取數據比通過指針在堆上存取數據快些。
一般大家說的堆棧和棧是一樣的,就是棧(stack),而說堆時才是堆heap. 棧是先入後出的,一般是由高地址向低地址生長。
堆和棧的對比
從以上知識可知,
棧是系統提供的功能,特點是快速高效,缺點是有限制,數據不靈活;而堆是函數庫提供的功能,特點是靈活方便,數據適應面廣泛,但是效率有一定降低。
棧是系統數據結構,對於進程/線程是唯一的;堆是函數庫內部數據結構,不一定唯一。不同堆分配的內存無法互相操作。
棧空間分靜態分配和動態分配兩種。靜態分配是編譯器完成的,比如自動變量(auto)的分配。動態分配由malloca函數完成。棧的動態分配無需釋放(是自動的),也就沒有釋放函數。為可移植的程序起見,棧的動態分配操作是不被鼓勵的!堆空間的分配總是動態的,雖然程序結束時所有的數據空間都會被釋放回系統,但是精確的申請內存/釋放內存匹配是良好程序的基本要素。
堆棧是一種執行“後進先出”算法的數據結構。
設想有一個直徑不大、一端開口一端封閉的竹筒。有若干個寫有編號的小球,小球的直徑比竹筒的直徑略小。現在把不同編號的小球放到竹筒裡面,可以發現一種規律:先放進去的小球只能後拿出來,反之,後放進去的小球能夠先拿出來。所以“先進後出”就是這種結構的特點。
堆棧就是這樣一種數據結構。它是在內存中開辟一個存儲區域,數據一個一個順序地存入(也就是“壓入——push”)這個區域之中。有一個地址指針總指向最後一個壓入堆棧的數據所在的數據單元,存放這個地址指針的寄存器就叫做堆棧指示器。開始放入數據的單元叫做“棧底”。數據一個一個地存入,這個過程叫做“壓棧”。在壓棧的過程中,每有一個數據壓入堆棧,就放在和前一個單元相連的後面一個單元中,堆棧指示器中的地址自動加1。讀取這些數據時,按照堆棧指示器中的地址讀取數據,堆棧指示器中的地址數自動減 1。這個過程叫做“彈出pop”。如此就實現了後進先出的原則。
堆棧是計算機中最常用的一種數據結構,比如函數的調用在計算機中是用堆棧實現的。
堆棧可以用數組存儲,也可以用以後會介紹的鏈表存儲。
下面是一個堆棧的結構體定義,包括一個棧頂指針,一個數據項數組。棧頂指針最開始指向-1,然後存入數據時,棧頂指針加1,取出數據後,棧頂指針減1。
#define MAX_SIZE 100
typedef int DATA_TYPE;
struct stack
{
DATA_TYPE data[MAX_SIZE];
int top;
};
小魚哥哥 (2008-11-17 13:16:17)
PHP是C開發的
所以這些開概念對於PHP來說應該同樣適用。
1、棧的定義
棧(Stack)是限制僅在表的一端進行插入和刪除運算的線性表。
(1)通常稱插入、刪除的這一端為棧頂(Top),另一端稱為棧底(Bottom)。
(2)當表中沒有元素時稱為空棧。
(3)棧為後進先出(Last In First Out)的線性表,簡稱為LIFO表。
棧的修改是按後進先出的原則進行。每次刪除(退棧)的總是當前棧中"最新"的元素,即最後插入(進棧)的元素,而最先插入的是被放在棧的底部,要到最後才能刪除。
【示例】元素是以a1,a2,…,an的順序進棧,退棧的次序卻是an,an-1,…,a1。
2、棧的基本運算
(1)InitStack(S)
構造一個空棧S。
(2)StackEmpty(S)
判棧空。若S為空棧,則返回TRUE,否則返回FALSE。
(3)StackFull(S)
判棧滿。若S為滿棧,則返回TRUE,否則返回FALSE。
注意:
該運算只適用於棧的順序存儲結構。
(4)Push(S,x)
進棧。若棧S不滿,則將元素x插入S的棧頂。
(5)Pop(S)
退棧。若棧S非空,則將S的棧頂元素刪去,並返回該元素。
(6)StackTop(S)
取棧頂元素。若棧S非空,則返回棧頂元素,但不改變棧的狀態。
3.測試
下面的代碼來自網上,代碼可能有點亂,但是我個人感覺寫得非常好,有時光看理論不看代碼還真的難以理解,當你把代碼看明白以後,別人的代碼也就成為了自己的代碼,可以拿來直接用的,謝謝提供代碼的朋友。
多看看別人寫得好的代碼,理解了以後,然後再自己實踐,這是一種學習的好方式,前提是你要有耐心,不能太浮燥。
C語言:
#include <stdio.h>
#define stacksize 100 /*定義stacksize為常數100 */
//進棧算法
int push(int s[],int x,int *ptop)
{
int top;
top=*ptop; //ptop是指針變量;*ptop獲得實際棧頂指針
if ( top==stacksize ) //棧滿
{
printf("overflow\n");
return 0;
}
else
{
s[top]=x;
top++;
*ptop=top; //實際棧頂指針加1,返回到調用函數處
return 1;
}
}
//出棧算法
int pop(int s[],int *py,int *ptop)
{
int top;
top=*ptop; //ptop是指針變量;*ptop獲得實際棧頂指針
if (top==0) //棧空
{
printf("stack empty\n");
return 0;
}
else
{
--top;
*py=s[top]; //實際棧頂指針減1,返回到調用函數處
*ptop=top;
return 1;
}
}
int main()
{
static int s[stacksize];
int top=0,result,y;
int i;
result=push(s,11,&top); //將11壓進棧中
printf("top: %d\n", top);
result=push(s,22,&top); //將22壓進棧中
printf("top: %d\n", top);
result=push(s,33,&top); //將33壓進棧中
printf("top: %d\n", top);
for (i=0;i<3;i++)
{
result=pop(s,&y,&top); //將11從棧中彈出
printf("top=%d,y=%d\n",top,y);
}
}
下面是在CentOS上編譯測試的結果
[root@CentOS_Test_Server server]# gcc -o stack stack.c
[root@CentOS_Test_Server server]# ./stack
top: 1
top: 2
top: 3
top=2,y=33
top=1,y=22
top=0,y=11