C++中的數組,指針解析


哎,由於上課的時候沒有聽課,導致指針這里真的是似懂非懂,雖然對寫代碼影響不大,但是總是精確度下了一個檔次,所以今天趁機把這寫個玩意兒弄明白點,省的以后每次都得查。咱們不求文章長,只求內容清楚~

 如果有誰看出了里面有什么問題,請幫忙指出來,免得誤導別人~餃子在此先說聲謝謝了~


其實關於數組比較好掌握,就是分配某種類型的一個組,這個組的長度必須給出或者初始化,我一開始覺得很不方便,因為有很多情況下我們不知道數組的長度,比如這個數組要由用戶定義之類的情況,但是沒辦法,電腦要為這個數組分配一個內存空間,你不告訴電腦,電腦編譯的時候就迷茫了,得出錯,所以就互相遷就吧,給他個長度,或者給個初始值,這都是必要的。

 

數組的聲明:簡單來說,數組是從低維,0開始存放的,舉個例子  int a[2][2] 在內存里的存放順序就是:a[0][0] - a[0][1] - a[1][0] - a[1][1]. 額,因為就倆數字所以看起來像二進制數數,反正就這個道理。聲明的時候,要么就給出中括號里面的數字,要么就給個初始化,比如 int a[2][2];   或者int a[][2]={1,1,1,1};當然這個等效於int a[][2]={{1,1},{1,1}};  注意,低維的數字不能省,這個‘[2]’里的2不可以省。

 

接下來是指針

首先要知道的是內存的訪問方式,一般來說我們都是通過變量名來訪問內存的,比如int a=1; 我們通過a來訪問這個存放1的內存,但是還有一種方式是通過地址來訪問。打個比方,學校就是我們的內存,每個學生都有自己的名字,以及對應的學號,那么名字就是這里的變量名,而學號就是地址,在批量處理,要傳輸大量數據的時候,通過學號當然比通過名字訪問要方便,所以兩個方式各有千秋,必須都掌握好。

指針: 指針其實是一種數據類型,具有指針類型的變量成為指針變量,指針變量用來存放內存單元地址。聲明方法如下:

//數據類型 * 標識符
char * c;

這里的*就告訴電腦這是個指針變量,前面的數據類型只表示指針所指地址的數據是那種類型,也就是說,c是指針,不是char(說了句廢話。。)。

可以這么理解,'*' 相當於我們定義一個變量int a=3;時的'int', 至於為什么要聲明內存的數據類型(也就是為什么'*'前要有'char'),原因很簡單,不同的數據類型占有的內存單元長度不同,比如是個short類型的指針,那么內存占倆個字節,但是如果是long的話,就占4個字節,所以要有數據類型,告訴指針取幾個字節。

 

感謝8樓的總結,我在這里引用一下:

指針,是一個內存讀取器類。
可以按照給定的數據類型定義和地址位置返回期望的數據值。

數組,是對指針的再次封裝。
包含一個連續內存塊以及一個指針常量。

 

關於'*'和'&'

'*'的意思之前也講過了,就是個指針運算符。‘&’的名字叫取地址運算符。區別可以這么說:

int * p; //定義了一個int型指針。
int a;
p=&a; // p等於a的地址,也就是說&這個符號表示‘取地址’

‘&’ 這個符號還可以這么用:int &y; 表示聲明一個int型的引用 y。

 

給指針賦值可以像上面↑那樣,先聲明,后賦值,也可以是聲明的時候直接賦值,效果雷同給普通變量賦值。注意,對於數組,可以直接用數組名,因為數組名就是它的地址:

int a[5];
int *p=a;//不需要'&',因為a本身即是一個地址了。

使用指針是,如果直接使用,出來的是地址,加個'*',出來的是內容,具體這么表示吧:

int a=5;
int *p=&a;
cout<<p<<endl; // 這一行將輸出a的地址
cout<<*p<<endl; // 這一行將輸出數字'5'

聲明的時候要注意:

  • 可以聲明指向常量的指針,但是不要妄圖通過指針來改變這個常量值╮(╯_╰)╭,不過指針不像常量那么有節操,指針可以改變所指對象的值。如下:
    const char * p="HELLO"; // 這個const是形容char的
    char s[]="HI";
    p=s; //這么寫是可以的,就是相當於給p一個新的地址,

    *p='HI'; // 這就要出錯了,都說了人家char是個常量了,不要改人家嘛。

    //但是:
    char *p="HELLO";
    *p='H'; //這個編譯可以通過,但是運行出錯了。因為違反了指針的規則。
    利用這個特點,可以保證指針所指向的常量不被意外更改。
  • ‘*’放在const前面的話,表示這個指針是個常量,指針本身不能被更改。下面這種情況 line2是不被允許的說~
    char * const p="abc";
    p="def"; // nonono,要出錯咯~
     
  • 雖然我很討厭規矩,但是編程嘛,必須按着規矩來,定義了什么類型的指針,就賦什么類型的值,咱不能給int型指針賦個'x'是吧。不過總有那么幾個叛逆的,所以就有了種叫做void類型的指針,通過強制轉換,可以訪問任何類型的數據。void指針的使用:
    void *vp;  // 一個void類型的指針
    int a=5;
    int *px;
    vp = &a;
    px = (int *)vp;//把vp的void * 強制轉換成 int *,好滿足px的類型。


