C++內存分配及字符串賦值

       本文介紹在Ubuntu12.10g++環境下C++內存分配問題。並由此解釋在用g++編譯時,字符串常量賦值給字符指針類型時提示warningdeprecated conversion from string constant to 'char *'警告的原因

一、C++內存分配

       C++編譯器將應用程序的內存空間分成四個部分,從內存低地址開始依次爲:代碼和常量區(用於存儲只讀的代碼數據和常量值)、全局變量和靜態變量區(用於存儲全局變量和靜態變量)、堆區(用於保存newmalloc申請的內存)、棧區(用於保存函數返回地址、局部變量等)。

我們將用如下代碼來測試我們的假設:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <malloc.h>

using namespace std;

int quanju;/*全局變量,全局區/靜態區(static)*/
void fun(int f_jubu); /*代碼區*/
int main(void)
{
       int m_jubu;/*棧區(stack)*/
       static int m_jingtai;/*靜態變量,全局區/靜態區(static)*/
       const int conInt = 5;/*main中的局部變量,位於棧區,被const修飾,變量值不可變*/
       static const int sconInt = 6;/*常量,位於常量區*/
       char *m_zifum,*m_zifuc = "hello";/*指針本身位於棧。指向字符串"hello",位於代碼區/常量區*/
       char* zifuc_hw = "hello world";/*字符串"hello world",位於常量區*/	
       
       /*正確的賦值方式*/
       char *zif = (char*)malloc(sizeof(char) * 6);
       strcpy(zif, "hello");
       cout<<zif<<endl;
       cout<<m_zifuc<<endl;

       void (*pfun)(int); /*棧區(stack)*/
       int (*pmain)(void);
       pfun=&fun;
       pmain = &main;
       m_zifum = (char *)malloc(sizeof(char)*10);/*指針內容指向分配空間,位於堆區(heap)*/
       pfun(1);
       cout<<"全局變量		:"<<&quanju<<endl;
       cout<<"main靜態變量		:"<<&m_jingtai<<endl;
       cout<<"main字符串常量(hello)	:"<<(void*)m_zifuc<<endl;
       cout<<"main字符串常量(h w)	:"<<(void*)zifuc_hw<<endl;
       cout<<"main局部變量(const修飾):"<<&conInt<<endl;
       cout<<"main靜態整型常量	:"<<&sconInt<<endl;
       cout<<"fun函數代碼地址		:"<<(void*)pfun<<endl;
       cout<<"main函數代碼地址	:"<<(void*)pmain<<endl;
       cout<<"main字符串(堆分配)	:"<<(void*)m_zifum<<endl;
       cout<<"main函數函數指針變量	:"<<&pfun<<endl;
       cout<<"main局部變量		:"<<&m_jubu<<endl;
       cout<<"main局部變量		:"<<&m_zifuc<<endl;
       cout<<"main局部變量		:"<<&m_zifum<<endl;
       return 0;
}
void fun(int f_jubu)
{
       static int f_jingtai;
       char* f_zifuc = "hello";
       cout<<"fun靜態變量		:"<<&f_jingtai<<endl;/*靜態變量,位於靜態區*/
       cout<<"fun字符串常量(hello)	:"<<(void*)f_zifuc<<endl;/*常量,位於常量區,同main中的“hello”地址相同*/
       cout<<"fun形參變量		:"<<&f_jubu<<endl;/*棧區(stack),但是與主函數中m_jubu位於不同的棧*/
       cout<<"fun局部變量		:"<<&f_zifuc<<endl;
}

實驗結果:

hello

fun字符串常量(hello :     0x8048c58

main字符串常量(hello :  0x8048c58

main字符串常量(hw :     0x8048c5e

main靜態整型常量 :         0x8048e64

main函數代碼地址 :         0x80487dc

fun函數代碼地址 :           0x8048a73

fun靜態變量 :                 0x804a0f8

main靜態變量 :               0x804a0fc

全局變量 :                      0x804a0f0

main字符串(堆分配) :     0x9ed0008

fun形參變量 :                 0xbfe0e8b0

fun局部變量 :                 0xbfe0e89c

main函數函數指針變量 : 0xbfe0e8d4

main局部變量 :              0xbfe0e8c8

main局部變量 :              0xbfe0e8d0

main局部變量 :              0xbfe0e8cc

main局部變量(const修飾) :0xbfe879d8

二、堆區和棧區的比較

       兩個區的主要區別在於以下幾個方面:

1、管理方式不同;

2、空間大小不同;

3、能否產生碎片不同;

4、生長方向不同;

5、分配方式不同;

6、分配效率不同;    

       棧是一塊連續的內存空間,具有後進先出的特點因此不存在內存碎片,而且計算機底層直接提供支持,分配效率高。無需程序員管理,編譯器會自動申請和釋放。

       堆的管理方式一般是採用鏈表管理可用的內存塊,當用戶申請一塊內存時,系統從可用內存塊中查找一塊滿足要求的內存空間分配給用戶使用;用戶釋放內存後,系統將其回收。因此堆的內存管理需要由程序員來進行,分配效率不如棧。

三、字符串賦值給指針變量的告警

       在用g++作編譯器時,將字符串常量賦值給指針變量將得到warningdeprecated conversion from string constant to 'char *'的警告。例如:char*ptrSt = “hello”;

這是因爲將字符指針變量ptrSt指向一個位於常量區的字符串常量“hello”。如果在運行時修改ptrSt指向內存的值,例如:ptrSt[0]= 'j',將會拋出異常,在linuxg++下,拋出了“Segmentation fault”的異常。

       因此我們在將一個字符串常量賦值給字符指針變量時,應該將該變量限定爲const型,即const char*。如果需要在代碼中修改字符指針指向的變量的值,應該採用如下兩種方式:

chars[] = “hello”;
char*ptrSt = s;

或者

char*ptrSt = (char*)malloc(sizeof(char) * 6);
strcpy(ptrSt,“hello”);

Reference

1.C++內存分配方式詳解——堆、棧、自由存儲區、全局/靜態存儲區和常量存儲區

2.C/C++編程:結合內存分佈圖分析內存問題

3.關於程序設計的內存分配問題

4.關於函數字符數組調用的問題(沒有搞清指針的概念)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章