最近重新溫習了一下c++的指標,發現以前沒有理解的東西好像開始有點懂了
雖然指標這種東西挺煩人的,但是弄懂了總比沒懂要好
首先是指標的宣告
typename * ptrname;
要指向什麼樣的型別就宣告為什麼樣的型別,比如:
int * ptr; ptr就是乙個指向int資料的指標,相信有的小夥伴對於*運算子兩邊的空格有一點困惑,可能你會在書上看到int *ptr是c程式設計師的習慣,int* ptr是c++程式設計師的習慣,不過具體怎麼用看你個人習慣,反正在**新增空格對於底層編譯器來說沒有任何區別
宣告了指標就要知道指標該怎麼用了
首先是指標的賦值操作
1.可以對已有的變數取址之後賦給指標,
比如:int a = 3;
int *pa;
pa = &a;
這樣賦值之後,指標pa就指向了變數a所在的記憶體空間了
2.可以通過new運算子來初始化指標
int *ptr = new int;
經過初始化之後,指標就指向乙個沒有命名的存放int型別的記憶體空間了
獲取指標指向記憶體空間中存放的資料可以用*運算子,這裡說一下我以前也很困惑的問題,現在才搞明白,起始int*可以認為是指標變數的型別,如果按照上面的那句宣告 typename * ptrname; 說明ptrname是乙個
typename *型別的指標,如果要對他進行取值,那麼在指標變數前面加上*運算子就可以了
int a = 3;
int *pa = &a;
cout << *pa << endl;
cout << a << endl;
可以看到輸出結果都是3
接下來來說一說指標的運算
指標是一種變數,自然就可以進行運算操作,普遍的計算機中,指標變數是乙個32位的無符號整型(直觀體現就是電腦裡面的位址值一般都是8位的16進製制數)
先來說說加法運算
c++允許指標變數和整數相加(剛剛提到,指標變數實際上是乙個整型)不過講他加上1之後,結果等於原來的值加上指向物件佔的位元組數
double *pdouble = ;
cout << "pdouble = " << pdouble << endl;
pdouble = pdouble + 1;
cout << "pdouble + 1 = " << pdouble << endl;
下面是輸出結果
可以看到pdouble+1之後位址值增加了8,這是因為指標pdouble指向的物件為double型別,每乙個double型別的資料佔8個位元組,所以將指標的值加1可以理解為將指標移動到指向下乙個資料
這裡要說明的是,陣列的名字也是乙個指標,指向陣列的第乙個元素,不過它是乙個常量,是不能修改的,直接上**
double doublearr[3] = ;
double *pdouble = doublearr;
cout << "doublearr = " << doublearr << endl;
cout << "pdouble = " << pdouble << endl;
cout << "&doublearr[0] = " << &doublearr[0] << endl;
下面是輸出結果:
當你厭倦了通過常規方式訪問陣列元素時,可以嘗試一下通過指標來訪問,具體方式是*(ptr+i), i就表示訪問元素的下標,不過要注意的是,括號是不能省略的,先上**
double doublearr[3] = ;
double *pdouble = doublearr;
cout << "doublearr[1] = " << doublearr[1] << endl;
cout << "*(pdouble + 1) = " << *(pdouble + 1) << endl;
cout << "*pdouble + 1 = " << *pdouble + 1 << endl;
執行結果如下:
前面兩行正常,最後一行結果明顯不同,原因就是*運算子的優先順序比+運算子的優先順序高,如果不加括號,那麼就會先進行取值操作,這樣取到的就是下標為0的元素了,結果也就變成了2
指標的還有乙個作用是用來建立動態陣列,也就是在執行時設定陣列的長度
一般的陣列在宣告時就制定大小,也就是說陣列的長度在編譯時就確定了
如:int arr[20]
如果使用new 運算子建立陣列,就可以根據實際需要在執行時指定陣列的大小:
如:int size;
cin >> size;
int *arr = new int[size];
現在再來講一下字串和指標,先看一段**吧,便於理解:
int intarr[3] = ;
int *intptr = intarr;
char strarr[10] = "strarr";
char *strptr = strarr;
const char *conststrptr = "conststrptr";
cout << "intarr = " << intarr << endl;
cout << "intptr = " << intptr << endl;
cout << "strarr = " << strarr << endl;
cout << "strptr = " << strptr << endl;
cout << "conststrptr = " << conststrptr << endl;
下面是執行結果:
通過之前的分析我們知道,intarr跟intptr是陣列的第乙個元素的位址值,輸出結果正常;那麼我們也認為strarr,strptr的值也是字串的第乙個字元的位址,但不幸的是輸出了整個字串,這其中的原因就在於cout在處理char的位址時,將它視為字串的位址,也就是說他會繼續吧第乙個字元後面的字元列印出來,直到遇到空字元('\0')
如果這樣你還不能理解,那麼再看下乙個例程
char strarr[10] = "lixin";
char *strptr = strarr;
cout << "strptr = " << strptr << endl;
cout << "after strptr++" << endl;
strptr++;
cout << "strptr = " << strptr << endl;
執行結果如下:
通過這個例程可以知道,如果你傳乙個字元的位址給cout,那麼它會把字元後面的所有內容都輸出直到遇到'\0'
另外要注意的是,通過指標在執行時建立字元陣列時,長度一定要是字串長度+1,因為字串都會隱式的新增乙個空字元在末尾,所以要多開闢乙個空間存放空字元
重新認識container
我還清楚的記得,第一次從 那兒聽說container這個詞 結果他給我解釋了半天還是似懂非懂的。今天,偷閒翻了下posa4,發現裡面對container的解釋特別清楚。粗略的理解下來是,為了分離關注點,而實現的對系統資源的封裝。豁然開朗的發現,os就是應用程式的container。突發奇想的,開發乙...
重新認識測試
以前總覺得測試是軟體開發的邊緣職位,開發人員才是軟體生命週期的核心人員。隨著對網際網路公司的了解,逐步了解到測試的重要性。以bat為例,三家公司均設定了測試開發工程師崗位,該崗位的主要職責就是編寫自動化測試案例,通過對 的邏輯進行分析,設計出能夠覆蓋大部分 的測試用例。如阿里的測試開發工程師的崗位描...
重新認識ARC
雖然用了很久的arc,感受了 簡潔。但是對arc底層實現並不了解。今天抽空研究了下,做些簡單地總結。一 strong 1.區域性變數 對於區域性變數來說,在超出作用域的地方由編譯器自動插入release。大概轉化為 在非arc返回的autorelease型別的方法 在blog手碼大概 如有錯誤還望指...