指針的運算:

         指針可以進行加、減運算,規則其實很容易理解。比如我定義了一個short型指針p,占4個字節,那么p+1,就是地址往后數4個字節,一般是給數組用的。比如:

int a[]={2,3,4,5};
int *p=a;
cout<<*(p+1)<<endl; //輸出就是3

 

指針型函數:

這個東西是大大的好啊,可以讓返回值從一個擴展的大批的數據,具體用法就是返回類型后面加個"*",用起來很爽。同樣來點內容免得光說不練。

int * getAll(int *a){
.....
// 處理了半天,然后返回
return a;
}

(這里謝謝@陳梓瀚(vczh)的指正)

這樣返回的就是四個數字而不是一個數字了,可以通過返回的指針,進行運算,得到這批數據,並且可以保護這批數據。

 

指向函數的指針

其實函數和數組一樣,在內存中從函數名開始存起,也就是說知道了函數名,接下來的內存里放的就是函數體了,所以,既然指針可以指向數組,當然也可以指向函數了。形式就是: 數據類型 (* 函數指針名)(形參表)   如果一個函數的   返回值類型=指針數據類型  形參表=指針形參表,那個這個函數指針就可以指向這個函數了。

void function(int a,int b);
void function2(int x,int y);
void (* fpointer)(int,int); //必須和要指向的函數形參類型,個數,順序完全相同,才能指向這個函數

//使用時:
function(5,5);
// 上下 兩者效果等同
fpointer=function;
fpointer(6,6);

fpointer=function2; // 多好啊還可以指向別的函數,只要條件符合。

對象指針:(話說這部分其實很廢柴啊囧rz)
 就是指向一個類的指針 語法: 類名 * 指針名;   調用成員時: 指針名->成員名; 注意在給指針賦值前,要對這個對象進行初始化~

Clock c(1,2,4);
Clock *p;
p=&c; //這里c必須是初始化好的。否則不可以使用指針p
p->getTime();


指向類的非靜態成員的指針:在類的外部定義一個指針指向類得公有成員時,定義如下:

如果是公有數據成員:

Clock  clock(1,1,2);
Clock *pClock = &clock;
//定義
int Clock::*pHour;

//賦值:
pHour=&Clock::Hour;

//調用:(三個效果相同)
clock.*pHour;
pClock->Hour;
clcok.Hour;

如果是公有函數成員:

Clock  clock(1,1,2);
Clock *pClock = &clock;
//定義: 返回類型 (類名::*指針名)(參數表)
int (Clock::*pGetHour)();

//賦值:
pGetHour= &Clock::GetHour;

//調用:(三個效果相同)
clock.*pGetHour;
pClock->GetHour;
clcok.GetHour;


到這里我已經頭暈了,不知道耐心看到這里的同學們頭暈了沒?暈了的話喝口水,刷刷微博先,勞逸結合嘛~

 

動態內存分配:(哇,聽起來好高端)7行代碼概括:

int *point;
point = new int(2); //分配動態存儲空間並把數值2放入內存
// .....
delete point;
/*------------------------------------------*/
Clock *pclock = new Clock[2]; //此時不可以初始化
pclock[0].Set(1,2,3);//就假設有這么個函數唄
pclock[1].Set(4,5,6);
delete[] pclock; //就是為了說,這里delete后面要有‘[]’


淺拷貝和深拷貝:(最后一點兒啦  加油~)

其實這個用代碼寫起來復雜,但是說起來很簡單。

如果一個類里面有個成員p是個指針,定義了實體對象clock, clock2,然后clock中的p指向一個存着int型數據的內存空間。當我們僅僅用clock2.p=clock.p來給clock2中的p賦值的話,其實兩個實體對象的指針p就指向了同一個內存空間,這樣的話,對這個內存空間的數字進行操作的時候,就會同時影響到clock和clock2.這就是淺拷貝。

深拷貝,就是讓它不印象唄。所以clock2的p如果這么拷貝:p=new int(*clock.p); 那么倆玩意兒就互不影響了,如此這般,就是深拷貝。

 

呼,終於結束了,玩兒微博去也~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM