7.【動態內存分配】

【專題】【重點】                                                                        
動態內存分配【重點 難點】                                                             
傳統數組的缺點:                                                                     
1. 數組長度必須事先制定,且只能是常整數,不能是變量                              
例子:                                                                        
int a[5]; //ok                                                              
int len =5; int a[len];   //error 不能是變量                                
2. 傳統形式的定義的數組,該數組的內存程序員無法手動釋放它,是由系統自動釋放的    
  在一個函數運行期間,系統爲該函數中數組所分配的存儲空間會一直存在,            
  直到該函數運行完畢時,數組的空間纔會被系統釋放。                              
                                                                                        
3. 數組的長度一旦定義,其長度就不能再更改 a[5] 其中5就表示數組長度               
數組的長度不能在函數運行的過程總動態的擴充或縮小                              
                                                                                        
4. A函數定義的數組,在A函數運行期間可以被其他函數使用,但A函數運行完畢之後,     
A函數中的數組將無法再被其他函數使用                                           
傳統方式定義的數組,不能跨函數使用                                            
                                                                                        
爲什麼需要動態分配內存                                                              
動態數組很好的解決了傳統數組的四個缺陷                                            
傳統數組也叫靜態數組                                                              
                                                                                        
動態內存分配的舉例_動態數組的構造                                                   
malloc函數的使用:malloc 是分配內存的意思                                         

malloc是memory(內存) allocate(分配)的縮寫

#include <stdio.h>                                                                                           
#include <malloc.h>   //不能省                                                                               
int main(void)                                                                                               
{                                                                                                            
	int i = 5;  //靜態分配了 4個字節  //5行                                                                    
	int *p = (int *)malloc(4);    //6行                                                                        
		/*                                                                                                       
			1.要使用malloc函數,必須添加malloc.h的頭文件                                                           
			2.malloc函數只有一個形參,並且形參是整型                                                               
			3.形參 (4) 表示請求系統爲本程序分配4個字節                                                             
			4.malloc函數只能返回第一個字節的地址                                                                   
		        5.6行最終分配了8個字節,P變量佔了4個字節,p所指向的內存也佔了4個字節                                   
		        6.p 本身所佔 的4個內存是靜態分配的,p 所指向的 4個內存是動態分配的                                     
		*/                                                                                                       
	*p = 5; //*p 代表的就是一個int變量,只不過*p這個整型變量的內存分配方式和5行的分配方式不同                  
	free(p);  //表示把p所指向的內存給釋放掉,p本身的內存是靜態的,不能由程序員手動釋放,                        
			  //p本身的內存只能在p變量所在的函數運行終止時由系統自動釋放                                           
	printf("hello!\n");                                                                                        
	return 0;                                                                                                 
}                                                                                                            
解析:                                                                                                       
	(int *)是將malloc請求的字節強制轉換爲整型變量,按整型變量所佔字節數來劃分地址。                            
	(第一個字節地址只有值,而沒有類型,只有強制轉換後纔會給加上所屬轉換的類型。)                             
			malloc後面的括號中必須是一個值,而這個值必須爲整數,無論請求的字節數是多少,比如 malloc(200)           
					但是最終返回的都是第一個字節的地址,如果只知道第一個字節地址,但是並不知道第一個字節地址指向的變量 
					最終會佔用幾個字節,所以需要在前面進行強制的變量類型轉換,告訴程序最後按什麼標準來劃分地址。以便明 
					白第一個字節地址到底指向的是一個什麼類型的變量。最終表示請求來的字節數按第一個字節地址所指向的變量 
					類型所佔的字節數來劃分,比如(int *)是4個字節的整型變量類型,那麼最後就會按4個字節來進行劃分。    
					                                                                                                   
					如果按 malloc(200) 來看:                                                                          
					char *  	佔1字節  200個變量                                                                       
					int * 		佔4字節	 50個變量                                                                        
					double *	佔8字節  25個變量                                                                        
					                                                                                                   
					int *p = (int *)malloc(4)                                                                          
					完了之後,請求來的4個字節的首地址就會給p 而通過強制類型轉換,也知道了轉換後的類型。                
