1. 程式人生 > >c指標面試

c指標面試

1. 常指標與常量的指標
        char * const p;
  char const * p
  const char *p
  上述三個有什麼區別?

  char * const p;   //p為只讀指標。
  char const * p;//p值只讀的指標。
  const char *p; //和char const *p

---------------------------------------------------
2.定義與宣告
宣告是普通的宣告:它所描述的並非自身,而是描述在其他地方建立的物件。
定義是特殊的宣告:它為物件分配記憶體,即現場建立物件。

---------------------------------------------------
3.左值與右值
 I.左值:編譯時可知。左值可以分為可修改左值和不可修改左值,陣列名就是一個不可修改的左值。即不能給陣列名賦值!(注意這裡指的是“陣列名”) 這是為什麼呢?下面有一個現場:
char a[10] = {'a'};
char b[10] = {'b'};
a = b;
編譯時出現的錯誤:
error: incompatible types when assigning to type ‘char[10]’ from type ‘char *’ 
結論:
當陣列名為左值時,它的型別是字元陣列;當陣列名為右值時,它的資料型別是字元指標。

 II.右值:執行時可知。
---------------------------------------------------

4.指標與陣列
 如果編譯器需要一個地址來執行一種操作,對於被定義的陣列變數而言的,它地址在編譯時可知,所以它就可以直接進行操作;而對於被宣告的指標而言,只有在程式執行的時候才知道它所指向的地址的值,然後才能在當前地址上操作。

 char array[] = “sdfsdf”;   …   c = a[i];
 陣列的下標引用步驟:(1)取編譯器符號中的符號array的地址(假設是8888)
         (2)array[i]即為取地址8888+i的內容。
 char *p; … c = *p;
 指標的間接引用步驟:(1)取編譯器符號表中符號p的地址(假設是7777)
         (2)獲取7777位置處的內容(假設是9999)
         (3)取9999處地址的內容,即為*p
 
 char *p = “abcdefg”;
 char a[] =“abcdefg”;
那麼,p[i]與a[i]的區別?
a[i]是直接在(符號表a的地址+i)處獲取內容,即為直接引用。
p[i]是先獲取符號表p地址的內容,然後在該內容上+i地址處獲取內容,即為間接引用。這裡的“間接”指的是要被操作的地址不能直接從編譯器符號表中直接獲得,而是從指標物件中獲得。


     char str1[] = "abc";
  char str2[] = "abc";
  const char str3[] = "abc";
  const char str4[] = "abc";

  const char *str5 = "abc";
  const char *str6 = "abc";

  char *str7 = "abc";
  char *str8 = "abc";

  cout << ( str1 == str2 ) << endl;
  cout << ( str3 == str4 ) << endl;
  cout << ( str5 == str6 ) << endl;
  cout << ( str7 == str8 ) << endl;

 

   列印結果是什麼?

解答:結果是:0 0 1 1

str1,str2,str3,str4是陣列名,各表示一個數組變數(即物件變數),它們有各自的記憶體空間;而str5,str6,str7,str8是指標變數,它們指向相同的常量區域。不同的物件之間當然不可能相等,而指向相同區域的指標變數是相等的。

-----------------------------------------------

5. sizeof()函式

以下程式碼中的兩個sizeof用法有問題嗎?
void UpperCase( char str[] ){ // 將 str 中的小寫字母轉換成大寫字母 
 int i; 
 for( i = 0; i < sizeof(str)/sizeof(str[0]); ++i ){ 
 if(str[i] >= 'a' && str[i] <= 'z') 
           str[i] -= ('a'-'A' ); 
 }

}

int main(){ 
 char str[] = "aBcDe"; 
 printf("str字元長度為: %lu/n", sizeof(str)/sizeof(str[0])); 
 UpperCase( str ); 
 printf("%s/n", str); 
}

 

答:函式內的sizeof有問題。

根據語法,sizeof只能測出定義的物件,不能測出宣告的變數。靜態陣列是定義的物件,可以測出;而在函式內,str只是一個宣告的變數,非定義的物件,故不能測出。
在gcc4.4.5/x86_64-linux-gnu環境下有,
sizeof(char*)=8
sizeof(int*)=8
所以,這裡可以得到正確的結果,但是有時候,可能出現數組越界的情況。


-------------------------------------------------

 

