C/C++中的指針[非常全面]-創(chuàng)新互聯(lián)

寫(xiě)在最前面

這篇博客很長(zhǎng),基本包含了所有指針及指針相關(guān)的知識(shí)以及一些細(xì)節(jié);相應(yīng)的可能會(huì)有一些羅嗦;認(rèn)真看完一定會(huì)有所收獲(大佬除外)!

成都創(chuàng)新互聯(lián)自2013年起,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目成都做網(wǎng)站、網(wǎng)站建設(shè)、外貿(mào)營(yíng)銷網(wǎng)站建設(shè)網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢(mèng)想脫穎而出為使命,1280元來(lái)賓做網(wǎng)站,已為上家服務(wù),為來(lái)賓各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:18980820575指針

變量被解釋為計(jì)算機(jī)內(nèi)存中的位置,可以通過(guò)它們的標(biāo)識(shí)符(它們的名字)訪問(wèn)。這樣,程序就不需要關(guān)心內(nèi)存中數(shù)據(jù)的物理地址; 它只是在需要引用變量時(shí)使用標(biāo)識(shí)符。

對(duì)于 C + + 程序來(lái)說(shuō),計(jì)算機(jī)的內(nèi)存就像一連串的內(nèi)存單元,每個(gè)單元的大小都是一個(gè)字節(jié),每個(gè)單元的地址都是唯一的。這些單字節(jié)內(nèi)存單元的排序方式允許大于一個(gè)字節(jié)的數(shù)據(jù)表示占用具有連續(xù)地址的內(nèi)存單元。

這樣,每個(gè)單元就可以通過(guò)其唯一地址很容易地定位在內(nèi)存中。例如,地址為1776的內(nèi)存單元總是緊跟在地址為1775的單元之后,在地址為1777的單元之前,正好是776之后的1000個(gè)單元,正好是2776之前的1000個(gè)單元。

當(dāng)聲明一個(gè)變量時(shí),需要存儲(chǔ)它的值被分配到內(nèi)存中的一個(gè)特定位置(它的內(nèi)存地址)。一般來(lái)說(shuō),C + + 程序不會(huì)主動(dòng)確定其變量存儲(chǔ)在確切內(nèi)存地址。這個(gè)任務(wù)留給了運(yùn)行程序的環(huán)境——通常是一個(gè)操作系統(tǒng),它決定運(yùn)行時(shí)的特定內(nèi)存位置。然而,程序能夠在運(yùn)行時(shí)獲取變量的地址,以便訪問(wèn)相對(duì)于變量處于某個(gè)位置的數(shù)據(jù)單元,這是有用的。

取地址運(yùn)算符(&)

變量的地址可以通過(guò)在變量名前面加上與號(hào)(&)(稱為取地址運(yùn)算符操作符)來(lái)獲得。例如:

1
foo = &myvar;

這會(huì)將變量 myvar 的地址分配給 foo; 通過(guò)在變量 myvar 的名稱前面加上 運(yùn)算符 &?,我們不再將變量本身的內(nèi)容分配給 foo,而是將其地址分配給 foo。

內(nèi)存中變量的實(shí)際地址在運(yùn)行時(shí)之前無(wú)法知道,但是為了幫助澄清一些概念,我們假設(shè) myvar 在運(yùn)行時(shí)放置在內(nèi)存地址1776中。

在這種情況下,考慮以下代碼片段:

myvar = 25;
foo = &myvar;
bar = myvar;

每個(gè)變量執(zhí)行后所包含的值如下圖所示:

1b16aaf14e3917e6a5293c5511d69d58.png

首先,我們將值25賦給 myvar (一個(gè)變量,我們假設(shè)它在內(nèi)存中的地址為1776)。

第二個(gè)語(yǔ)句指定 myvar 的地址,我們假設(shè)它是1776。

最后,第三個(gè)語(yǔ)句將 myvar 中包含的值賦給 bar。這是一個(gè)標(biāo)準(zhǔn)的分配操作。

第二個(gè)語(yǔ)句和第三個(gè)語(yǔ)句之間的主要區(qū)別是操作符(&)的出現(xiàn)。

存儲(chǔ)另一個(gè)變量地址的變量(如前面示例中的 foo)在 C + + 中稱為指針。指針是該語(yǔ)言的一個(gè)非常強(qiáng)大的特性,在低級(jí)編程中有許多用途。稍后,我們將看到如何聲明和使用指針。

