1. 程式人生 > >C/C++(C++內存管理,內聯函數,類型轉換,命名空間,string類)

C/C++(C++內存管理,內聯函數,類型轉換,命名空間,string類)

多個 產生 沒有 turn out 強制類型轉化 表現 高度 變量

內存管理

new/delete

C語言中提供了 malloc 和 free 兩個系統函數,#include

struct Stu
{
int age;
string name;
};
Stu* pStu = new Stu{23,"assassin"};
cout<

char *p = new int[4];
strcpy(p,"china");
cout<<p<<endl;

int *pi = new int[5];
//int *pi = new int[5]{0};//初始化0,一般不這樣
memset(pi,0,sizeof(int[5]));//初始化
for(int i = 0
;i < 5;i++) { cout<<pi[i]<<endl; }

生成指針數組:

char **p = new char*[5]{NULL};
p[0] = "assassin";
p[1] = "automan";
p[2] = "wunworld";
while(*p)
{
    cout<<*p++<<endl;
}
/*
assassin
automan
wunworld
*/

生成二維數組;

int (*pa)[4] = new int[3][4]{{0}};//初始化
for(int i = 0;i < sizeof(int
[3][4])/sizeof(int[4]);i++) { for(int j = 0;j < 4;j++) { cout<<pa[i][j]<<" "; } cout<<endl; } /* 0 0 0 0 0 0 0 0 0 0 0 0 */ //多維 int (*ppp) [3][4][5] = new int[2][3][4];

釋放delete:

int *p = new int;
delete p;
int *a = new int[100];
delete []a;//正確的釋放
delete a;//只把第一個釋放了

int (*aa)[4
] = new int[3][4]; delete []aa;//多位的數組也是一個方括號,底層用遞歸

註意事項

1,new/delete 是關鍵字,效率高於 malloc 和 free.
2,配對使用,避免內存泄漏和多重釋放。
3,避免,交叉使用。比如 malloc 申請的空間去 delete,new 出的空間被 free;

//c
int *p = (int *)malloc(100);
if(NULL == p)
    return -1;
//c++
int *pi = new (std::nothrow) int[100];
if(pi == NULL)
    return -1;

內聯函數(inline function)

c 語言中有宏函數的概念。宏函數的特點是內嵌到調用代碼中去,避免了函數調用的開銷。但是由於宏函數的處理發生在預處理階段,缺失了語法檢測和有可能帶來的語意差錯,容易使得內存text段體積變大,不會類型檢查。

#define SQR(i) ((i)*(i))
int main()
{
    int i=0;
    while(i<5)
    {
        // printf("%d\n",SQR(i++));
        printf("%d\n",sqr(i++));
    }
    return 0;
}

int sqr(int i)
{
    return i*i;
}
/*
優點:一段高度抽象的邏輯,不易產生歧義,是的text段體積變小,會類型檢查。
缺點:函數調用的壓棧與出棧的開銷
*/

內聯函數兼有宏和函數的優點。系統自己有一套優化方案,inline變成了給編譯器的一種建議。

inline int sqr(int i)
{
    return i*i;
}

評價
優點:避免調用時的額外開銷(入棧與出棧操作)
代價: 由於內聯函數的函數體在代碼段中會出現多個“副本”,因此會增加代碼段的空間。
本質:以犧牲代碼段空間為代價,提高程序的運行時間的效率。
適用場景:函數體很“小”,且被“頻繁”調用。

強制類型轉化

static_cast 
//對於隱時類型可以轉化的
reinterpret_cast
//對於無隱式的類型轉化,static_cast不可用
const_cast
//
dynamic_cast
//

static_cast

float a = 5.6;
int b = 5;

b = static_cast<int>(a);//把a轉成int賦值給b

void *p,int *q;
p = q;//可以
q = p;//不可以,任何指針都可以賦值給void *類型,但是void *類型不可以賦值給指針類型。
q = static_cast<int*>(p);

reinterpret_cast

int a[5] = {1,2,3,4,5};
int *p = reinterpret_cast<int*>((reinterpret_cast<int>(a)+1));

const_cast
( 脫) 常類型轉換,只能引用與指針與引用
const 一定不可以修改

void func(const int &r)
{

}
void func2(int & v)
{
    cout<<v<<endl;
}

int main()
{
    const int a = 19;
    func(10);//可以
    func(a+10);//可以,應為參數中有const修飾。
    func2(const_cast<int&>(a));//因為a是const int類型
    int & ra = const_cast<int&>(a);
    ra = 200;
    cout<<"a = "<<a<<" ra= "<<ra<<endl;
    cout<<"&a = "<<&a<<" ra = "<<&ra<<endl;
    /*
    a = 19 ra = 200
    &a = 0x... 不一樣
    */
}

