您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關C++中指針怎么使用的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
是為了指針運算和取值。
當使用指針取值的時候需要知道怎么取值,比如按照多少個字節去取值,這是需要確定才能取到正確的值的,要知道用多少個字節去取就得知道指針的類型是什么。
我們知道指針的運算增加或者減少1意味著需要偏移指針所表示的類型的大小個字節數,比如說一個int字節的指針增加1,表示偏移4個字節(一般情況下int都是4個字節),所以這也是需要知道指針的類型。
本來從字面上來說指針和數組是八竿子打不著的,它們理應是井水不犯河水的,怎么就扯上了呢?我們經常聽說數組指針、指針數組,這些都是什么意思呢?他們到底是指針還是數組呢?下面將一一為你解答。
指針數組,首先它是一個數組,數組里面的每個元素都是一個指針,例如比如int *p[4]
就是一個指針數組,因為運算符[]的優先級運算符*的優先級高,所以p優先和[]組成數組,然后*和類型int組合成數組元素的類型。 例如以下程序就是一個指針數組的示例:
main.c #include <stdio.h> int main(){ char *str[3] = { "我是數組1", "我是數組2", "我是數組3" }; printf("%s\n%s\n%s\n", str[0], str[1], str[2]); return 0; }
數組指針,首先它是一個指針,這個指針所指向的對象是數組,比如這個指針是p,那么通過解引用*p獲得內容就是一個數組,例如int (*p)[4]
,主意帶上括號, 通常數組指針也作為一個二維數組來使用。
所謂的二級指針其實就是一個指向指針的指針,例如int **p
就是一個二級指針,它內部存放的對象是一個指針,通過一次解引用獲得的是內存存放的指針的地址,需要再次對這個內部的指針進行解引用才能獲取到 這個真是內容的值。
理解起來有點繞,那么這個拗口的二級指針有什么作用呢?二級指針在C++中可能用的不多,但是在C中是經常使用的一把利器,它通常作為一個函數的參數,起到在函數內部對一個指針進行初始化的作用, 比如經典的音視頻處理工具FFmpeg中就大量使用了二級指針。 以下例子展示如何通過二級指針對指針形式賦值:
main.cpp void initP(int **p){ *p = new int(10); } int main() { int *p = nullptr; // 一個空的指針 initP(&p); // 通過二級指針初始化指針p std::cout << "*p的值:" << *p << endl; delete p; return 0; }
可能在這里就有人和當初筆者剛接觸C語言一樣迷惑了,難道不能通過給函數傳遞一級指針給指針初始化嗎?這是不行的,這是因為值傳遞的緣故,像深入探討的童鞋們可以寫個例子打印下實參的具體地址對比下研究下其背后的原理。
我們都知道C++是一門面向對象的設計語言,支持多態就是它的一個重要特性之一,在學習C++類的相關知識的時候老師就告訴我們:*在C++語言中,當我們使用基類的引用(或指針)調用一個虛函數時將發生動態綁定。*也就是 說使用通過父類的指針或引用就能按照實參的實際類型是父類還是子類調用不同的虛函數。
例如如以下代碼:
main.cpp class Base{ public: virtual void print() const{ std::cout << "base print" << endl; } virtual ~Base(){ } }; class Child:public Base{ public: void print() const override{ std::cout << "Child print" << endl; } }; void testPrint(const Base &base){ base.print(); } int main() { Base a = Child(); testPrint(a);// 打印Base print Child b = Child(); // 注意,不能寫成Base b = Child(),否則打印的是Base的print testPrint(b); // 打印Child print Base *c = new Child(); // 指針,動態類型與靜態類型不一致 testPrint(*c); // 打印Child print Base &&r = Child(); // 表達式是右值引用,動態類型與靜態類型不一致 testPrint(r); // 打印Child print return 0; }
為什么在上面的程序中變量a的實際類型是Child,但是函數testPrint內部調用的卻是父類的打印方法呢?不是說引用會觸發多態嗎?函數testPrint也是通過引用傳遞的呀, 真是百思不得其jie呀。
要解開這個疑惑就得了解下靜態類型和動態類型的知識了。靜態類型在編譯時總是已知的,首先靜態類型是變量聲明時的類型或表達式生成的類型;動態類型則是變量或表達式表示的內存中的對象的類型,動態類型直到運行時才可知。 如果變量在定義時表達式既不是引用也不是指針,則它的動態類型永遠與靜態類型一致的,也就是聲明時所指的類型,否則的話靜態類型可能與動態類型不一致。
那么有了靜態類型與動態類型的概念之后再結合注釋看上面的示例代碼是不是就有一種撥開云霧見青天的感覺了呢?
函數指針顧名思義就是指向函數的指針,它的定義:函數指針是指向函數的指針變量。因此“函數指針”本身首先應是指針變量,只不過該指針變量指向函數。
其聲明方式是:
返回值類型 (*函數名) (參數)
函數指針的一個重要用途就是作為函數的參數,用于在函數內部進行指針函數的調用,一般用作回調函數,比如在創建一個POSIX線程的就需要傳遞一個函數指針用于指明該線程做點什么事情。
以下代碼展示了一個簡單的函數指針的使用方法:
void testFunc(int a,int b,void (*func)(int c,int d) ){ // do something func(a,b); } void callback(int a,int b){ } int main() { testFunc(1,2,callback); return 0; }
這里類成員指針表示的是指向類的某個對象的非靜態成員的指針,而不是表示類成員變量的指針,首先需要區分好這是兩個不同的概念,如果不能好好區分這兩個概念的童鞋,需要再好好思考一下。
成員指針的類型囊括了類的類型以及成員的類型。當初始化一個這樣的指針時,我們令其指向類的某個成員,但是不指定該成員所屬的對象;直到使用成員指針時,才提供成員所屬的對象。
和其他指針一樣,在聲明成員指針時我們也使用*來表示當前聲明的名字是一個指針。與普通指針不同的是,成員指針還必須包含成員所屬的類。下面是一個使用的示例:
class Person{ public: virtual void print() const{ std::cout << "base print" << endl; } virtual ~Person(){ } public: string lastName; string firstName; }; int main() { string Person::*p; // 聲明了一個類成員指針 p = &Person::firstName; // 成員變量的指針指向了Peron的name Person person; person.*p = "hello"; // 使用成員指針 p = &Person::lastName; // 成員變量的指針指向了Peron的lastName person.*p = "world"; // 使用成員指針 std::cout << person.firstName << " " << person.lastName << std::endl; return 0; }
至于這個成員指針有什么用處,給筆者的感覺就是重新命了一個別名的感覺,甚至有點脫褲子放屁?但是存在即合理,不是沒有用處,只是筆者見過那種場景而已吧。。。
除了有指向類成員變量的指針外還有指向類成員函數的指針,這里就不多展開探討了!!!
#include<stdio.h> int change(char **p) { int i, j; for (i = 0; i < 5; i++) { for (j = 0; *(*(p + i) + j) != '\0'; j++)//利用指針的指針取二維數組的元素 { *(*(p + i) + j) = 'c'; printf("%c", *(*(p + i) + j)); } printf("\n"); } return 0; } int main(void) { char *a[5] = { "hello", "zhuyu", "jiajia", "linux","Ubuntu" };//如果想使用 需使用指針數組即*a[5] 聲明一個有五個字符串指針的數組。 //但是由于每個元素都是指針字符串,所以只能夠讀取,而不能夠寫入。 change(a); return 0; }
感謝各位的閱讀!關于“C++中指針怎么使用”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。