#include <stdio.h>                                                                                                  
#include <malloc.h>                                                                                                 
void f(int *q)                                                                                                     
{                                                                                                                   
  //*p = 200;  //error                                                                                              
  //q = 200;  //error                                                                                               
  //**q = 200; //error 因爲*q已經是個整型變量了,所以前面不能再加*號                                                
    * q =200;                                                                                                       
//	free(q);  //是把q所指向的內存釋放掉,必須註釋掉,否則會導致第17行代碼會出錯                                      
}                                                                                                                   
int main(void)                                                                                                      
{                                                                                                                   
        int *p = (int *)malloc(sizeof(int)); //動態分配int類型的字節數4個字節,sizeof(int)的返回值是int                   
        *p = 10;                                                                                                          
	printf("%d\n",*p);   //10                                                                                         
	f(p);    //p是int *類型                                                                                           
	printf("%d\n",*p);  //200   //第17行                                                                              
	return 0;                                                                                                         
}                                                                                                                   
	解析:                                                                                                              
		因爲f(p)調用上面的f函數,而這個括號內p存放的是動態內存分配而來的第一個字節的地址,那麼將這個地址傳遞給q,那麼   
		void f(int *q)中q的值就是這個地址,跟p等同,而*q=200 是給*q這個整型變量賦值200,即改變了*q 的值,也相當於改變了
		*p的值爲200,所以最終*p的輸出值也爲200                                                                          
					                                                                                                                
		而如果free(q);生效,則因爲最終q指向的是sizeof申請來的整型的4個字節,所以如果生效,則會釋放掉申請來4字節的內存。 
		從而導致出錯。                                                                                                  