解引用運(yùn)算符?(*)

如前所述,存儲(chǔ)另一個(gè)變量地址的變量稱為指針。指針被稱為“指向”它們所存儲(chǔ)的地址的變量。

指針的一個(gè)有趣的屬性是,它們可以用來(lái)直接訪問(wèn)它們指向的變量。這是通過(guò)在指針名稱前面加上解引用運(yùn)算符(*)來(lái)完成的。操作符本身可以被讀作“指向的值”。

因此,根據(jù)上一個(gè)示例的值,下面的語(yǔ)句:

baz = *foo;

這可以理解為: “ baz 等于 foo 指向的值”,這個(gè)語(yǔ)句實(shí)際上將值25賦給 baz,因?yàn)?foo 是1776,而1776指向的值(遵循上面的例子)是25。

a6a2dc5878fd1edc791f832652d6043b.png

清楚地區(qū)分 foo 指的是1776,而 * foo (標(biāo)識(shí)符前面帶有星號(hào) *)指的是存儲(chǔ)在地址1776的值,在本例中為25,這一點(diǎn)很重要。注意包含或不包含解引用運(yùn)算符的區(qū)別(我已經(jīng)添加了如何解讀這兩個(gè)表達(dá)的解釋性注釋) :

baz = foo;   // baz equal to foo (1776)
baz = *foo;  // baz equal to value pointed to by foo (25)

因此,引用運(yùn)算符和解引用運(yùn)算符是相輔相成的:

  • &是地址操作符,可以簡(jiǎn)單地理解為“某某的地址”
  • *是解引用運(yùn)算符,可以理解為“指向的值”

因此,它們有相反的含義: 用 & 獲得的地址可以用 * 解引用。

前面,我們執(zhí)行了以下兩個(gè)賦值操作:

myvar = 25;
foo = &myvar;

執(zhí)行上述兩個(gè)語(yǔ)句之后,下列所有表達(dá)式的結(jié)果都是 true:

myvar == 25
&myvar == 1776
foo == 1776
*foo == 25

聲明指針

由于指針能夠直接引用它所指向的值,所以當(dāng)指向 char 時(shí),指針與指向 int 或 float 時(shí)具有不同的屬性。一旦解引用,就需要知道類型。為此,指針的聲明需要包含指針要指向的數(shù)據(jù)類型。

指針的聲明遵循以下語(yǔ)法:

type * name;

其中 type 是指針指向的數(shù)據(jù)類型。此類型不是指針本身的類型,而是指針指向的數(shù)據(jù)的類型。例如:

int * number; char * character; double * decimals;

這是指針的三個(gè)聲明。每個(gè)指針都指向一種不同的數(shù)據(jù)類型,但實(shí)際上,它們都是指針,并且所有指針都可能占用相同的內(nèi)存空間(指針的內(nèi)存大小取決于程序運(yùn)行的平臺(tái))。然而,它們所指向的數(shù)據(jù)不占用相同的空間,也不屬于相同的類型: 第一個(gè)指向 int,第二個(gè)指向 char,最后一個(gè)指向 double。因此,盡管這三個(gè)示例變量都是指針,但它們實(shí)際上有不同的類型: int * 、 char * 和 double * ,這取決于它們指向的類型。

注意,在聲明一個(gè)指針時(shí)使用的星號(hào)(*)僅表示它是一個(gè)指針(它是它的類型復(fù)合說(shuō)明符的一部分) ,不應(yīng)該與之前看到的解引用運(yùn)算符混淆,但它也是用星號(hào)(*)寫(xiě)的。它們只是用同一個(gè)符號(hào)表示的兩個(gè)不同的東西。

讓我們看一個(gè)關(guān)于指針的例子:

// my first pointer
#includeusing namespace std;

int main ()
{
  int firstvalue, secondvalue;
  int * mypointer;

  mypointer = &firstvalue;
  *mypointer = 10;
  mypointer = &secondvalue;
  *mypointer = 20;
  cout<< "firstvalue is "<< firstvalue<< '\n';
  cout<< "secondvalue is "<< secondvalue<< '\n';
  return 0;
}
輸出:
firstvalue is 10
secondvalue is 20?

在 cpp.sh 中編輯和運(yùn)行

