C++ 引用和指針

引用和指針看上去差不多,(看上去差不多,其實男寶寶和女寶寶是不一樣的)用起來還是有一定差距。本人菜鳥僅將遇到的問題記錄備案,以便日後翻查

ptrfunc.h

#ifndef PTRFUNC_H__
#define PTRFUNC_H__
typedef int (*func)(int,int);
struct AA
{
func s;
int a;
};
#endif

1、錯誤

main.cpp

#include <stdio.h>
#include "ptrfunc.h"
extern void getinfo (AA pp);
int main(int argc,char* argv[])
{
int a=2;
int b=3;
AA pm; 
pm.a=b;
printf("pm's a is %d\n",pm.a);
getinfo(pm);
pm.s(2,3);

return 1;
}

interface.cpp

#include "ptrfunc.h"
#include <stdio.h>
int add(int a,int b)
{
printf("result is %d\n",a+b);
return a+b;
}
void getinfo(AA p)
{
  p.s=add;
}

[root@localhost test]# g++ interface.cpp main.cpp -g -o main
[root@localhost test]# ./main 
pm's a is 3
段錯誤 (core dumped)

2、錯誤

main.cpp

#include <stdio.h>
#include "ptrfunc.h"
extern void getinfo (AA *pp);
int main(int argc,char* argv[])
{
int a=2;
int b=3;
AA *pm;
pm->a=b;

printf("pm's a is %d\n",pm->a);
getinfo(pm);
pm->s(2,3);

return 1;
}

interface.cpp

#include "ptrfunc.h"
#include <stdio.h>
int add(int a,int b)
{
printf("result is %d\n",a+b);
return a+b;
}
void getinfo(AA *p)
{
  p->s=add;
}

[root@localhost test]# g++ interface.cpp main.cpp -g -o main
[root@localhost test]# ./main 
段錯誤 (core dumped)

3、正確

main.cpp

#include <stdio.h>
#include "ptrfunc.h"
extern void getinfo (AA *pp);
int main(int argc,char* argv[])
{
int a=2;
int b=3;
        AA *pm=new AA(); ;
pm->a=b;

printf("pm's a is %d\n",pm->a);
getinfo(pm);
pm->s(2,3);

return 1;
}

interface.cpp

#include "ptrfunc.h"
#include <stdio.h>
int add(int a,int b)
{
printf("result is %d\n",a+b);
return a+b;
}
void getinfo(AA *p)
{
  p->s=add;
}

[root@localhost test]# g++ interface.cpp main.cpp -g -o main
[root@localhost test]# ./main 
pm's a is 3
result is 5

4、正確

main.cpp
#include <stdio.h>
#include "ptrfunc.h"
extern void getinfo (AA &pp);
int main(int argc,char* argv[])
{
int a=2;
int b=3;
AA pm; 
pm.a=b;

printf("pm's a is %d\n",pm.a);
getinfo(pm);
pm.s(2,3);
return 1;
}

interface.cpp

#include "ptrfunc.h"
#include <stdio.h>
int add(int a,int b)
{
printf("result is %d\n",a+b);
return a+b;
}
void getinfo(AA &p)
{
  p.s=add;
}

[root@localhost test]# g++ interface.cpp main.cpp -g -o main
[root@localhost test]# ./main 
pm's a is 3
result is 5

後記:

int n;

int &m = n;

在C++中,多了一個C語言沒有的引用聲明符&,如上,m就是n的引用,簡單的說m就是n的別名,兩者在內存中佔同樣的位置,不對m開闢新的內存空間,對m的任何操作,對n來說是一樣的。

對於引用,有以下三條規則:

(1)引用被創建的同時必須被初始化(指針則可以在任何時候被初始化)。
(2)不能有NULL 引用,引用必須與合法的存儲單元關聯(指針則可以是NULL)。
(3)一旦引用被初始化,就不能改變引用的關係(指針則可以隨時改變所指的對象)。

假如在一個函數中動態申請內存空間,用指針和用引用作形參會得到不同的結果,如下面的例子:

void fun(int* b){ //用指針做形參
b = (int*)malloc(sizeof(int)*3);

for(int i=0; i<3; i++){
a[i] = i;
}
}

void fun(int* &b){ //用引用做形參
b = (int*)malloc(sizeof(int)*3);

for(int i=0; i<3; i++){
b[i] = i;
}
}

如果在main函數中定義了一個int型的空指針並分別作爲實參傳入,如下:

int main(){
int *a = NULL;

fun(a);

for(int i=0; i<3; i++){
cout << a[i] << " ";
}
cout << "\n";

return 0;
}

結果用指針的函數會出現內存訪問出錯,用引用的函數則運行正常並正確輸出1 2 3.

這是因爲:

1.指針雖然是地址傳遞,但實際上也是在函數中又定義了一個新的指針讓其與傳入的指針指向同一地址。但兩個指針本身作爲變量在內存中的存放地址是不同的,就是說這是兩個不同的變量,只是內容(即所指地址)相同。

2.在函數中對新定義的指針動態申請內存,但是當函數結束後,申請的內存的生命週期也就結束了,所以當回到主函數時,作爲實參的指針地址和內容都沒有變化。仍然是個空指針,對其進行訪問自然出現了內存讀錯誤了。

假如在main函數中這樣寫:

int *a = (int*)malloc(sizeof(int)*3);

就不會出現內存讀錯誤了,但是輸出結果還是錯誤的,道理也是一樣的。

3.用引用作爲實參傳入時,fun函數中的b其實就是主函數中a的別名(或者叫外號),反正就是操作完全相同,地址相同,內容相同的一個變量,所以當fun函數返回時,對b的操作在主函數中對a同樣有效。

再看一個例子:

int *a = NULL;

char* b = (char*)a;

int *a = NULL;

char* &b = (char*)a;

這一次是在編譯階段的區別:

用指針可以通過編譯,而用引用則不可以,提示類型轉換出錯。

通過這兩個例子可以看出,指針比引用靈活,也更加危險。

摘自『高質量c++編程』
條款一:指針與引用的區別
指針與引用看上去完全不同(指針用操作符’*’和’->’,引用使用操作符’.’),但是它們似乎有相同的功能。指針與引用都是讓你間接引用其他對象。你如何決定在什麼時候使用指針,在什麼時候使用引用呢?
首先,要認識到在任何情況下都不能用指向空值的引用。一個引用必須總是指向某些對象。因此如果你使用一個變量並讓它指向一個對象,但是該變量在某些時候也可能不指向任何對象,這時你應該把變量聲明爲指針,因爲這樣你可以賦空值給該變量。相反,如果變量肯定指向一個對象,例如你的設計不允許變量爲空,這時你就可以把變量聲明爲引用。

PS:引用在定義時不可加const,否則編譯出錯,在形參前面則可以加const以確保在函數中該變量不會被修改。


發佈了17 篇原創文章 · 獲贊 1 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章