程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++內存管理(一)

C++內存管理(一)

編輯:C++入門知識


1、  內存分配方式
(1)從靜態存儲區域分配。例如使用static、全局變量。靜態存儲區的數據在程序編譯的時候就已經分配好了,在程序運行期間一直存在,只有在程序推出之後才會釋放。
(2)在棧上分配。函數內部的局部變量都是在棧上分配的,在函數階數時存儲空間便被釋放;
(3)在堆上分配。程序員根據自己的需要申請和釋放內存(new/delete malloc/free)
2、在內存的分配過程中經常會出現一些錯誤。
(1)內存未分配成功卻使用了他。例如內存中沒有足夠大的剩余空間此時內存分配(new/malloc)失敗之後會返回NULL,可以用assert(p!=NULL)或者if語句進行檢查。
(2)內存分配成功卻沒有初始化就引用它。 int *p=newint(10);//忘記初始化
(3)內存分配成功,但是越界操作。在使用數組下標時容易出現“多1”、“少1”
(4)忘記釋放內存,造成內存洩露。
(5)內存被釋放(delete)之後卻繼續使用它
3、指針與數組
(1)修改內容
char a[]=”hello”;
a[0]=’X’;
cout<<a<<endl;
char *p=”world”;  //這裡定義p指向常量字符串
p[0]=’X’;              //錯誤,常量字符串的值不能被改變
cout<<endl;
(2)當使用數組作為函數的參數進行傳遞時,該數組自動退化為同類型的指針
void printLen(char a[100])
{
         Cout<<sizeof(a)<<endl;//這裡會輸出4 而不是100
}
(3)指針參數傳遞內存
如果一個函數的參數是一個指針,不要使用該指針去申請動態內存。例如:
void getMem(char *p, int len)
{
         p=(char*)malloc(sizeof(char) * len);
}
void  test(void)
{
         char*str=NULL;
         getMem(str,1100);//執行之後str仍是NULL
         strcopy(str,“hello”);//由於str=NULL 所以導致運行錯誤
}
 
上面運行錯誤是因為,在函數中重視要為每個參數制作一個臨時的副本,在getMem中,指針參數p的副本就是_p,在編譯器中會使_p=p。從而在函數體中修改了_p所指向的內容也就修改了p所指向的內容,這也就是指針可以作為輸出參數的根本原因。但是在getMem函數中,臨時的副本_p申請了一個新的內存空間,從而把_p所指向的空間改變了,從此再改變_p所指向的內容時,原來p所指向的內容被沒有變化。而且這裡沒有使用free函數釋放內存,從而在每次執行getMem的時候還會洩露一塊內存。

解決辦法:通過指向指針的指針   或者   返回指針
(1)指向指針的指針
void getMem1(char **p, int num)
{
         *p=(char*)malloc(sizeof(char) * num);
}
void  test1(void)
{
         char*str = NULL;
         getMem1(&str,100);         //注意這裡是&str
         strcpy(str,“hello”);
         cout<<str<<endl;
         free(str);   //不要忘了釋放內存
}
 
(2)使用return返回指針
使用函數的返回值來動態傳遞內存的這種做法雖然比較好,但是有時候程序員常常會把return語句返回的結果弄錯掉。主要是強調不要使用return語句返回指向棧內存的指針,因為該內存在函數結束的時候將會被釋放,下次再訪問該內存空間時存儲的很可能不是原來的數據。例如:
#include "stdafx.h"
#include <iostream>
using namespace std;
 
char  *getStr(void)
{
         char  str1[] = "hello world";//這個數據存儲在棧上,在這個函數階數之後這個空間將會被釋放。
                                      //由於返回的str指向的是這個地址,在以後再次用到這個地址時
                                      //由於str這個空間已經被分配給其他變量,所以之後對str的操作
                                      //會出錯。
         cout<<"str1[]的地址"<<&str1<<endl;
         returnstr1;  //這裡編譯器會提出警告,VC6.0中返回的地址為0x0012FE90
}
 
void  test()
{
         char*str2=NULL;
         str2= getStr(); //這裡str2=0x0012FEF0
         cout<<"str2的地址"<<&str2<<endl;
         cout<<str2<<endl;//打印出來的並不是 hello world  而是一串比較亂的字符,因為並不知道str2裡面存的是什麼
}
 
void main(void)
{
         test();
}
注釋:其實這裡可以把下面這個函數中的變量定義做些修改:
char  *getStr(void)
{
         char  str1[] = "hello world";
}
這個函數裡的變量定義到靜態存儲區中就可以實現輸出“hello world”
例如 static char str1[] = “hello world”; 或者 char *p = “hello world”;//這裡需要注意一下第二種方法定義的是一種字符常量
 作者:qingtingchen1987

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved