C++中的指針和引用(非掃盲博文)

考研過後又重新撿起C++的書本開始學習,很多以往學到的現在卻又有所忽略,尤其是C++中指針,引用的問題,這是C++的精妙之處,也是C++難以掌握的一個非常關鍵的點。
總結得不是很全,這個要是所有的都寫上,那花的時間就多了去了,比較適合已經對指針和引用有了一定了解的人看
總結下C++中關於指針和引用的那些事。
指針概念:

int *c;
int a=2;
c=&a;
//指針就是地址,就是指向另外一塊內存
——————————————————————————————————————————————————————
int a=2;
int *c=&2;
//這段代碼和上面一樣,先定義後取地址
______________________________________________________
由於指針指的是地址,所以就可以間接操作變量a
*c=3;
這樣a的值也就變成了3

引用概念:

引用就簡單了,就是取了另外一個名字而已
int a=0;
int &b=a;
然後對b的操作其實也是對a的操作
比如:
b=3;
這樣a也變成3

引用變量就是一個別名!只是給原事物換了個包裝殼用了另外一個名字而已!!!記住這句話,引用的問題就差不多解決了!!!

指針和數組
(這個就有得說了,其中坑也有很多,可我覺得掌握核心要點就好了,如果別人代碼風格比較奇葩就把它改過來)

**一維數組**
int a[4]={1,2,3,4,5};
int *c;
c=a;
這樣就可以用指針c去操作數組a
a[2]=*(c+2);
其實a[2]這樣的寫法在編譯器處理的時候也是處理成*(c+2);只是做個語法糖方便使用,增加可讀性
**二維數組**
<font face="黑體">
int a[4][4]={{1,2,3,4},{1,2,3,4},{1,2,3,4},{1,2,3,4}};
int *c[4];
for(int i=0;i<4;i++)
c[i]=a[i];
----------------------------------------------------------
a[2][2]=*(*(a+2)+2)=*(a[2]+2)三者相等
c[2][2]=*(*(c+2)+2)=*(c[2]+2)三者相等
他們指的東西是相同的
</font>

這些都是比較基礎的指針用法,關於二維數組有一個很容易搞混的地方

int a[2][2] = { {1,2},{3,4} };
這個代碼中
sizeof(a)值是16
sizeof(a[0])是8
sizeof(a[0][0])是4
因爲a指的是整個數組
a[0]就是指第0行
a[0][0]就是指第一個元素

關於指針還有一個很重要的點!就是當函數參數是指針的時候要特別注意
首先:不要產生野指針,因爲野指針是隨便指向一塊內存塊,萬一執行了什麼操作那就會引發大問題,C++編譯器也會有預防野指針亂用的方法,比如

#include<iostream>
using namespace std;
void canshu(char*f)
{
    f = new char;
    *f = 'a';
}
int main()
{

    char *s;
    canshu(s);
    cout << *s << endl;
    getchar();
    return 0;
}
編譯器會報錯,但是把s初始化後可以看下
#include<iostream>
using namespace std;
void canshu(char*f)
{
    f = new char;
    *f = 'a';
}
int main()
{
    char code='b';
    char *s=&b;
    canshu(s);
    cout << *s << endl;
    getchar();
    return 0;
}
但是輸出s仍然還是b

所以在很多時候,當我們把指針作爲實參,並且想將該指針在另外一個函數中給它分配一塊內存,我們通常都是這麼做
(首先我們先來點難度小一點的)
在函數體中改變字符變量的值
方法一:指針法間接操作

void canshu(char*f)
{
    *f = 'q';
}
int main()
{
    char c='w';
    char *s = &c;
    canshu(s);
    cout << *s << endl;
    getchar();
    return 0;
}

方法二:引用法直接更改

void canshu(char &f)
{
    f = 'q';
}
int main()
{
    char c = 'b';
    canshu(c);
    cout << c<< endl;
    getchar();
    return 0;
}

兩道小菜消化消化,離成功就進了一步!

那就回到最初始的題目:
如何在函數體中給傳進來的指針實參分配內存呢?????
1)將形參聲明爲指針引用

void canshu(char*&f)
{
    f = new char;
    *f = 'a';
}

爲什麼這樣就可以了呢?
因爲這就是引用的特性!一個變量是引用的就說明給它什麼,它用的就是什麼,而不會再複製出一個臨時變量出來!
引用變量就是一個別名!只是給原事物換了個包裝殼用了另外一個名字而已!!!記住這句話,引用的問題就差不多解決了!!!
2)採用雙指針
先提一下,之前已經說過了,指針就是地址,指向另一個變量所在的地址,通過它可以間接地去訪問其他變量,我們這裏也可以採用這個方法去控制

void canshu(char**f)
{
    *f = new char;
    **f = 'a';
}
int main()
{
    char c = 'b';
    char *s = &c;
    canshu(&s);//注意區分,這裏的'&'符號的作用是取地址
    cout << *s << endl;
    getchar();
    return 0;
}

這種已經是難度比較高,比較難理解的問題了.掌握了上面指針的問題,掌握了上面所有的指針用法,引用含義,對指針的使用應該是一般都可以應付了,但是C++奧妙無窮,還有很多很多坑需要去慢慢發掘。

上述兩個要點是非常非常重要的點,指針有關函數參數的問題還有一個要點

void canshu(char*f)
{
    int x=sizeof(f);
    //無論傳進來的f值有多大,x的值都是類型的大小值
    char變量爲1字節,那麼就是1
    int變量是4字節,那麼就是4
    double8個字節,那麼就是8
    (這個和電腦,編譯器有關,我是windows10/visual studio下測試)
}

所以當我們傳遞數組,字符串時,取sizeof來得到容量大小是得不到的,還是要另外聲明一個大小做參數比較好,我覺得這樣的函數設置比較安全。

關於引用的一個陷阱:對全局變量進行引用,這樣會出編譯器錯誤
上述例子可以見得,指針和引用有時候可以相互取代,用哪個更好??
答案是能用引用就用引用
一:引用更安全,引用被賦值以後就不能被更改,而指針可以更改指向不同對象(當然你需要用到這個性質的話就使用指針)
二:指針可能產生野指針,而這一點非常致命,容易導致嚴重的bug,而引用不會有這種問題。正因爲指針可以指向對象,可以空值(野指針),可以null,所以需要進行測試,這樣相比,引用的效率就高寫了
三:引用創建的時候必須初始化
總之,指針比引用靈活,引用比指針高效安全,各取所長,就能開發出又靈活多變又安全高效的代碼,這就是C++的魅力之處啊,管中窺豹不外如是!
指針的用途十分廣泛,其實用的比引用多些
把握這幾個點,對於指針的使用會越來越熟練
一:指針移動的時候要先看看指針每次移動多少,這和它類型有關
二:指針賦值的時候看看類型是否匹配
三:指針做函數參數的時候看看你是不是想給傳進來的實參分配內存?
四:處處防止出現野指針,指針不用請賦值爲NULL;
感覺幾個最關鍵的,最容易搞不懂的點都總結了,還有些指針數組和數組指針,函數指針和指針函數,常量引用和引用常量等等等等,先掛幾個鏈接,以後有遇到比較容易搞錯的坑再補一下吧
指針數組和數組指針
指針函數和函數指針
(這個最常見的就是C++ algorithm庫中的sort函數第三個參數了,sort函數默認是遞增,但是改變排序方向就要編寫一個函數作爲參數傳遞進去,本質就是用的函數指針)
常量引用和引用常量

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