動態一維數組的構造:                                                                                                  
  -------------------------------                                                                                     
	#include <stdio.h>                                                                                                  
	#include <malloc.h>                                                                                                 
	int main(void)                                                                                                      
	{                                                                                                                   
		int a[5]; //如果int佔4個字節的話,則本數組總共包含有20個字節,每個4個字節爲一個元素,從a[0]開始,後面依次類推。   
		int len;                                                                                                          
		int * pArr;                                                                                                       
		int i;                                                                                                            
		printf("請輸入你要存放的元素的個數:\n");                                                                         
		scanf("%d",&len);                                                                                                 
		pArr = (int *)malloc(4 * len);  //動態的構造了一個數組,因爲是整型指針變量,一個元素佔4個字節,而len是元素個數    
		for (i=0;i<len;++i)    //對動態一維數組進行操作                                                                   
			scanf("%d",&pArr[i]); //對動態一維數組進行賦值                                                                  
		printf("一維數組的內容是:\n");                                                                                   
		for (i=0;i<len;++i)      //對動態一維數組進行循環輸出                                                             
			printf("%d\n",pArr[i]);                                                                                         
			                                                                                                                
		free(pArr);  //釋放掉pArr所指向的動態數組分配的內存                                                               
		                                                                                                                  
		return 0;	                                                                                                        
	}                                                                                                                   
	                                                                                                                    
  解析:                                                                                                               
  		動態數組在使用上是跟靜態數組的使用方式是一樣的,只是構造的時候不一樣而已。                                      
  	                                                                                                                  
  		因爲pArr是整型指針變量佔4個字節,所以動態內存分配後,指向的是內存分配的20個字節中的前4個字節,如果pArr+1 則表示 
  		指向的是第二個4個字節(即第5個字節到第8個字節),而不是在前面4字節的基礎上+1成爲5個字節。因爲每4個字節爲一部分。
  		由幾個字節爲一部分,需要由pArr的指針變量類型來決定。                                                            
  		                                                                                                                
  		pArr = (int *)malloc(4 * len);等同於int pArr[0]、int pArr[1]、int pArr[2]、int pArr[3]、int pArr[4]             
  		即int pArr[5]                                                                                                   
  		動態的構造了一個一維數組,該數組的數組名是pArr,數組長度是len,單個元素如上所示。                                
  		                                                                                                                
  		上面靜態的a[5]有靜態的20字節的內存                                                                              
  		下面pArr動態申請的有20個字節的內存                                                                              
  				由上可知:                                                                                                  
  						a[0]是第一個元素,佔用了20個字節的前4個字節                                                             
  				那麼:pArr[0]同樣也是佔用了動態分配的20字節的前4個字節                                                      
  							又pArr[0]等同於 *(pArr+0)                                                                             
  							所以例如:a[2]就等同於pArr[2]                                                                         
  							                                                                                                      
  		 那麼如何動態的增加數組的長度呢:                                                                               
  		 可以使用realloc函數:realloc(aArr,100)  括號裏面,前面表示數組名,後面表示要擴充的字節數容量上限。             
  		 如果pArr當初指向的是50個字節的內存,那麼運行的時候就會擴充到100.前50個字節的數據會保留。                       
  		 如果pArr當初指向的是150個字節的內存,那麼運行的時候就縮小到100,後50個字節的數據會丟失。                       

                                  

		  #include <stdio.h>                                                                                                 
		  #include <malloc.h>                                                                                                
		  void f(int *q)                                                                                                     
		  {                                                                                                                  
		  		*q = 10;                                                                                                       
		  }	                                                                                                                 
		  //void g(int **p)                                                                                                  
		  //{                                                                                                                
		  //}					                                                                                                       
		  int main(void)                                                                                                     
		  {                                                                                                                  
		  	int *p = (int *)malloc(4);  //動態請求4字節  p指向的是(int*)                                                   
		  	printf("*p = %d\n",*p);   //輸出的是垃圾數字                                                                     
		  	f(p);                                                                                                            
		  //g(&p);               //p是int*,&p是int**                                                                        
		  	printf("*p = %d\n",*p);                                                                                          
		  	                                                                                                                 
		  	return 0;                                                                                                        
		  }	                                                                                                                 
		  程序運行的結果爲:*p = 10                                                                                          
		  ---------------------------                                                                                        
		  #include <stdio.h>                                                                                                 
		  #include <malloc.h>                                                                                                
		  void f(int **q)                                                                                                    
		  {                                                                                                                  
		  	**q = **q + 30;                                                                                                  
		  }                                                                                                                  
		  int main(void)                                                                                                     
		  {                                                                                                                  
		  	int i;                                                                                                           
		  	int *p;                                                                                                          
		  	printf("請輸入一個數字:\n");                                                                                    
		  	scanf("%d",&i);                                                                                                  
		  	p = (int *)malloc(4);  //動態請求4個字節的內存  //第13行                                                         
		  	p = &i;                                                                                                          
		  	f(&p);                                                                                                           
		  	printf("i = %d\n",i);                                                                                            
	//		free(p);  error,此處不能添加,否則會有內存報錯。                                                                
		  	return 0;                                                                                                        
		  }                                                                                                                  
		  程序運行的結果爲:i = 輸入的任何數+30後的結果                                                                      
		  如果將第13行取消,程序依然可以運行,只是卻變成了由系統自行分配的靜態內存。                                         
		  --------------------------------------------------------------------------                                         
		靜態內存和動態內存的區別比較:                                                                                       
				靜態內存是由系統自動分配,由系統自動釋放                                                                         
				靜態內存是在棧中分配的                                                                                           
				                                                                                                                 
				動態內存是由程序員手動分配,手動釋放,如果忘了釋放,就會出現內存泄漏,內存越用越少,最後就會死機。               
				動態內存是在堆分配的  		堆就是堆排序                                                                           
				                                                                                                                 
		-----------------------------------------------                                                                      
		跨函數使用內存的問題:                                                                                               
				靜態變量不能跨函數使用內存:                                                                                     
				#include <stdio.h>                                                                                               
				void f(int **q)                                                                                                  
				{                                                                                                                
					int i = 5;                                                                                                     
					//**q等價於*p   *q等價於p    q和**q都不等價於p                                                                 
					//*q = i;  error,因爲*q = i; 等價於 p = i 這樣寫是錯誤的,而p中存放的是地址不是變量                           
					*q = &i;  //  p = &i                                                                                           
				}                                                                                                                
				int main(void)                                                                                                   
				{                                                                                                                
					int *p;                                                                                                        
					f(&p);    //第12行                                                                                            
					printf("%d\n",*p);  //本句語法沒有問題,但邏輯上有問題。                                                       
															//不能讀取不屬於自己的內存,在規則上講  //第13行                                           
					return 0;                                                                                                      
				}                                                                                                                
				程序的運行結果爲:5   .                                                                                          
				解析:                                                                                                           
						此程序在語法上是沒有問題的,但是在現實中邏輯上是有問題的,不能這樣去寫程序。                                 
						程序在運行到第12行的時候,實際上f函數的靜態內存已經由系統自動釋放掉了,                                      
						所以這個時候第13行的p指向的i變量就不存在了,換句話說就是無法訪問了。                                         
						由此可見靜態變量當被終止的時候就不能夠被其他函數使用了。                                                     
				----------------------------------------------------------------------------------                               
				動態內存可以跨函數使用:                                                                                         
                                #include <stdio.h>                                                                                               
                                #include <malloc.h>                                                                                              
                                void f(int **q)                                                                                                  
                                {                                                                                                                
                                   *q = (int *)malloc(sizeof(int)); //sizeof(數據類型) 返回值是該數據類型所佔的字節數                             
                                   // 等價於 p = (int *)malloc(sizeof(int));                                                                        
                                // q = 5; error                                                                                                  
                                // *q = 5; //p=5; error                                                                                          
                                   **q = 5; //*p = 5;                                                                                               
                                }                                                                                                                
                                int main(void)                                                                                                   
                                {                                                                                                                
                                   int *p;                                                                                                        
                                   f(&p);                                                                                                         
                                   printf("%d\n",*p);   //  第15行                                                                                
                                   return 0;                                                                                                      
                                }                                                                                                                
                               運行結果爲:5                                                                                                    
                               解析:                                                                                                           
                                    因爲是動態分配的內存 而p指向的是malloc(sizeof(int))中的int的4個字節的內存,而最終此程序並沒有手動釋放內存的  
                                    free(q),且動態內存是在堆裏面進行分配的不存在出棧,所以在最後第15行,仍然可以訪問之前動態分配的內存。        
        ---------------------------------------------------------------------------------------------------------------- 




                                        

發佈了113 篇原創文章 · 獲贊 119 · 訪問量 50萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章