1. 程式人生 > >malloc和memset的理解

malloc和memset的理解

思科某筆試題
int main
{
	char *p1 = "hello";
	char *p2;
	p2 = (char *)malloc(20);
	//p2 = (char *)malloc(sizeof(char));
	memset(p2,0,20);
	while(*p2++ = *p1++)
		printf("%s\n",p2);
        return 0;
}
結果輸出5個空的換行。

這裡主要考察++,*,=這些運算子的優先順序。

注意點;memset是對位元組操作的,memset(p2, 0, 20),這個 把20個位元組空間全部賦值為assic為0的值,就是null。

一、原型:extern void *malloc(unsigned int num_bytes);

標頭檔案:#include <malloc.h> 或 #include <alloc.h> (注意:alloc.h 與 malloc.h 的內容是完全一致的。)

功能:分配長度為num_bytes位元組的記憶體塊

說明:如果分配成功則返回指向被分配記憶體的指標,否則返回空指標NULL。

當記憶體不再使用時,應使用free()函式將記憶體塊釋放。

舉例:

  1. #include<stdio.h>
  2. #include<malloc.h>
  3. int main()  
  4. {  
  5.     char *p;  
  6.     p=(char *)malloc(100);  
  7.     if(p)  
  8.         printf("Memory Allocated at: %x/n",p);  
  9.     else
  10.         printf("Not Enough Memory!/n");  
  11.     free(p);  
  12.     return 0;  
  13. }  

二、函式宣告(函式原型):

  void *malloc(int size);

  說明:malloc 向系統申請分配指定size個位元組的記憶體空間。返回型別是 void* 型別。void* 表示未確定型別的指標。C,C++規定,void* 型別可以強制轉換為任何其它型別的指標。這個在MSDN上可以找到相關的解釋,具體內容如下:

malloc returns a void pointer to the allocated space, or NULL if there is insufficient memory available. To return a pointer to a type other than void, use a type cast on the return value. The storage space pointed to by the return value is guaranteed to be suitably aligned for storage of any type of object. If size is 0, mallocallocates a zero-length item in the heap and returns a valid pointer to that item. Always check the return frommalloc, even if the amount of memory requested is small.

三、malloc與new的不同點

  從函式宣告上可以看出。malloc 和 new 至少有兩個不同: new 返回指定型別的指標,並且可以自動計算所需要大小。比如:

      int *p;

  p = new int; //返回型別為int* 型別(整數型指標),分配大小為 sizeof(int);

  或:

  int* parr;

  parr = new int [100]; //返回型別為 int* 型別(整數型指標),分配大小為 sizeof(int) * 100;

    而 malloc 則必須由我們計算要位元組數,並且在返回後強行轉換為實際型別的指標。

    int* p;

  p = (int *) malloc (sizeof(int));

  第一、malloc 函式返回的是 void * 型別,如果你寫成:p = malloc (sizeof(int)); 則程式無法通過編譯,報錯:“不能將 void* 賦值給 int * 型別變數”。所以必須通過 (int *) 來將強制轉換。

  第二、函式的實參為 sizeof(int) ,用於指明一個整型資料需要的大小。如果你寫成:

  int* p = (int *) malloc (1);

  程式碼也能通過編譯,但事實上只分配了1個位元組大小的記憶體空間,當你往裡頭存入一個整數,就會有3個位元組無家可歸,而直接“住進鄰居家”!造成的結果是後面的記憶體中原有資料內容全部被清空。

  malloc 也可以達到 new [] 的效果,申請出一段連續的記憶體,方法無非是指定你所需要記憶體大小。

  比如想分配100個int型別的空間:

  int* p = (int *) malloc ( sizeof(int) * 100 ); //分配可以放得下100個整數的記憶體空間。

  另外有一點不能直接看出的區別是,malloc 只管分配記憶體,並不能對所得的記憶體進行初始化,所以得到的一片新記憶體中,其值將是隨機的。

  除了分配及最後釋放的方法不一樣以外,通過malloc或new得到指標,在其它操作上保持一致。

 總結:

malloc()函式其實就在記憶體中找一片指定大小的空間,然後將這個空間的首地址範圍給一個指標變數,這裡的指標變數可以是一個單獨的指標,也可以是一個數組的首地址,這要看malloc()函式中引數size的具體內容。我們這裡malloc分配的記憶體空間在邏輯上連續的,而在物理上可以連續也可以不連續。對於我們程式設計師來說,我們關注的是邏輯上的連續,因為作業系統會幫我們安排記憶體分配,所以我們使用起來就可以當做是連續的。