注意,即使第一個(gè)值和第二個(gè)值都沒(méi)有在程序中直接設(shè)置任何值,最終都會(huì)通過(guò)使用 mypoint 間接設(shè)置一個(gè)值。

為了證明一個(gè)指針在程序的生命周期內(nèi)可以指向不同的變量,這個(gè)示例使用第二個(gè)值和同一個(gè)指針 mypoint 重復(fù)這個(gè)過(guò)程。

這里有一個(gè)更詳細(xì)的例子:

// more pointers
#includeusing namespace std;

int main ()
{
  int firstvalue = 5, secondvalue = 15;
  int * p1, * p2;

  p1 = &firstvalue;  // p1 = address of firstvalue
  p2 = &secondvalue; // p2 = address of secondvalue
  *p1 = 10;          // value pointed to by p1 = 10
  *p2 = *p1;         // value pointed to by p2 = value pointed to by p1
  p1 = p2;           // p1 = p2 (value of pointer is copied)
  *p1 = 20;          // value pointed to by p1 = 20
  
  cout<< "firstvalue is "<< firstvalue<< '\n';
  cout<< "secondvalue is "<< secondvalue<< '\n';
  return 0;
}
輸出:
firstvalue is 10
secondvalue is 20

Edit & run on cpp.sh

另一件事提醒注意的是

int * p1, * p2;

這聲明了前面示例中使用的兩個(gè)指針。但是請(qǐng)注意,每個(gè)指針都有一個(gè)星號(hào)(*) ,以便兩者都有 int * (指向 int 的指針)類型。由于優(yōu)先級(jí)規(guī)則,這是必需的。注意,如果代碼是:

int * p1, p2;

P1的確是 int * 類型,但是 p2的類型是 int。對(duì)于這個(gè)目的,空間一點(diǎn)也不重要。但是無(wú)論如何,對(duì)于大多數(shù)對(duì)每條語(yǔ)句聲明多個(gè)指針感興趣的指針用戶來(lái)說(shuō),只要記住在每個(gè)指針上加一個(gè)星號(hào)就足夠了。或者更好: 對(duì)每個(gè)變量使用不同的語(yǔ)句。

指針和數(shù)組

數(shù)組的概念與指針的概念有關(guān)。實(shí)際上,數(shù)組的工作方式非常類似于指向它們的第一個(gè)元素的指針,而且,實(shí)際上,數(shù)組總是可以隱式地轉(zhuǎn)換為適當(dāng)類型的指針。例如,考慮以下兩個(gè)聲明:

int myarray [20]; int * mypointer;

下面的賦值操作是有效的:

mypointer = myarray;

之后,mypoint 和 myarray 將是等價(jià)的,并且具有非常相似的屬性。主要的區(qū)別在于,我的指針可以被賦予一個(gè)不同的地址,而 myarray 永遠(yuǎn)不能被賦予任何東西,并且總是表示同一塊20個(gè) int 類型的元素。因此,下列轉(zhuǎn)讓無(wú)效:

myarray = mypointer;

讓我們看一個(gè)混合數(shù)組和指針的例子:

// more pointers
#includeusing namespace std;

int main ()
{
  int numbers[5];
  int * p;
  p = numbers;  *p = 10;
  p++;  *p = 20;
  p = &numbers[2];  *p = 30;
  p = numbers + 3;  *p = 40;
  p = numbers;  *(p+4) = 50;
  for (int n=0; n<5; n++)
    cout<< numbers[n]<< ", ";
  return 0;
}

輸出:

10, 20, 30, 40, 50,

Edit & run on cpp.sh

指針和數(shù)組支持相同的操作集,兩者的含義相同。主要區(qū)別在于,指針可以分配新的地址,而數(shù)組不能。

在關(guān)于數(shù)組的章節(jié)中,方括號(hào)([])被解釋為指定數(shù)組元素的索引。實(shí)際上,這些括號(hào)是一個(gè)解引用運(yùn)算符,稱為偏移運(yùn)算符。它們像 * 一樣解引用它們所跟隨的變量,但是它們也將括號(hào)之間的數(shù)字添加到被解引用的地址。例如:

a[5] = 0;       // a [offset of 5] = 0
*(a+5) = 0;     // pointed to by (a+5) = 0

這兩個(gè)表達(dá)式是等價(jià)和有效的,a不僅?是一個(gè)指針,而且?是一個(gè)數(shù)組。請(qǐng)記住,數(shù)組,它的名稱可以像指向其第一個(gè)元素的指針一樣使用。