用來移除對象的常量性(cast away the constness)使用 const_cast 去除 const 限定的目的不是為了修改它的內容,使用 const_cast 去除 const 限定,通常是為了函數能夠接受這個實際參數。
可以改變 const 自定義類的成員變量,但是對於內置數據類型,卻表現未定義行為 .

const 常變量

#defined N 200 //宏,在於處理的發生了替換
const int a = 100;//編譯階段發生了替換
//const 永遠不會發生改變

命名空間(namespace scope)

//全局無名空間
int v = 55;
int main()
{
    int *p = &v;//訪問全局的
    int v =5;
    cout<<v<<endl;//5
    cout<<*p<<endl;//55

    cout<<::v<<endl;//::作用域運算符,前面要命名空間,平常調配用的函數之前省略::
    
    return 0;
}

namespace 是對全局命名空間的再次劃分

#include<iostream>
using namespace std;
namespace Spac{
    int a;//全局變量 
    struct Stu{};//數據類型 
    void func();//函數 
    namespace//其它命名空間 
}

使用:

#include<iostream>
using namespace std;
namespace Space {
    int x;
    int y;
}
namespace Other {
    int x;
    int y;
}
int main()
{
    Space::x = 200;//這種與本地的不會沖突
    cout<<Space::x<<endl;//200

    using Space::x;//在這作用域內的x都是Space命名空間中的x
    x = 20;
    cout<<x<<endl;

    using Space Space;//直接把Space這個命名空間打開
    x = 20;
    y = 30;


    return 0;
}

各種之間沖突解決

利用最小單位的作用域塊

#include<iostream>
using namespace std;//標中庫空間命名
namespace Space {
    int x;
    int y;
}
namespace Other {
    int x;
    int y;
}
int main()
{
    {
        using Space Space;
        x = 20;
        y = 30;
    }
    {
        using Space Other;
        x = 50;
        y = 70;
    }
    int x,y;

    return 0;
}

支持嵌套

namespace Space {
    int x;
    int y;
    namespace Other {
        int m;
        int n;
    }
}
int main()
{
    using namespace Space::Other;//使用Other命名空間中的變量,不建議嵌套
    m = 30;
    return 0;
}

協同開發中的使用

namespace Space {
    int x;
}
namespace Space {
    int y;
}//命名空間相同會自動合並
int main()
{
    using namespace Space;
    x = 10;
    y = 20;
    return 0;
}

系統string類

string是一個類而非關鍵字,初始化比較靈活(類似js中var)

string s = "assassin";//賦值
string s2 = "assassin1";
cout<<s2.size()<<endl;//大小
string s3 = "wunworld";
s3 += s2;//拼接
if(s == s2)//比較 
    cout<<"s = s2"<<endl;
else if(s > s2)
    cout<<"s > s2"<<endl;
else
    cout<<"s < s2"<<endl;

char buf[1024];
strcpy(buf,s.c_str());
//如果和字符連用時,一定用c_str(),返回的是char *類型
//交換swap(string &s2)成員函數
s.swap(s2);

查找:

int find(char c, int pos = 0);
int find(char * s, int pos = 0);
//返回下標值,沒有找到返回-1,默認從 0 下標開找

eg:

string s = "assassin";
int n = s.find("i",0);
cout<<n<<endl;//6

string 類型數組

string sArray[10] = {
                        "0",
                        "1",
                        "22",
                        "333",
                        "4444",
                        "55555",
                        "666666",
                        "7777777",
                        "88888888",
                        "999999999",
};
for(int i=0; i<10; i++)
{
    cout<<sArray[i]<<endl;
}

string 數組是高效的,如果用二維數組來存入字符串數組的話,則容易浪費空間,此時列數是由最長的字符串決定。如果用二級指針申請堆空間,依據大小申請相應的空間,雖然解決了內存浪費的問題,但是操作麻煩。用 string 數組存儲,字符串數組的話,效率即高又靈活。

學習C++的建議:
1、在 C++中幾乎不需要用宏,用 const 或 enum 定義顯式的常量,用 inline 避免函數 調用的額外開銷,用模板去刻畫一族函數或類型,用 namespace 去避免命名沖突。
2、不要在你需要變量之前去聲明,以保證你能立即對它進行初始化。
3、不要用 malloc,new 運算會做的更好。
4、避免使用 void*、指針算術、聯合和強制,大多數情況下,強制都是設計錯誤的指示器。
5、盡量少用數組和 C 風格的字符串,標準庫中的 string 和 vector 可以簡化程序。
6、更加重要的是,試著將程序考慮為一組由類和對象表示的相互作用的概念,而不是一堆數據結構和一些可以撥弄的二進制

C/C++(C++內存管理,內聯函數,類型轉換,命名空間,string類)