欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++掃盲篇之指針詳解

 更新時(shí)間:2022年03月25日 16:42:48   作者:思想覺悟  
C++中一個(gè)指針的使用就已經(jīng)讓很多人欲哭無淚,可是更不幸的是他還有指向指針的指針,這篇文章主要給大家介紹了關(guān)于C++掃盲篇之指針的相關(guān)資料,需要的朋友可以參考下

前言

指針對于學(xué)習(xí)C/C++的人來說是一道必須邁過去的坎,就像學(xué)習(xí)九陽神功必須要打通任督二脈一樣的道理。雖然說隨著智能指針的普及,很少需要程序員再手動(dòng)操作原始指針, 但是如果你連原始指針的都沒學(xué)好,那你怎么可能用好智能指針呢?

無論是原始指針還是智能指針,要想用好它就一定要做到知其然,知其所以然。

因?yàn)楸疚拈喿x對象是有了一定指針基礎(chǔ)的童鞋,所以如果你對指針如果是處于一無所知的狀態(tài)的話,建議先去溫習(xí)下指針的基礎(chǔ)知識,不然可能讀起來會(huì)打擊你求知的欲望。

指針為什么要有類型

是為了指針運(yùn)算和取值。

當(dāng)使用指針取值的時(shí)候需要知道怎么取值,比如按照多少個(gè)字節(jié)去取值,這是需要確定才能取到正確的值的,要知道用多少個(gè)字節(jié)去取就得知道指針的類型是什么。

我們知道指針的運(yùn)算增加或者減少1意味著需要偏移指針?biāo)硎镜念愋偷拇笮€(gè)字節(jié)數(shù),比如說一個(gè)int字節(jié)的指針增加1,表示偏移4個(gè)字節(jié)(一般情況下int都是4個(gè)字節(jié)),所以這也是需要知道指針的類型。

指針和數(shù)組

本來從字面上來說指針和數(shù)組是八竿子打不著的,它們理應(yīng)是井水不犯河水的,怎么就扯上了呢?我們經(jīng)常聽說數(shù)組指針、指針數(shù)組,這些都是什么意思呢?他們到底是指針還是數(shù)組呢?下面將一一為你解答。

指針數(shù)組,首先它是一個(gè)數(shù)組,數(shù)組里面的每個(gè)元素都是一個(gè)指針,例如比如int *p[4] 就是一個(gè)指針數(shù)組,因?yàn)檫\(yùn)算符[]的優(yōu)先級運(yùn)算符*的優(yōu)先級高,所以p優(yōu)先和[]組成數(shù)組,然后*和類型int組合成數(shù)組元素的類型。 例如以下程序就是一個(gè)指針數(shù)組的示例:

main.c
#include <stdio.h>
int main(){
    char *str[3] = {
        "我是數(shù)組1",
        "我是數(shù)組2",
        "我是數(shù)組3"
    };
    printf("%s\n%s\n%s\n", str[0], str[1], str[2]);
    return 0;
}

數(shù)組指針,首先它是一個(gè)指針,這個(gè)指針?biāo)赶虻膶ο笫菙?shù)組,比如這個(gè)指針是p,那么通過解引用*p獲得內(nèi)容就是一個(gè)數(shù)組,例如int (*p)[4],主意帶上括號, 通常數(shù)組指針也作為一個(gè)二維數(shù)組來使用。

二級指針

所謂的二級指針其實(shí)就是一個(gè)指向指針的指針,例如int **p就是一個(gè)二級指針,它內(nèi)部存放的對象是一個(gè)指針,通過一次解引用獲得的是內(nèi)存存放的指針的地址,需要再次對這個(gè)內(nèi)部的指針進(jìn)行解引用才能獲取到 這個(gè)真是內(nèi)容的值。

理解起來有點(diǎn)繞,那么這個(gè)拗口的二級指針有什么作用呢?二級指針在C++中可能用的不多,但是在C中是經(jīng)常使用的一把利器,它通常作為一個(gè)函數(shù)的參數(shù),起到在函數(shù)內(nèi)部對一個(gè)指針進(jìn)行初始化的作用, 比如經(jīng)典的音視頻處理工具FFmpeg中就大量使用了二級指針。 以下例子展示如何通過二級指針對指針形式賦值:

main.cpp
void initP(int **p){
    *p = new int(10);
}

int main() {
    int *p = nullptr; // 一個(gè)空的指針
    initP(&p); // 通過二級指針初始化指針p
    std::cout << "*p的值:" << *p << endl;
    delete p;
    return 0;
}

可能在這里就有人和當(dāng)初筆者剛接觸C語言一樣迷惑了,難道不能通過給函數(shù)傳遞一級指針給指針初始化嗎?這是不行的,這是因?yàn)橹祩鬟f的緣故,像深入探討的童鞋們可以寫個(gè)例子打印下實(shí)參的具體地址對比下研究下其背后的原理。

指針與多態(tài)綁定

我們都知道C++是一門面向?qū)ο蟮脑O(shè)計(jì)語言,支持多態(tài)就是它的一個(gè)重要特性之一,在學(xué)習(xí)C++類的相關(guān)知識的時(shí)候老師就告訴我們:*在C++語言中,當(dāng)我們使用基類的引用(或指針)調(diào)用一個(gè)虛函數(shù)時(shí)將發(fā)生動(dòng)態(tài)綁定。*也就是 說使用通過父類的指針或引用就能按照實(shí)參的實(shí)際類型是父類還是子類調(diào)用不同的虛函數(shù)。