指針初始化

指針可以初始化為在定義時(shí)指向特定位置的指針

int myvar; int * myptr = &myvar;

等同于:

int myvar; int * myptr; myptr = &myvar;

初始化指針時(shí),初始化的是指向的地址(即 myptr) ,而不是指向的值(即 * myptr)。因此,上述守則不得與以下面混淆:

int myvar; int * myptr; *myptr = &myvar;

無(wú)論如何,這都沒(méi)有多大意義(而且也不是有效的代碼)。

可以將指針初始化為變量的地址(如上例所示) ,也可以初始化為另一個(gè)指針(或數(shù)組)的值:

int myvar; int *foo = &myvar; int *bar = foo;

指針?biāo)阈g(shù)

對(duì)指針進(jìn)行算術(shù)運(yùn)算與對(duì)正則整數(shù)類型進(jìn)行算術(shù)運(yùn)算略有不同。首先,只允許執(zhí)行加法和減法操作; 其他操作在指針世界中毫無(wú)意義。但是,根據(jù)指針?biāo)赶虻臄?shù)據(jù)類型的大小,加法和減法在使用指針時(shí)的行為略有不同。

當(dāng)引入基本數(shù)據(jù)類型時(shí),我們看到類型具有不同的大小。例如: char 的大小總是1字節(jié),short 通常比這個(gè)大,int 和 long 甚至更大; 它們的確切大小取決于系統(tǒng)。例如,假設(shè)在給定的系統(tǒng)中,char 占用1個(gè)字節(jié),short 占用2個(gè)字節(jié),long 占用4個(gè)字節(jié)。

假設(shè)現(xiàn)在我們?cè)谶@個(gè)編譯器中定義了三個(gè)指針:

char *mychar; short *myshort; long *mylong;

假設(shè)我們知道它們分別指向內(nèi)存位置1000,2000和3000。

因此,如果我們寫(xiě):

++mychar; ++myshort; ++mylong;

正如預(yù)期的那樣,mychar 將包含值1001。但是不那么明顯,myshort 將包含值2002,mylong 將包含3004,盡管它們每個(gè)只增加了一次。原因是,當(dāng)向指針加1時(shí),指針會(huì)指向下面同一類型的元素,因此,它所指向的類型的字節(jié)大小被添加到指針中。

c5ac2e4b915c095e684963c9646daaae.png

這適用于對(duì)指針進(jìn)行任意數(shù)字的加減運(yùn)算。如果我們寫(xiě)下:

mychar = mychar + 1;
myshort = myshort + 1;
mylong = mylong + 1;

關(guān)于遞增(+ +)和遞減(--)操作符,它們都可以用作表達(dá)式的前綴或后綴,但行為略有不同: 作為前綴,遞增發(fā)生在計(jì)算表達(dá)式之前,作為后綴,遞增發(fā)生在計(jì)算表達(dá)式之后。這也適用于遞增和遞減指針的表達(dá)式,這些指針可以成為更復(fù)雜的表達(dá)式的一部分,這些表達(dá)式還包括解引用操作符(*)。記住運(yùn)算符優(yōu)先級(jí)規(guī)則,我們可以回想起后綴運(yùn)算符,如遞增和遞減,比前綴運(yùn)算符,如解引用運(yùn)算符(*)具有更高的優(yōu)先級(jí)。因此,下面的表達(dá):

*p++

等效于 * (p + +)。它所做的是增加 p 的值(所以它現(xiàn)在指向下一個(gè)元素) ,但是因?yàn)?+ + 被用作后綴,所以整個(gè)表達(dá)式被計(jì)算為指針最初指向的值( 指向它在增加之前的地址)。

關(guān)于運(yùn)算符優(yōu)先級(jí):c++ 運(yùn)算符優(yōu)先級(jí)表格

本質(zhì)上,這些是解引用運(yùn)算符與遞增運(yùn)算符的前綴和后綴版本的四種可能的組合(同樣適用于遞減運(yùn)算符) :

*p++   // same as *(p++): increment pointer, and dereference unincremented address
*++p   // same as *(++p): increment pointer, and dereference incremented address
++*p   // same as ++(*p): dereference pointer, and increment the value it points to
(*p)++ // dereference pointer, and post-increment the value it points to

涉及這些運(yùn)算符的一個(gè)典型但不那么簡(jiǎn)單的語(yǔ)句是:

*p++ = *q++;

因?yàn)?+ + 的優(yōu)先級(jí)高于 * ,所以 p 和 q 都是遞增的,但是因?yàn)閮蓚€(gè)遞增運(yùn)算符(+ +)都用作后綴而不是前綴,所以賦給 * p, * q 的值都是在遞增之前?p 和 q。然后兩者再遞增的。這大致相當(dāng)于:?

*p = *q;
++p;
++q;

*p = *q;
++p;
++q;
  • tips:通過(guò)添加括號(hào)(),增加表達(dá)式的易讀性來(lái)減少混淆。

指針與常量

指針可用于根據(jù)地址訪問(wèn)變量,這種訪問(wèn)可能包括修改指向的值。但也可以聲明指針,這些指針可以訪問(wèn)指向的值來(lái)讀取它,但不能修改它。對(duì)于這一點(diǎn),將指針指向的類型限定為 const 就足夠了。例如:

int x;
int y = 10;
const int * p = &y;
x = *p;          // ok: reading p
*p = x;          // error: modifying p, which is const-qualified

這里 p 指向一個(gè)變量,但是以一種常量限定的方式指向它,這意味著它可以讀取指向的值,但是不能修改它。還要注意,表達(dá)式 & y 的類型為 int * ,但是它被賦值給類型為 const int * 的指針。這是允許的: 指向非常數(shù)的指針可以隱式轉(zhuǎn)換為指向常數(shù)的指針。但不是反過(guò)來(lái)!作為一個(gè)安全特性,常量指針不能隱式轉(zhuǎn)換為非常量指針。

指向 const 的元素的指針的用例之一是作為函數(shù)參數(shù): 將非 const 指針作為參數(shù)的函數(shù)可以修改作為參數(shù)傳遞的值,而將 const 指針作為參數(shù)的函數(shù)則不能。

// pointers as arguments:
#includeusing namespace std;

void increment_all (int* start, int* stop)
{
  int * current = start;
  while (current != stop) {
    ++(*current);  // increment value pointed
    ++current;     // increment pointer
  }
}

void print_all (const int* start, const int* stop)
{
  const int * current = start;
  while (current != stop) {
    cout<< *current<< '\n';
    ++current;     // increment pointer
  }
}

int main ()
{
  int numbers[] = {10,20,30};
  increment_all (numbers,numbers+3);
  print_all (numbers,numbers+3);
  return 0;
}

輸出:

11
21
31

注意 print _ all 使用指向常量元素的指針。這些指針指向它們無(wú)法修改的常量?jī)?nèi)容,但它們本身不是常量: 也就是說(shuō),指針仍然可以遞增或分配不同的地址,盡管它們無(wú)法修改它們指向的內(nèi)容。

這就是將常量的第二個(gè)維度添加到指針的地方: 指針本身也可以是常量。這是通過(guò)將 const 附加到指定類型(在星號(hào)之后)來(lái)指定的:

int x;
      int *       p1 = &x;  // non-const pointer to non-const int
const int *       p2 = &x;  // non-const pointer to const int
      int * const p3 = &x;  // const pointer to non-const int
const int * const p4 = &x;  // const pointer to const int

使用 const 和指針的語(yǔ)法肯定是有難度的,并且識(shí)別最適合每種用法的情況往往需要一些經(jīng)驗(yàn)。在任何情況下,盡早正確使用指針(和引用)獲得常量都是很重要的,但是如果您第一次接觸到常量和指針的混合,那么您不應(yīng)該過(guò)于擔(dān)心現(xiàn)在還沒(méi)熟練掌握,慢慢熟悉它。

const 限定符可以在指針類型之前或之后,具有完全相同的含義:

const int * p2a = &x;  //      non-const pointer to const int
int const * p2b = &x;  // also non-const pointer to const int

與星號(hào)周圍的空格一樣,本例中 const 的順序只是一個(gè)樣式問(wèn)題。本章使用前綴 const,由于歷史原因,這似乎更加擴(kuò)展,但兩者完全等價(jià)。每種風(fēng)格的優(yōu)點(diǎn)仍在互聯(lián)網(wǎng)上激烈爭(zhēng)論。

指針和字符串文字