功 能

  將s所指向的某一塊記憶體中的每個位元組的內容全部設定為ch指定的ASCII值,   塊的大小由第三個引數指定,這個函式通常為新申請的記憶體做初始化工作,   其返回值為指向S的指標。 [編輯本段] 用 法   void *memset(void *s, int ch, unsigned n); [編輯本段] 程式例   #include <string.h>   #include <stdio.h>   #include <memory.h>

memset函式

  int main(void)   {   char buffer[] = "Hello world\n";   printf("Buffer before memset: %s\n", buffer);   memset(buffer, '*', strlen(buffer) );   printf("Buffer after memset: %s\n", buffer);   return 0;   }   輸出結果:   Buffer before memset: Hello world   Buffer after memset: ***********   編譯平臺:   Microsoft Visual C++ 6.0   也不一定就是把內容全部設定為ch指定的ASCII值,而且該處的ch可為int或者其他型別,並不一定要是char型別。例如下面這樣:   int array[5] = {1,4,3,5,2};   for(int i = 0; i < 5; i++)   cout<<array[i]<<" ";   cout<<endl;   memset(array,0,5*sizeof(int));   for(int k = 0; k < 5; k++)   cout<<array[k]<<" ";   cout<<endl;   輸出的結果就是:   1 4 3 5 2   0 0 0 0 0   後面的表大小的引數是以位元組為單位,所以,對於int或其他的就並不是都乘預設的1(字元型)了。而且不同的機器上int的大小也可能不同,所以最好用sizeof()。   要注意的是,memset是對位元組進行操作,所以上述程式如果改為   int array[5] = {1,4,3,5,2};   for(int i = 0; i < 5; i++)   cout<<array[i]<<" ";   cout<<endl;   memset(array,1,5*sizeof(int));// 注意 這裡與上面的程式不同   for(int k = 0; k < 5; k++)   cout<<array[k]<<" ";   cout<<endl;   輸出的結果就是:   1 4 3 5 2   16843009 16843009 16843009 16843009 16843009   為什麼呢?   因為memset是以位元組為單位就是對array指向的記憶體的5個位元組進行賦值,每個都用ASCII為1的字元去填充,轉為二進位制後,1就是00000001,佔一個位元組。一個INT元素是4位元組,合一起就是00000001000000010000000100000001,就等於16843009,就完成了對一個INT元素的賦值了。   所以用memset對非字元型陣列賦初值是不可取的!   例如有一個結構體Some x,可以這樣清零:   memset( &x, 0, sizeof(Some) );   如果是一個結構體的陣列Some x[10],可以這樣:   memset( x, 0, sizeof(Some)*10 ); [編輯本段] memset函式詳細說明   1。void *memset(void *s,int c,size_t n)   總的作用:將已開闢記憶體空間 s 的首 n 個位元組的值設為值 c。   2。例子   main(){   char *s="Golden Global View";   clrscr();   memset(s,'G',6);//貌似這裡有點問題//   printf("%s",s);   getchar();   return 0;   }    【應該是沒有問題的,字串指標一樣可以,並不是只讀記憶體,可以正常執行】   3。memset() 函式常用於記憶體空間初始化。如:   char str[100];   memset(str,0,100);   4。memset()的深刻內涵:用來對一段記憶體空間全部設定為某個字元,一般用在對定義的字串進行初始化為‘memset(a, '\0', sizeof(a));   memcpy用來做記憶體拷貝,你可以拿它拷貝任何資料型別的物件,可以指定拷貝的資料長度;例:   char a[100], b[50];   memcpy(b, a, sizeof(b)); //注意如用sizeof(a),會造成b的記憶體地址溢位。   strcpy就只能拷貝字串了,它遇到'\0'就結束拷貝;例:   char a[100], b[50];   strcpy(a,b);   如用strcpy(b,a),要注意a中的字串長度(第一個‘\0’之前)是否超過50位,如超過,則會造成b的記憶體地址溢位。   5.補充:某人的一點心得   memset可以方便的清空一個結構型別的變數或陣列。   如:   struct sample_struct   {   char csName[16];   int iSeq;   int iType;   };   對於變數   struct sample_strcut stTest;   一般情況下,清空stTest的方法:   stTest.csName[0]='\0';   stTest.iSeq=0;   stTest.iType=0;   用memset就非常方便:   memset(&stTest,0,sizeof(struct sample_struct));   如果是陣列:   struct sample_struct TEST[10];   則   memset(TEST,0,sizeof(struct sample_struct)*10);