6.C不進行陣列 的下標檢查,地址可以越界,間接訪問的時候可能出現“段錯誤”:
 int a[5]={1,2,3,4,5}; 
 int *ptr=(int *)(&a+1); 
 printf("%d,%d/n",*(a+1),*(ptr-1));
   輸出結果是什麼?

  答案:輸出:2,5
  *(a+1)就是a[1],*(ptr-1)就是a[4],執行結果是2,5
  &a+1不是首地址+1,系統會認為加一個a陣列的偏移,是偏移了一個數組的大小(本例是5個int)
  &a是陣列指標,其型別為 int (*)[5];

--------------------------------------------

 

7.strcpy()函式:

int main(){ 
 char a; 
 char *str=&a; 
 strcpy(str,"hello"); 
 printf("%s/n", str); 
}
  答案:沒有為str分配記憶體空間,將會發生異常。問題出在將一個字串複製進一個字元變數指標所指地址。雖然可以正確輸出結果,但因為越界進行內在讀寫而導致程式崩潰。

---------------------------------------------

 

8.指標的間接引用

分析下面程式碼的問題:
    char* s="AAA";
   printf("%s",s);
   s[0]='B';
   printf("%s",s);
  
分析:物件s的內容,是一個常量字串“AAA”記憶體空間的首地址。s[0]='B'這一句,表示給一個字元常量賦值,顯然是不合法的。


---------------------------------------------

9. int (*s[10])(int) 表示的是什麼?

  答案:int (*s[10])(int) 函式指標陣列,每個指標指向一個int func(int param)的函式。

---------------------------------------------

10. 傳值函式,對主函式中的變數沒有影響
void getmemory(char *p){ 
 p=(char *) malloc(100); 
 strcpy(p,"hello world"); 

int main(){ 
 char *str=NULL; 
 getmemory(str); 
 printf("%s",str); 
 printf("/n");   
 free(str); 
 return 0; 
}
在getmemory()函式中,引數p充當一個行參。在主函式中,free()操作一個空指標,不會起任何作用。


------------------------------------------

 

11.要對絕對地址0x100000賦值,我們可以用*((unsigned int*)0x100000) = 1234;

   那麼要是想讓程式跳轉到絕對地址是0x100000去執行,應該怎麼做?

這裡必須要注意:有方法分配指定區域的記憶體,是給絕對地址賦值的前提條件。糾結的是,C沒有提供分配指定區域記憶體的方法。
  答案:*((void (*)( ))0x100000 ) ( );

  首先要將0x100000強制轉換成函式指標,即:

  (void (*)())0x100000
  然後再呼叫它:
  *((void (*)())0x100000)();
  用typedef可以看得更直觀些:
  typedef void(*)() voidFuncPtr;
  *((voidFuncPtr)0x100000)();

------------------------------------------

 

12. 分析下面的程式:
void GetMemory(char **p,int num){                     
 *p = malloc(num); 
}  
int main() 

 char *str=NULL;

 GetMemory(&str,100);  
 strcpy(str,"hello"); 
 free(str); 
 if(str!=NULL){ 
  printf("%X/n", str); 
 }   
}
  問輸出結果是什麼?
  答案:輸出的是指標物件str的值。在個指標分配記憶體的時候,其實給指標物件賦了一個值,這個值就是這片空間的首地址。釋放空間後,這個指標物件的值,其實是指向沒有被分配空間的地址。訪問這樣的越界空間,編譯是沒有問題的,但是執行時編譯器出現“Segmentation fault”.

-------------------------------------------

 

13.分析下面程式的結果:

int main() 

 char a[10]; 
 printf("%d",strlen(a)); 
}

答案:0,這由strlen()函式的內部實現有關。
--------------------------------------------

 

14.char (*str)[20];

  char *str[20];

---------------------------------------------

 

15.分析下面程式碼:

typedef struct AA{ 
 int b1 : 5; 
 int b2 : 2; 
}AA;

void main() 

 AA aa; 
 printf("%d/n", 'A'); 
 char cc[100]; 
 strcpy(cc,"0123456789abcdefghijklmnopqrstuvwxyz"); 
 memcpy(&aa,cc,sizeof(AA));//將sizeof(AA)個連續的位元組空間(從cc開始),源和目的地不能重疊 
 printf("%d %d/n", aa.b1, aa.b2);

}

  首先sizeof(AA)的大小為4,b1和b2分別佔5bit和2bit.經過strcpy和memcpy後,aa的4個位元組所存放的值是: 0,1,2,3的ASC碼,即00110000,00110001,00110010,00110011所以,最後一步:顯示的是這4個位元組的前5位,和之後的2位分別為:10000,和01,因為int是有正負之分