字符串文字是包含以空結(jié)尾的字符序列的數(shù)組。但也可以直接訪問(wèn)。字符串文字是適當(dāng)數(shù)組類型的數(shù)組,它包含所有字符和結(jié)束的 空字符('\0'),每個(gè)元素都是 const char 類型(作為文字,它們永遠(yuǎn)不能被修改)。例如:

const char * foo = "hello";

這將聲明一個(gè)數(shù)組,其文字表示為“ hello”,然后將指向其第一個(gè)元素的指針?lè)峙浣o foo。如果我們假設(shè)“ hello”存儲(chǔ)在從地址1702開(kāi)始的內(nèi)存位置,我們可以將前面的聲明表示為:

f5d4d894b68751a9912ac56658b824fc.png

注意,這里 foo 是一個(gè)指針,包含值1702,而不是“ h”或“ hello”,盡管1702確實(shí)是這兩個(gè)值的地址。
指針 foo 指向一個(gè)字符序列。由于指針和數(shù)組在表達(dá)式中的行為方式基本相同,foo 可以用來(lái)訪問(wèn)字符,其方式與以空結(jié)尾的字符序列的數(shù)組相同。例如:

*(foo+4)
foo[4]?

兩個(gè)表達(dá)式的值都為‘ o’(數(shù)組的第五個(gè)元素)。

指針指向指針

C + + 允許使用指向指針的指針,這些指針依次指向數(shù)據(jù)(甚至指向其他指針)。語(yǔ)法只需要在指針的聲明中為每個(gè)間接級(jí)別加一個(gè)星號(hào)(*) :

har a;
char * b;
char ** c;
a = 'z';
b = &a;
c = &b;

假設(shè)為每個(gè)變量隨機(jī)選擇內(nèi)存位置為7230、8092和10502,這可以表示為:

8581bbfcfae915b34a8dc47ed72db583.png

每個(gè)變量的值在對(duì)應(yīng)的單元格中表示,它們各自在內(nèi)存中的地址由它們下面的值表示。

例如新變量 c,它是一個(gè)指向指針的指針,可以在三個(gè)不同的間接級(jí)別中使用,每個(gè)級(jí)別對(duì)應(yīng)一個(gè)不同的值:

  • c的類型為 char * * ,值為8092
  • * c 是 char * 類型,值為7230
  • * * c 的類型為 char,值為‘ z’

空指針

指針的 void 類型是一種特殊類型的指針。在 C + + 中,void 表示沒(méi)有類型。因此,void 指針是指向沒(méi)有類型的值的指針(因此也是一個(gè)未確定的長(zhǎng)度和未確定的解引用屬性)。

這使 void 指針具有很大的靈活性,可以指向任何數(shù)據(jù)類型,從整數(shù)值或浮點(diǎn)數(shù)到字符串。作為代價(jià),它們有一個(gè)很大的局限性: 它們指向的數(shù)據(jù)不能被直接解引用(這是合乎邏輯的,因?yàn)槲覀儧](méi)有要解引用的類型) ,出于這個(gè)原因,void 指針中的任何地址都需要轉(zhuǎn)換成具體數(shù)據(jù)類型的指針類型,然后才能被解引用。

它的一個(gè)可能用途是將泛型參數(shù)傳遞給函數(shù),例如:

// increaser
#includeusing namespace std;

void increase (void* data, int psize)
{
  if ( psize == sizeof(char) )
  { char* pchar; pchar=(char*)data; ++(*pchar); }
  else if (psize == sizeof(int) )
  { int* pint; pint=(int*)data; ++(*pint); }
}

int main ()
{
  char a = 'x';
  int b = 1602;
  increase (&a,sizeof(a));
  increase (&b,sizeof(b));
  cout<< a<< ", "<< b<< '\n';
  return 0;
}
輸出:
y, 1603

Sizeof 是一個(gè)集成在 C + + 語(yǔ)言中的運(yùn)算符,它返回參數(shù)的大小(以字節(jié)為單位)。對(duì)于非動(dòng)態(tài)數(shù)據(jù)類型,此值為常數(shù)。因此,例如,sizeof (char)為1,因?yàn)?char 的大小總是為一個(gè)字節(jié)。

無(wú)效指針和空指針

原則上,指針指向有效的地址,如變量的地址或數(shù)組中元素的地址。但是指針實(shí)際上可以指向任何地址,包括不引用任何有效元素的地址。典型的例子是指向數(shù)組中不存在元素的指針和未初始化的指針:

int * p;               // 未初始化的指針(局部變量)uninitialized pointer (local variable)
                       // 為什么強(qiáng)調(diào)是局部變量,因?yàn)槿肿兞繒?huì)有默認(rèn)初始化
int myarray[10];
int * q = myarray+20;  // 出界元素 || element out of bounds

P 和 q 都不指向已知包含值的地址,但是上面的語(yǔ)句都不會(huì)導(dǎo)致錯(cuò)誤。在 C + + 中,指針可以獲取任何地址值,不管這個(gè)地址上是否真的有什么東西??赡軐?dǎo)致錯(cuò)誤的是解引用這類指針(即,實(shí)際訪問(wèn)它們指向的值)。訪問(wèn)這類指針會(huì)導(dǎo)致未定義行為,從運(yùn)行時(shí)的錯(cuò)誤到訪問(wèn)一些隨機(jī)值。

但是,有時(shí)候,指針確實(shí)需要顯式地指向不存在的地方(nowhere:不知道如何翻譯恰當(dāng),就翻譯為不存在的地方,以下同),而不僅僅是一個(gè)無(wú)效的地址。對(duì)于這種情況,存在一個(gè)任何指針類型都可以使用的特殊值: 空指針值。這個(gè)值可以用兩種方式在 C + + 中表示: 或者使用一個(gè)整數(shù)值為零,或者使用 nullptr 關(guān)鍵字:

int * p = 0; int * q = nullptr; // 一般使用第二種,見(jiàn)名知意

在這里,p 和 q 都是空指針,這意味著它們顯式地指向不存在的地方,并且它們實(shí)際上相等: 所有空指針比較等于其他空指針。在舊代碼中,定義的常量 NULL 用于引用空指針值也很常見(jiàn):

int * r = NULL;  // 一般是c語(yǔ)言的寫(xiě)法,c++ 寫(xiě)nullptr 更規(guī)范

NULL 在標(biāo)準(zhǔn)庫(kù)的一些頭文件中定義,被定義為某個(gè)空指針常量值(如0或 nullptr)的別名。

不要將空指針(null pointers)與空指針(voidpointers)混淆!null指針是一個(gè)值,任何指針都可以用來(lái)表示它指向“不存在的地方”,而void指針是一種指向某處的指針,沒(méi)有特定的類型。一個(gè)引用存儲(chǔ)在指針中的值,另一個(gè)引用它所指向的數(shù)據(jù)類型。

函數(shù)指針

C + + 允許使用指向函數(shù)的指針進(jìn)行操作。這種方法的典型用途是將函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù)。函數(shù)指針的聲明語(yǔ)法與常規(guī)函數(shù)聲明語(yǔ)法相同,只不過(guò)函數(shù)的名稱被括在括號(hào)()之間,并在名稱前插入星號(hào)(*) :

// pointer to functions
#includeusing namespace std;

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

int subtraction (int a, int b)
{ return (a-b); }

int operation (int x, int y, int (*functocall)(int,int))
{
  int g;
  g = (*functocall)(x,y);
  return (g);
}

int main ()
{
  int m,n;
  int (*minus)(int,int) = subtraction;

  m = operation (7, 5, addition);
  n = operation (20, m, minus);
  cout<

在上面的示例中,minus是指向具有兩個(gè) int 類型參數(shù)的函數(shù)的指針。它被直接初始化為指向函數(shù)subtraction:

int (* minus)(int,int) = subtraction;

函數(shù)指針在實(shí)際的主要的應(yīng)用是回調(diào)函數(shù),關(guān)于函數(shù)指針與回調(diào)函數(shù)的細(xì)節(jié)可以看下面的博客:

函數(shù)指針與回調(diào)函數(shù)

參考網(wǎng)址:https://cplusplus.com/doc/tutorial/pointers/?

一個(gè)在線c++運(yùn)行的網(wǎng)站(沒(méi)有科學(xué)上網(wǎng),可能有時(shí)打不開(kāi)):C++ Shell?

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧

名稱欄目:C/C++中的指針[非常全面]-創(chuàng)新互聯(lián)
當(dāng)前URL:http://muchs.cn/article42/heiec.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供全網(wǎng)營(yíng)銷推廣、定制網(wǎng)站、電子商務(wù)、標(biāo)簽優(yōu)化、靜態(tài)網(wǎng)站、品牌網(wǎng)站制作

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)