C++<第九篇>:指針

系統(tǒng)的內(nèi)存就像是帶有編號(hào)的小房間,如果想要使用內(nèi)存就需要得到房間號(hào),這個(gè)房間號(hào) 就是地址。
通過(guò)地址可以找到指定的內(nèi)存單元。
在C++語(yǔ)言中,有專門用來(lái)存放內(nèi)存單元地址的變量類型,它就是指針類型。
指針是一種數(shù)據(jù)類型,通常所說(shuō)的指針就是指針變量。
指針和地址其實(shí)是一個(gè)意思,所以指針就是地址,地址就是指針。

一、指針的聲明

聲明指針的一般形式如下:

數(shù)據(jù)類型標(biāo)識(shí) *指針變量名

如:

int *p;
float *p;
char *p;
二、指針的賦值

初始化時(shí)賦值:

int i = 100;
int* p = &i;

cout << "i的地址:" << p << endl;

先聲明后賦值:

int i = 100;
int* p;
p = &i;

cout << "i的地址:" << p << endl;

輸出的結(jié)果是:

i的地址:00000018046FFC04

符號(hào)&(取址符)的作用是:獲取變量的地址;

三、指針運(yùn)算

指針變量可以++(p++),也可以--(p--),可以將指針指向上一個(gè)或者下一個(gè)內(nèi)存地址。

先看下代碼:

int i = 100;
int* p;
p = &i;
cout << "i的地址:" << p << endl;
p++;
cout << "i的地址:" << p << endl;
p++;
cout << "i的地址:" << p << endl;
p++;
cout << "i的地址:" << p << endl;
p++;
cout << "i的地址:" << p << endl;

輸出結(jié)果是:

i的地址:000000AFDC8FF9A4
i的地址:000000AFDC8FF9A8
i的地址:000000AFDC8FF9AC
i的地址:000000AFDC8FF9B0
i的地址:000000AFDC8FF9B4

當(dāng)前指針的類型是int類型,int占用4個(gè)字節(jié),所以地址和地址之間的跨度是4個(gè)字節(jié)。

再看下代碼:

int16_t i = 6;
int16_t * p;
p = &i;
cout << "i的地址:" << p << endl;
p++;
cout << "i的地址:" << p << endl;
p++;
cout << "i的地址:" << p << endl;
p++;
cout << "i的地址:" << p << endl;
p++;
cout << "i的地址:" << p << endl;

我們將int換成了int16_t,int16_t占2個(gè)字節(jié)。輸出結(jié)果是:

i的地址:000000D0F66FF9B4
i的地址:000000D0F66FF9B6
i的地址:000000D0F66FF9B8
i的地址:000000D0F66FF9BA
i的地址:000000D0F66FF9BC

可以看到,地址和地址之間的跨度變成了2個(gè)字節(jié)。

所以,可以使用自增和自減運(yùn)算符將指針指向下(上)一個(gè)地址。

四、指向空的指針和空類型指針

(1)指向空的指針

int * p;

如上代碼的指針p沒有被初始化,沒有被初始化的指針都不可以使用,一旦使用沒有初始化的指針程序?qū)⒈罎?,這是比較危險(xiǎn)的。
有時(shí)候,我們寧愿先將指針指向空:

int * p = NULL;

使用指向空的指針程序不會(huì)崩潰。

如果要輸出p,p的輸出結(jié)果是:

0000000000000000

(2)空類型的指針

void* PI;

使用void修飾數(shù)據(jù)類型的指針?lè)Q為空類型的指針,空類型的指針可以被任意類型接受,如:

int i = 6;
void* PI = &i;

有必要的話,可以使用強(qiáng)制轉(zhuǎn)換:

(int *)PI
五、指針與數(shù)組

指針可以指向數(shù)組

int a[] = {1, 2, 3, 4, 5};
int* p = a; // 指向第一個(gè)元素

cout << p << endl;
cout << *p << endl;

如上代碼,指針變量p指向了數(shù)組a,a默認(rèn)是第一個(gè)元素的地址。

那么如何指向第二個(gè)元素呢?

int* p = a + 1;

或者

int* p = a;
p++;

由于數(shù)組是一個(gè)連續(xù)的空間,所以以上的寫法成立。

所以,指針可以遍歷數(shù)組,代碼如下:

int a[] = {1, 2, 3, 4, 5};
int* p = a;
int len = sizeof(a) / sizeof(int);
for (size_t i = 0; i < len; i++)
{
    cout << *p++ << endl;
}

二維數(shù)組也是一樣,也可以使用指針遍歷。

指針可以遍歷字符串,代碼如下:

char str[] = "hello word"; // 聲明并初始化字符串
char* p = str; // 將指針指向字符串str

while (*p != '\0')
{
    cout << *p++;
}
cout << endl;

字符串的結(jié)尾必然是字符“\0”,所以可以利用這個(gè)特性遍歷字符串。

指針可以拼接字符串,代碼如下:

char str1[20] = "my name is ";
char str2[] = "zhangsan";
char* p1 = str1;
char* p2 = str2;

// 將指針指向str1的末尾
while (*p1 != '\0')
{
    p1++;
}

// 將p2拼接到p2后面
while (*p2 != '\0')
{
    *p1++ = *p2++;
}
*p1 = '\0';

cout << str1 << endl;
六、指針在函數(shù)中的使用

