指標的引用——在函數中的巧妙應用,指標引用函數
前面有一篇文章講了指標與引用。並且還提到不能定義指向引用的指標(因為引用不是對象,沒有實際的地址)。那麼,能否定義指標的引用呢?答案是肯定的,因為指標本身就是一個對象。即然是對象,就能定義一個引用邦定該對象。先來看看指標的引用的用法:
以int類型為例如下:
void ReferencePointer(){inti = 5;// 變數iint*p = &i;// 指標p,指向變數iint*&pr = p;// 指標的引用,與p指向同一個變數icout << i << " " << *p << " " << *pr << endl;i = 10;cout << i << " " << *p << " " << *pr << endl;cout << "addr: " << p << " " << pr << endl;// 指標的引用其它就是指標p的一個別名,和p有相同的地址pr = NULL;// 因此也可以給指標賦空cout << "addr: " << p << " " << pr << endl;}
結果:
5 5 5
10 10 10
addr: 0045FE50 0045FE50
addr: 00000000 00000000
在函數中,指標的引用作為參數可以起到很巧妙的作用。
假設有一個書的類Book,基定義如下:
struct Book
{
string isbn;
string name;
double price;
string author;
};
現在需要這樣一個函數:有一個檔案存放著一本書的相關資訊(ISBN、書名、價格),現要從這個檔案中讀取資訊並賦給Book的對象。
要定義這樣一個函數,我們首先會想到的是有一個輸入(檔案的路徑)和一個輸出(Book的對象)。你可能會這樣定義函數:
Book* GetBookFromFile(const string& filePath);
這種方式你必須在函數體內建立Book的對象(也就建立一個Book的記憶體空間),但函數體內建立的記憶體空間只在函數的範圍內有效,在函數體外是無效的,也就是說返回的指標將指向一個任意的值,這將是非常危險的。
如函數內:
在函數被調用後:
既然不行,您應該會想到另外一種定義方式如下:
Book GetBookFromFile(const string& filePath);
沒錯,這樣定義確實可以,但需要在函數體內聲明一個Book的對象,函數傳回值的時候會進行一次對象的拷貝。這樣增加了一個對象拷貝的過程,使效率降低。
Book GetBookFromFile(const string& filePath){Book book;fstream fileInput(filePath);fileInput >> book.isbn >> book.name >> book.price;return book;}
您可能還會想到這種方式:
void GetBookFromFile(Book &book, const string& filePath);
沒錯,這確實可以解決上面的問題,不用再對對象進行拷貝。但新的問題又來了,上層調用這個函數時,如果要判斷返回book對象是否正確擷取了檔案的資訊得逐個地判斷基屬性是否空,如下代碼。這無疑加重了上層調用的負擔。
Book book;
GetBookFromFile(book, "E:\\book.txt");
if (!book.isbn.empty() && !book.name.empty() && book.price > 0)
{
// TO DO ...
}
當然,這有一種改進的方式,就是把傳回值類型void改為bool,這樣就可以通過返回的bool值確定函數是否成功調用。
針對上面的這個問題,如果返回的是Book的指標,直接判斷返回的指標是否為NULL就可以。那麼您可以有以下兩種定義:
void GetBookFromFile(Book* book, const string& filePath);
void GetBookFromFile(Book*& book, const string& filePath);
當然,我是建議選擇第二種方式,因為引用確保了傳進來的指標有一個正確的值(引用必須在定義時被初始化)
定義如下:
void GetBookFromFile(Book* pBook, const string& filePath){if (pBook == NULL){return;}fstream fileInput(filePath);fileInput >> pBook->isbn >> pBook->name >> pBook->price;}
void GetBookFromFile(Book*& pBook, const string& filePath){if (pBook == NULL){return;}fstream fileInput(filePath);fileInput >> pBook->isbn >> pBook->name >> pBook->price;}
對這兩個函數,調用方式都可以如下:
Book* pBook = new Book();pBook->author = "SimileSunrise";GetBookFromFile(pBook, "E:\\book.txt");delete pBook;
指標與引用在函數調用中的不同
“int createbitree(Bitree &t )
為什麼int createbitree(bitree *t )不可以??
”
因為你主函數中定義的t本身就是指標,如果你直接用int createbitree(bitree *t)相當於傳值進去,如果要傳地址的話要用二級指標:
int createbitree(bitree **t)
c++中的函數引用與指標的不同?
#include <stdio.h>
void F(int a, int b){printf("hello %d %d\n", a, b);};
typedef void (&pF)(int, int);
int main()
{
int a = 1, b = 3;
pF x = F;
x(a, b);
printf("0x%X 0x%X", F, x);
}
全域變數是被儲存在記憶體中的全域靜態區的, 全域變數的聲明總是定義, 因為編譯器會將他們的值初始化為其預設值, 可以在全域範圍內定義變數, 但不能在全域範圍內實施操作, 因為操作是在函數中實現的, 你要分清初始化和賦值的不同, 所以比如有一個全域變數a;
int a; // 等價於int a(int());
則以下對a的操作都是違法的:
++a;
a--;
a += 1;
....
程式是由函數構建的, 而不是檔案構建的, 所以以上操作根本執行不到, 所以編譯不同過, 而且C/C++編譯器貌似只識別全域範圍內變數的聲明定義, 所以在你試圖global = 10的時候它認為你要建立一個不帶類型標識符的變數global, 所以給你一個錯誤; 另外它又發現你企圖聲明的這個變數與已存在的變數名有衝突, 所以它又給你一個錯誤...