例如如以下代碼:

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(); // 指針,動(dòng)態(tài)類型與靜態(tài)類型不一致
    testPrint(*c); // 打印Child print

    Base &&r = Child(); // 表達(dá)式是右值引用,動(dòng)態(tài)類型與靜態(tài)類型不一致
    testPrint(r); // 打印Child print
    return 0;
}

為什么在上面的程序中變量a的實(shí)際類型是Child,但是函數(shù)testPrint內(nèi)部調(diào)用的卻是父類的打印方法呢?不是說引用會(huì)觸發(fā)多態(tài)嗎?函數(shù)testPrint也是通過引用傳遞的呀, 真是百思不得其jie呀。

要解開這個(gè)疑惑就得了解下靜態(tài)類型和動(dòng)態(tài)類型的知識了。靜態(tài)類型在編譯時(shí)總是已知的,首先靜態(tài)類型是變量聲明時(shí)的類型或表達(dá)式生成的類型;動(dòng)態(tài)類型則是變量或表達(dá)式表示的內(nèi)存中的對象的類型,動(dòng)態(tài)類型直到運(yùn)行時(shí)才可知。 如果變量在定義時(shí)表達(dá)式既不是引用也不是指針,則它的動(dòng)態(tài)類型永遠(yuǎn)與靜態(tài)類型一致的,也就是聲明時(shí)所指的類型,否則的話靜態(tài)類型可能與動(dòng)態(tài)類型不一致。

那么有了靜態(tài)類型與動(dòng)態(tài)類型的概念之后再結(jié)合注釋看上面的示例代碼是不是就有一種撥開云霧見青天的感覺了呢?

函數(shù)指針

函數(shù)指針顧名思義就是指向函數(shù)的指針,它的定義:函數(shù)指針是指向函數(shù)的指針變量。因此“函數(shù)指針”本身首先應(yīng)是指針變量,只不過該指針變量指向函數(shù)。

其聲明方式是:

返回值類型 (*函數(shù)名) (參數(shù))  

函數(shù)指針的一個(gè)重要用途就是作為函數(shù)的參數(shù),用于在函數(shù)內(nèi)部進(jìn)行指針函數(shù)的調(diào)用,一般用作回調(diào)函數(shù),比如在創(chuàng)建一個(gè)POSIX線程的就需要傳遞一個(gè)函數(shù)指針用于指明該線程做點(diǎn)什么事情。

以下代碼展示了一個(gè)簡單的函數(shù)指針的使用方法:

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;
}

類成員指針

這里類成員指針表示的是指向類的某個(gè)對象的非靜態(tài)成員的指針,而不是表示類成員變量的指針,首先需要區(qū)分好這是兩個(gè)不同的概念,如果不能好好區(qū)分這兩個(gè)概念的童鞋,需要再好好思考一下。

成員指針的類型囊括了類的類型以及成員的類型。當(dāng)初始化一個(gè)這樣的指針時(shí),我們令其指向類的某個(gè)成員,但是不指定該成員所屬的對象;直到使用成員指針時(shí),才提供成員所屬的對象。

和其他指針一樣,在聲明成員指針時(shí)我們也使用*來表示當(dāng)前聲明的名字是一個(gè)指針。與普通指針不同的是,成員指針還必須包含成員所屬的類。下面是一個(gè)使用的示例:

class Person{
public:
    virtual void print() const{
        std::cout << "base print" << endl;
    }

    virtual ~Person(){
    }

public:
    string lastName;
    string firstName;
};

int main() {
    string Person::*p; // 聲明了一個(gè)類成員指針
    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;
}

至于這個(gè)成員指針有什么用處,給筆者的感覺就是重新命了一個(gè)別名的感覺,甚至有點(diǎn)脫褲子放屁?但是存在即合理,不是沒有用處,只是筆者見過那種場景而已吧。。。

除了有指向類成員變量的指針外還有指向類成員函數(shù)的指針,這里就不多展開探討了?。?!

補(bǔ)充:用指針的指針指向指針數(shù)組

#include<stdio.h> 
int change(char **p)
{
	int i, j;
	for (i = 0; i < 5; i++)
	{
		for (j = 0; *(*(p + i) + j) != '\0'; j++)//利用指針的指針取二維數(shù)組的元素
		{
			*(*(p + i) + j) = 'c';
			printf("%c", *(*(p + i) + j));
		}
		printf("\n");
	}
	return 0;
}
 
int main(void)
{
	char *a[5] = { "hello", "zhuyu", "jiajia", "linux","Ubuntu" };//如果想使用 需使用指針數(shù)組即*a[5] 聲明一個(gè)有五個(gè)字符串指針的數(shù)組。
	                                                              //但是由于每個(gè)元素都是指針字符串,所以只能夠讀取,而不能夠?qū)懭搿?
	change(a);
	return 0;
}

總結(jié)

到此這篇關(guān)于C++掃盲篇之指針的文章就介紹到這了,更多相關(guān)C++指針掃盲內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論