1. 程式人生 > >c語言-指標陣列

c語言-指標陣列

指標

記憶體和地址怎麼理解呢?

機器中有一些位置,每一個位置被稱為【位元組】/byte,許多現代機器上,每個位元組包含8個位。更大記憶體單位【字】,通常包含2個或4個位元組組成。

一個字包含4個位元組,它的地址是什麼?

他仍然只有一個地址,是最左邊還是最右邊的那個位元組的位置,取決於機器。

機器事實-關於整型的起始位置:

在要求邊界對齊(boundary alignment)的機器上,整型儲存的起始位置只能是某些特定的位元組,通常是2或4的倍數。

變數名和地址關係?

所有高階語言的特性之一,就是通過名字而不是地址來訪問記憶體的位置。那麼名字和地址是怎麼關聯的呢?關聯關係不是硬體所提供的,它是由編譯器實現的,硬體仍然通過地址訪問記憶體位置。

儲存在記憶體的一個32位值,到底是整型還是浮點呢?

什麼型別取決於使用方式,如果使用整型算術指令,這個值就被解釋為整數,如果使用浮點型指令,他就是個浮點數。

指標變數他的地址對應的記憶體中存的是什麼內容?

儲存是一個值,這個值,通常被當做地址來使用。

對於int a=112; int *d = &a;  為什麼編譯器最終將a的地址寫入d對應的記憶體空間,而不是把112寫入d的記憶體空間呢?

原因應該是這樣設計靈活,且效率高,更重要的是硬體的設計如:RAM 有地址這個概念

符號* 什麼含義?

用來執行間接訪問操作。對一個變數間接訪問,宣告含義?就是不把這塊記憶體值直接使用,而是把它用作地址,把這個地址對應的內容取出。

指標未初始化是什麼含義,有什麼風險?對未初始化的指標訪問會發生什麼?如int *a  ;  *a=12;

這個操作可能會有下面情景發生

     1.  運氣好a 的初始值是非法地址,出錯,終止程式,在unix系統上這個錯誤memory fault  ,在windows出現一般保護性異常(general  protection exception)

     2.更嚴重的情況,這個指標偶爾可能包含一個合法地址,即是這樣的情況:引發錯誤的程式碼,與原先用於操作那個值得程式碼完全不相干。

編譯器能檢測出來初始化的指標p,   *p = 12,這樣,並給出警告嗎?

標準定義的NULL指標什麼含義?我怎麼定義一個NULL指標變數?怎麼判斷一個指標是不是NULL指標。

表示不指向任何東西。定義一個變數賦值為零。與零值比較來判斷指標是不是NULL指標。

在機器層面NULL指標內容到底是什麼呢?

NULL 指標可能不是0,在此情況,編譯器將負責零值和內部值之間的翻譯和轉換。

對一個NULL指標間接訪問會出現什麼情況?

因編譯器而異,有的不報錯。有的發生錯誤,並終止程式。

怎麼定義一個指標變數才是好習慣?

如果你已經知道指標將被初始化為什麼地址,就把它初始化為該地址,否則把它初始化為NULL。

在對一個變數賦值時,編譯器會校驗,檢查什麼?

         校驗,使用變數型別和應該使用的變數的型別不一致時,編譯器會報錯。

         分析下*&a = 25;  非重點

指標常量是什麼能不能訪問操作並賦值?

*100 = 25;  *100 就是指標常量。這條語句是非法的,需要強制型別轉換如:

 *(int *) 100 = 25;

指標常量什麼樣情況才能用到?

        如:與輸入輸出裝置控制器通訊。

指標的指標怎麼用示意圖畫明白?

指標定義和使用的分析:

定義(包括宣告和初始化)

    宣告的分析:有就是指標;初始化,左值使用,*【變數】代表是將右邊的值寫入指標變數記憶體中(【變數】);

    **【變數】左值使用,賦值,*【變數】表示地址記憶體開啟,開啟結果還是地址,**【變數】表示多次開啟,還是代表開啟地址,注意編譯器能知道這種變化,**兩次就是二級指標

    使用:*【變數】是右值表示式*代表間接訪問,把【】中當做地址使用,找到這個地址對應的記憶體單元,把值拿出來,就是*【】表示式的值了

 

注意* 是右結合性

Int a =12;

Int *b = &a;

Int **c = &b;

畫圖要點:

    1.箭頭===》是地址

    2. 虛線。表示關係

    3. 實線。表示*訪問

粗橢圓  當做右值使用,使用表示式的值。

粗方框  當做左值使用,指地址。

#include <stdlib.h>
#include <stdio.h>
int
main(){
        int a=12;
        int *b=&a;
        int **c= &b;

        printf("%p %p %p \n",a,b,c);
        printf("%d %d %d \n",sizeof(a),sizeof(b),sizeof(c));
//      printf("%s %s %s \n",a,*b,*c);
        printf("%d %d %d \n",a,*b,**c);
}

結果:

分析結果:  指標佔用八個位元組,地址佔用八個位元組,實際上用6個位元組表示地址(0x開頭)

例子 :指標要用對等的地址

#include <stdlib.h>
#include <stdio.h>
int
main(){
	int a=12;
	int *b= &a;
	int **c= &a;
	
	printf("%p %p \n",a,c);
	printf("%d %g \n",a,*c);
	printf("%d %d \n",sizeof(a),sizeof(c));
}

結果:編譯器報錯!

結果分析:指標要用對等的地址(或低一級指標賦值如&b, 或者同級別指標&d)來賦值,編譯器會檢驗出不符合的情況

為什麼&ch 不能用作左值?

&ch結果會儲存在某個地方/某個記憶體,但是我無法知道他位於何處,這個表示式,看不出他在機器中那個特定位置,所以它不是一個合法的左值。

什麼是左值,右值?

 左值可以再“=”號左側,也可以在等號右側,而右值只能出現在等號右側。

分析清楚一個指標表示式是左值還是右值有什麼好處?

分析表示式?

Char  ch = ‘a’;

    Char *cp = &ch;

  示意圖要求1. 標出求值的順序,2中間專題是虛線,橢圓,方框

   表示式

     &ch

 cp

&cp

*cp

*cp+1

*(cp+1)

++cp

Cp++

*++cp

*cp++

++*cp

(*cp)++

++*++cp

++*cp++

例項,strlen.c 必會默寫

指標+/- 整數  在什麼情況下可以這樣?

只能用於指向陣列中某個元素的指標,也適用於使用malloc函式動態分配獲得的記憶體。

指標指向陣列最後一個元素的後面的那個記憶體位置,有什麼問題?允許這樣,一般不允許對指向這個位置的指標進行間接訪問。

指標-指標什麼情況下允許這樣?

只有兩個指標指向同一個陣列中的元素時,相減的結果是ptrdiff_t(有符號整數型別)

<  <=   >  >= 可以比較的兩個指標有什麼限制?

他們都指向同一個陣列中的元素,但是兩個任意的指標可以執行相等或不相等測試。

陣列

陣列和指標的區別與聯絡?

陣列和指標有著本質的不同,指標是一個標量值。陣列名卻有很多屬性如:陣列元素的數量。只有當陣列名在表示式中使用時,編譯器才會為它產生一個指標常量

先來搞明白,什麼是宣告,什麼是定義?

c 語言中的物件有且只有一個定義,但它可以有多個extern 宣告。這裡的物件,只是跟連結器有關的“東西”比如函式和變數。

定義只能出現一個地方,宣告可以出現多次,宣告相當於普通的宣告,它說明並非本身,而是描述其他地方建立的物件。定義相當於特殊的宣告,它為物件分配記憶體

左值在編譯時可知,左值標示儲存結果的地方。右值直到執行時才知,如無特殊說明,右值表示的內容。

           C語言中有“可修改的左值”,很奇怪!意味著還有不可可以修改的左值,這個奇怪的術語是為與陣列名(是左值)區分。

陣列和指標是如何訪問的?

char a[9] = “abcdefgh”;    …..   c= a[i];

編譯器符號表具有一個地址9980

           執行時步驟1: 取i的值,將它與9980相加

           執行時步驟2: 取地址(9980+i)的內容

char *p ;  ………     c= *p;

編譯符號表有一個符號p, 它的地址為4624;

         執行時步驟1: 取4624的內容,就是5081

           執行時步驟2: 取地址5081 的內容

指定的訪問要靈活得多,但需要增加一次額外的提取。

 

定義為指標,但以陣列方式引用時會發生什麼?

  指標當然可以p[i] 用,

   char *p = “abcdefgh”;         c=p[i];

   編譯器符號表具有一個p, 地址為4624

       執行步驟1 :取地址4624的內容,即5081,

                     執行步驟2:     取得i的值,並將它與5081相加

                     執行步驟3:     取得地址[ 5081 + i] 的內容

指定的訪問要靈活得多,但需要增加一次額外的提取。(和陣列a對比)

注意寫程式碼時,宣告與定義相匹配

 

指標

陣列

通常用於動態資料結構

通常用於儲存固定數目且資料型別相同的元素

相關的函式malloc(), free().

隱式分配和刪除

通常指向匿名資料

自身即為資料名

間接訪問

直接訪問

 

 

定義指標時,編譯器並不為指標指向的物件分配空間,它只是分配指標本身的空間,除非在定義時同時賦給指標一個字串常量進行初始化。如:

char *p = “break”;

float *pip = 3.14;  //錯誤!!!!

什麼時候陣列和指標相同?

 陣列宣告,包含三種

  1. extern , 如  extern char a[]  ;  不能改寫成指標的形式
  2. 定義,如  char  a[10];  不能改寫成指標的形式
  3. 函式的引數,如func(char a[]);  選擇陣列形式,或者指標形式

  陣列,在表示式中使用

                     如c = a[i];  選擇陣列形式  或指標形式

 

規則1: 表示式中的陣列名被編譯器當作一個指向該陣列第一個元素的指標。

  例外情況如:  a 陣列作為sizeof()的運算元;b 使用& 操作符取陣列的地址;c陣列是一個字串,常量初始值。???

           如:

           int a[10], i=2;

           a[i]; 相當於*(a+i);  *(i+a);i[a]; 2[a];

           規則2: 在函式引數的宣告中,陣列名被編譯器當作指向該陣列第一個元素的指標。

           規則3: 下標總是與指標的偏移量相同

                     事實上,下標範圍檢查被認為並不值得加入C語言中。

指標總是有型別限制?p+2p+i   ; 是的,因為編譯器要直到步長啊。

陣列行參是如何被引用的?