C++編程中指針的聲明與基本使用講解
使用以下序列聲明指針。
[storage-class-specifiers] [cv-qualifiers] type-specifiers [ms-modifier] declarator ;
其中,任何有效指針聲明符均可用于 declarator。簡單指針聲明符的語法如下所示:
* [cv-qualifiers] identifier [= expression]
1.聲明說明符:
可選存儲類說明符。
應用于要指向的對象的類型的可選 const 或 volatile 關鍵字。
類型說明符:可表示要指向的對象的類型的類型名稱。
2.聲明符:
可選的 Microsoft 專用修飾符。
* 運算符。
應用于指針本身的可選 const 或 volatile 關鍵字。
標識符。
可選初始值設定項。
指向函數(shù)的指針的聲明符類似于以下形式:
(* [cv-qualifiers] identifier )( argument-list ) [cv-qualifers] [exception specification] [= expression];
對于指針數(shù)組,語法如下所示:
* identifier [ [ constant-expression ] ]
但是,指針聲明符可能更復雜。
多個聲明符及其初始值設定項可能同時出現(xiàn)在前面有聲明說明符且以逗號分隔的列表中的一個聲明中。
指針聲明的簡單示例如下:
char *pch;
前面的聲明指定 pch 指向 char 類型的對象。
更復雜的示例是
static unsigned int * const ptr;
前面的聲明指定 ptr 是一個指向 unsigned int 類型(帶靜態(tài)存儲持續(xù)時間)的對象的常量指針。
下一個示例演示如何聲明和初始化多個指針:
static int *p = &i, *q = &j;
在前面的示例中,指針 p 和 q 都指向類型 int 的對象并分別初始化為 i 和 j 的地址。存儲類說明符 static 應用于這兩個指針。
// pointer.cpp // compile with: /EHsc #include <iostream> int main() { int i = 1, j = 2; // local variables on the stack int *p; // a pointer may be assigned to "point to" the value of // another variable using the & (address of) operator p = & j; // since j was on the stack, this address will be somewhere // on the stack. Pointers are printed in hex format using // %p and conventionally marked with 0x. printf_s("0x%p\n", p); // The * (indirection operator) can be read as "the value // pointed to by". // Since p is pointing to j, this should print "2" printf_s("0x%p %d\n", p, *p); // changing j will change the result of the indirection // operator on p. j = 7; printf_s("0x%p %d\n", p, *p ); // The value of j can also be changed through the pointer // by making an assignment to the dereferenced pointer *p = 10; printf_s("j is %d\n", j); // j is now 10 // allocate memory on the heap for an integer, // initialize to 5 p = new int(5); // print the pointer and the object pointed to // the address will be somewhere on the heap printf_s("0x%p %d\n", p, *p); // free the memory pointed to by p delete p; // At this point, dereferencing p with *p would trigger // a runtime access violation. // Pointer arithmetic may be done with an array declared // on the stack or allocated on the heap with new. // The increment operator takes into account the size // of the objects pointed to. p = new int[5]; for (i = 0; i < 5; i++, p++) { *p = i * 10; printf_s("0x%p %d\n", p, *p); } // A common expression seen is dereferencing in combination // with increment or decrement operators, as shown here. // The indirection operator * takes precedence over the // increment operator ++. // These are particularly useful in manipulating char arrays. char s1[4] = "cat"; char s2[4] = "dog"; char* p1 = s1; char* p2 = s2; // the following is a string copy operation while (*p1++ = *p2++); // s2 was copied into s1, so now they are both equal to "dog" printf_s("%s %s", s1, s2); }
輸出:
0x0012FEC8 0x0012FEC8 2 0x0012FEC8 7 j is 10 0x00320850 5 0x00320850 0 0x00320854 10 0x00320858 20 0x0032085C 30 0x00320860 40 dog dog
另一個示例演示如何在數(shù)據(jù)結(jié)構(gòu)中使用指針;本例中采用鏈接列表。
// pointer_linkedlist.cpp // compile with: /EHsc #include <iostream> using namespace std; struct NewNode { NewNode() : node(0){} int i; NewNode * node; }; void WalkList(NewNode * ptr) { if (ptr != 0) { int i = 1; while (ptr->node != 0 ) { cout << "node " << i++ << " = " << ptr->i << endl; ptr = ptr->node; } cout << "node " << i++ << " = " << ptr->i << endl; } } void AddNode(NewNode ** ptr) { NewNode * walker = 0; NewNode * MyNewNode = new NewNode; cout << "enter a number: " << endl; cin >> MyNewNode->i; if (*ptr == 0) *ptr = MyNewNode; else { walker = *ptr; while (walker->node != 0) walker = walker->node; walker->node = MyNewNode; } } int main() { char ans = ' '; NewNode * ptr = 0; do { cout << "a (add node) d (display list) q (quit)" << endl; cin >> ans; switch (ans) { case 'a': AddNode(&ptr); break; case 'd': WalkList(ptr); break; } } while (ans != 'q'); }
輸出:
a 45 d a 789 d qa (add node) d (display list) q (quit) enter a number: a (add node) d (display list) q (quit) node 1 = 45 a (add node) d (display list) q (quit) enter a number: a (add node) d (display list) q (quit) node 1 = 45 node 2 = 789 a (add node) d (display list) q (quit)
固定和可變指針
const 和 volatile 關鍵字用于更改處理指針的方式。 const 關鍵字指定指針在初始化后無法修改;此后指針將受到保護,防止進行修改。
volatile 關鍵字指定與后跟的名稱關聯(lián)的值可由用戶應用程序中的操作以外的操作修改。因此,volatile 關鍵字對于聲明共享內(nèi)存中可由多個進程訪問的對象或用于與中斷服務例程通信的全局數(shù)據(jù)區(qū)域很有用。
如果某個名稱被聲明為 volatile,則每當程序訪問該名稱時,編譯器都會重新加載內(nèi)存中的值。這將顯著減少可能的優(yōu)化。但是,當對象的狀態(tài)可能意外更改時,這是保證可預見的程序性能的唯一方法。
若要將指針指向的對象聲明為 const 或 volatile,請使用以下形式的聲明:
const char *cpch; volatile char *vpch;
若要將指針的值(即指針中存儲的實際地址)聲明為 const 或 volatile,請使用以下形式的聲明:
char * const pchc; char * volatile pchv;
C++ 語言會阻止將允許修改聲明為 const 的對象或指針的賦值。此類賦值會移除用來聲明對象或指針的信息,從而違反原始聲明的意圖。請考慮以下聲明:
const char cch = 'A'; char ch = 'B';
假定前面聲明了兩個對象(const char 類型的 cch 和 char 類型的 ch),以下聲明/初始化將是有效的:
const char *pch1 = &cch; const char *const pch4 = &cch; const char *pch5 = &ch; char *pch6 = &ch; char *const pch7 = &ch; const char *const pch8 = &ch;
以下聲明/初始化存在錯誤。
char *pch2 = &cch; // Error char *const pch3 = &cch; // Error
pch2 的聲明聲明了一個可以用來修改常量對象的指針,因此不允許使用。 pch3 的聲明指定 pointer 是常量,而不是對象;與不允許使用 pch2 的原因相同,也不允許使用該聲明。
以下八個賦值顯示了通過指針進行的賦值以及對前面的聲明的指針值的更改;現(xiàn)在,假設 pch1 到 pch8 的初始化是正確的。
*pch1 = 'A'; // Error: object declared const pch1 = &ch; // OK: pointer not declared const *pch2 = 'A'; // OK: normal pointer pch2 = &ch; // OK: normal pointer *pch3 = 'A'; // OK: object not declared const pch3 = &ch; // Error: pointer declared const *pch4 = 'A'; // Error: object declared const pch4 = &ch; // Error: pointer declared const
聲明為 volatile 或 const 和 volatile 的組合的指針遵循相同的規(guī)則。
指向 const 對象的指針通常用于函數(shù)聲明中,如下所示:
errno_t strcpy_s( char *strDestination, size_t numberOfElements, const char *strSource );
前面的語句聲明了函數(shù) strcpy_s,其中,三個參數(shù)中的兩個是指向 char 的類型指針。由于參數(shù)是按引用而不是按值傳遞的,因此,如果未將 strSource 聲明為 const,則該函數(shù)可以自由修改 strDestination 和 strSource。將 strSource 聲明為 const 可向調(diào)用方保證調(diào)用的函數(shù)無法更改 strSource。
注意
由于存在從 typename * 到 const typename * 的標準轉(zhuǎn)換,因此將 char * 類型的參數(shù)傳遞到 strcpy_s 是合法的。但是,反之則不行;不存在從對象或指針中移除 const 特性的隱式轉(zhuǎn)換。
給定類型的 const 指針可以分配給同一類型的指針。但是,非 const 類型的指針不能賦給 const 指針。以下代碼顯示了正確和錯誤的賦值:
// const_pointer.cpp int *const cpObject = 0; int *pObject; int main() { pObject = cpObject; cpObject = pObject; // C3892 }
以下示例顯示了當有指針指向某個指向?qū)ο蟮闹羔槙r如何將對象聲明為 const。
// const_pointer2.cpp struct X { X(int i) : m_i(i) { } int m_i; }; int main() { // correct const X cx(10); const X * pcx = &cx; const X ** ppcx = &pcx; // also correct X const cx2(20); X const * pcx2 = &cx2; X const ** ppcx2 = &pcx2; }
相關文章
error LNK2019: 無法解析的外部符號 問題的解決辦法
error LNK2019: 無法解析的外部符號 問題的解決辦法,需要的朋友可以參考一下2013-05-05C/C++?Qt?數(shù)據(jù)庫QSql增刪改查組件應用教程
Qt?SQL模塊是Qt中用來操作數(shù)據(jù)庫的類,該類封裝了各種SQL數(shù)據(jù)庫接口,可以很方便的鏈接并使用。本文主要介紹了Qt數(shù)據(jù)庫QSql增刪改查組件的應用教程,感興趣的同學可以學習一下2021-12-12