操作系統對於內存的兩種管理方式
如鵬網 《C語言也能干大事》http://www.rupeng.com/Courses/Index/12
第三章透徹講指針 之 第 15 節: 棧空間
平時我們定義的變量都是分布在棧空間里,如下面的程序所示
1 #include <stdio.h> 2 int main(int argc, char *argv[]) 3 { 4 int i=5; 5 char s[] = "afasdfsfwfw"; 6 return 0; 7 }
棧空間:出了函數范圍,內存空間自動釋放。定義的局部變量int、局部數組等都在棧空間中。棧空間的尺寸有最大的限制,不適合分配大空間使用;棧空間出了函數范圍就釋放,不適合要給其他地方使用的內存。好處:不需要手動釋放。
1 #include <stdio.h> 2 3 int *getData() 4 { 5 int nums[10]={1,2,3,4,5,6,7,8}; 6 return nums; 7 } 8 9 int *getData3() 10 { 11 int i=5; 12 return &i; 13 } 14 15 int *getData2() 16 { 17 int aaa[10]={8,7,6,5,4,3,2,1}; 18 return aaa; 19 } 20 21 int main(int argc, char *argv[]) 22 { 23 int * nums = getData(); 24 getData2(); 25 printf("%d,%d,%d",nums[0],nums[1],nums[2]); 26 return 0; 27 }
上面程序第24行,如果注釋getData2(),上述程序的執行結果是1,2,3
但是如果不注釋getData2(),上述程序的執行結果是:8,7,6
這里很好的反映了棧空間的問題,因為注釋getData2()時,函數getData1()申請了棧空間存儲數組{1,2,3,4,5,6,7,8},指針num指向該數組首地址,所以打印輸出結果為1,2,3;但是一旦加入getData2(),因為getData1()執行完畢退出了,它申請的內存空間(存儲數組的)就被釋放掉了,再執行getData2(),該函數同樣申請內存空間{8,7,6,5,4,3,2,1}覆蓋了前述的數組{1,2,3,4,5,6,7,8}占用內存,故輸出結果變成了8,7,6。
注意:因此這里有一個編程規范,不要把局部變量的指針作為函數返回值返回
第二部分是堆空間的學習內容
堆空間:手動分配,使用完成之后需要手動釋放。使用malloc分配,使用free釋放。執行下列代碼,會看到程序的內存在暴漲
要在內存
優點:可以動態分配內存,分配比較大的內存,比如下載軟件每下載10M,才把緩沖區(分配的動態內存)的數據寫入磁盤。
下面是跟前面一樣的功能樣例,但是使用了動態內存分配,也就是堆空間的方法,最終打印輸出結果為1,2,3
1 #include <stdio.h> 2 #include <stdlib.h>//malloc在該頭文件中聲明 3 int *getData1() 4 { 5 int *nums = (int *)malloc(sizeof(int)*3); 6 nums[0] = 1; 7 nums[1] = 2; 8 nums[2] = 3; 9 return nums; 10 } 11 int *getData2() 12 { 13 int *nums = (int *)malloc(sizeof(int)*3); 14 nums[0] = 4; 15 nums[1] = 5; 16 nums[2] = 6; 17 return nums; 18 } 19 int main(int argc, char *argv[]) 20 { 21 int *num1 = getData1(); 22 int *num2 = getData2(); 23 printf("%d,%d,%d\n",num1[0],num1[1],num1[2]); 24 free(num1);//由調用者釋放內存,如果不釋放,會導致內存泄露 25 free(num2); 26 return 0; 27 }
函數返回指針的方法
方法1:在方法內malloc,用完了由調用者free
方法2:把局部變量定義為static,不適合於多線程調用,如果想保存返回內容,你需要調用者盡快復制一份。
方法3:由調用者分配內存空間,只是把指針發給函數,函數內部把數據拷貝到內存中(推薦)。案例:從文件名分析文件名和擴展名。
1 #include <stdio.h> 2 #include <string.h> 3 4 void parseFileName(char* filename,char* name, 5 char* ext) 6 { 7 char *ptr=filename; 8 9 while(*ptr!='\0') 10 { 11 ptr++; 12 } 13 char *endPtr = ptr;//結尾的指針 14 //ptr移動到了字符串的結尾 15 //再把ptr移動到"."的位置 16 while(*ptr!='.') 17 { 18 ptr--; 19 } 20 memcpy(name,filename,(ptr-filename)*sizeof(char)); 21 memcpy(ext,ptr+1,(endPtr-ptr)*sizeof(char)); 22 } 23 24 int main(int argc, char *argv[]) 25 { 26 char str[]="[TK-300]美.女.avi"; //調用者分配內存空間 27 char name[20]={0};//調用者分配內存空間 28 char ext[20]={0};//調用者分配內存空間 29 parseFileName(str,name,ext); 30 printf("文件名:%s,后綴:%s",name,ext); 31 return 0; 32 }
補充:memset()與memcpy()的功能?
strcpy()與strcpy_s()的差別?