先看下代碼,實(shí)現(xiàn)數(shù)據(jù)交換的功能:

#include <iostream>
#include <string>

using namespace std;

void swap(int a, int b);

int main()
{
    int x = 3;
    int y = 4;

    swap(x, y);

    cout << "x=" << x << endl;
    cout << "y=" << y << endl;

    return 0;
}

void swap(int a, int b) {
    int tmp;
    tmp = a;
    a = b;
    b = tmp;
}

輸出結(jié)果是:

x=3
y=4

需要在注意的是:swap方法必須聲明,否則默認(rèn)調(diào)用xkeycheck.h中的swap方法;

依據(jù)輸出結(jié)果可以看出,交換功能沒有實(shí)現(xiàn),因?yàn)楫?dāng)x,y做為實(shí)參傳遞給swap時(shí)就會(huì)產(chǎn)生x、y的副本,swap的方法實(shí)現(xiàn)只是x、y副本的交換;

我們可以將交換的代碼放在main方法中,這樣就不會(huì)產(chǎn)生副本:

int x = 3;
int y = 4;

int tmp;
tmp = x;
x = y;
y = tmp;

cout << "x=" << x << endl;
cout << "y=" << y << endl;

但是,數(shù)據(jù)的交換屬于一種功能,從代碼優(yōu)化的角度上來(lái)說(shuō),我們應(yīng)該將數(shù)據(jù)交換功能的代碼單獨(dú)提取出來(lái)用一個(gè)方法來(lái)封裝。

我們可以使用指針的方式實(shí)現(xiàn)數(shù)據(jù)的交換:

#include <iostream>
#include <string>

using namespace std;

void swap(int* a, int* b);

int main()
{
    int x = 3;
    int y = 4;

    swap(&x, &y);

    cout << "x=" << x << endl;
    cout << "y=" << y << endl;

    return 0;
}

void swap(int* a, int* b) {
    int tmp;
    tmp = *a;
    *a = *b;
    *b = tmp;
}

輸出結(jié)果是:

x=4
y=3

依據(jù)輸出結(jié)果得出結(jié)論,使用指針做為參數(shù)的方法,可以真正實(shí)現(xiàn)數(shù)據(jù)的交換。

七、引用

我們可以使用引用的方式實(shí)現(xiàn)數(shù)據(jù)的交換。

在xkeycheck.h中,有一個(gè)swap方法:

_CONSTEXPR20 void swap(_Ty& _Left, _Ty& _Right) noexcept(
    is_nothrow_move_constructible_v<_Ty>&& is_nothrow_move_assignable_v<_Ty>) {
    _Ty _Tmp = _STD move(_Left);
    _Left    = _STD move(_Right);
    _Right   = _STD move(_Tmp);
}

這個(gè)函數(shù)的形式參數(shù)變量使用“&”做為變量的引用。那么我們完全可以用引用的方式寫一個(gè)數(shù)據(jù)交換的功能,代碼如下:

#include <iostream>
#include <string>

using namespace std;

int main()
{
    int x = 3;
    int y = 4;

    swap(x, y);

    cout << "x=" << x << endl;
    cout << "y=" << y << endl;

    return 0;
}

void swap(int& a, int& b) {
    int tmp;
    tmp = a;
    a = b;
    b = tmp;
}
八、指向函數(shù)的指針

代碼如下:

#include <iostream>
#include <string>

using namespace std;

int sum(int a, int b);

int main()
{
    int x = 3;
    int y = 4;

    int(*p)(int, int) = sum;
    int s = (*p)(x, y);
    cout << "s=" << s << endl;

    return 0;
}

int sum(int a, int b) {
    return a + b;
}


int(*p)(int, int) = sum將指針指向函數(shù)sum,(int, int)做為函數(shù)sum的形式參數(shù),(*p)(x, y)將值傳入函數(shù),s是函數(shù)sum的返回值。
九、數(shù)組指針和指針數(shù)組

(1)數(shù)組指針

int a[][2] = {1,2,3,4};
int(*p)[2];
p = a;

a是一個(gè)二維數(shù)組,指針p就是a的行,所以數(shù)組指針也稱指向一維數(shù)組的指針,亦稱行指針。

(2)指針數(shù)組

指針數(shù)組的聲明形式是:

int *a[];

指針數(shù)組中的值都是地址。

演示代碼如下:

int x = 3;
int y = 4;

int *a[] = {&x, &y};

for (size_t i = 0; i < 2; i++)
{
    cout << a[i] << endl;
}

輸出結(jié)果是:

00000025E70FFAA4
00000025E70FFAC4

指針數(shù)組中每個(gè)元素占用8個(gè)字節(jié)的內(nèi)存空間。

如果想要輸出具體的值,代碼如下:

int x = 3;
int y = 4;

int *a[] = {&x, &y};

for (size_t i = 0; i < 2; i++)
{
    cout << *a[i] << endl;
}

a[i]存儲(chǔ)的是一個(gè)指針(地址),所以只要將a[i]改成 *a[i]即可。

指針數(shù)組的元素可以直接賦值為字符串:

const char* a[] = {"hello", "word"};

for (size_t i = 0; i < 2; i++)
{
    cout << a[i] << endl;
}

a[0]就是"hello",a[1]就是"word"。

使用*a[i]可以操作各自元素的字符串。

[本章完...]

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容