深入理解"指針"之面試題解析

   該編文章是收集網絡上有關指針題目並對其進行整理,其目的是加深對指針的理解,使自己對指針理解更加透徹。文章以講解題目爲主同時在原有題目基礎上進行拓展。

   一些理解不正確的地方,希望各位指正! 謝謝

   文章爲原創,轉載請註明出處,謝謝 ; 

   作者  :  飛哥

1.請說明以下定義指針之間的區別:

char  const * p1;    
char * const  p2;  
char const const p3; 
const char const p4;

  1) p1 稱之爲: 常量指針,就是指向常量的指針,該指針的目標不可被修改,但是指針本身可以被修改。

   例如:
    int n = 100;
    const int* p = &n; // int const* p;
    *p = 200; // error !
    int m = 1000;
    p = &m;
    (*p)++; // error !


  2) p2 稱之爲 : 指針常量就是指針類型的常量,該指針本身不能被修改,但是指針的目標可以被修改。

   例如:
    int n = 100;
    int* const p = &n;
    *p = 200; // ok !
    int m = 1000;
    p = &m; // error !
  3)p3和p4指針是意義是相同的,稱之爲: 常量指針常量,指針本身和它的目標都是常量,都不可被修改。

      這兩個指針比較好理解,我再次不再贅述;

   例如: 
    int n = 100, m = 1000;
    const int* const p = &n;
    *p = 200; // error !
    p = &m; // error !

  
   結論:   1.
常量指針,是常量不可以被修改,或者說指向不改變;

              2.指針常量,是指針本身不能被修改;或者說指向可以改變;

   爲避免混淆,您可以這樣理解:

      口頭提問時   :  常量指針和指針常量區別:  "指針"開頭表示指針本身不能被修改,"常量"開頭表示指向的內容不能被修改;

      自己理解時  :  " * " 後有const表示指針不能被改變; “ * ” 前有const表示指針指向的目標不能被改變;   


2.指針和引用區別

  1)概念不同:
    指針是指向變量的地址;
    引用是爲變量起別名。
  2)指針可以爲NULL,但引用不能;
     例如:  int *p = NULL;  //ok
               int& p = NULL; //error
  3)指針可以不被初始化,但引用不能;
     例如:  int* p;  //ok
               int& p;  //error;
  4)非常量的指針指向的對象可以改變,但是引用一旦初始化,其引用的對象就不能被改變;
      例如:
        int a,b;
        int* p = &a;
        p = &b;  //此時p指向了b;
      但是:
        int& r = b;
        r = a;  //此時r還是b的別名而不是a的別名;
   5)有指針常量,但是沒有引用常量(上訴4已經證明)
       但可以有常量引用:     
       例如:  const int&  r = a;
                 r = 200;  //error;
                 int const & r = a;  //error,無法編譯通過,不存在引用常量;
     通過對第一個知識點的理解,相信您能很快理解這個錯誤原因;
   6)存在指針的指針但不存在引用的引用也不存在引用的指針;
     例如:   char*&  p1 = p;  //ok
                char&*  p1 = p;  //error
    7)存在指針數組但不存在引用數組
     例如:  int * arr[10]; //ok
               int & arr[10]; //error

3.請說明下面輸出結果

   
    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是指針,它們指向相同的常量區域。
     如果還是不懂,請看我寫的"重新認識數組"這篇文章。

4.下面輸出數組大小的函數有沒有問題?

int Strlen(char str[])
{
    return (int)(sizeof(str)-1);
}
  有問題,函數 strlen(char str[])與strlen(char* pStr)寫法的含義相同,在形參與實參結合過程中,
  實際上是一個賦值的過程,實參爲數組傳到形參後,形參只是一個指針,指針大小在32位下是4字節;
  所以有問題;
  如果還是不懂,請看我寫的"重新認識數組"這篇文章。

5.說說下面兩者的區別:

   char *p = “abcdefg”;
   char a[] =“abcdefg”;
   那麼,p[i]與a[i]的區別?
  a[i]是直接在(符號表a的地址+i)處獲取內容,即爲直接引用。
  p[i]是先獲取符號表p地址的內容,然後在該內容上+i地址處獲取內容,即爲間接引用。這裏的“間接”指的是要被操作的地址不能直接從編譯器符號表     中直接獲得,而是從指針對象中獲得。

6. 
 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)是首地址向後便宜一個4字節取目標,等價於a[1];
           &a  :  此時"a"代表的是整個數組;   //如果不懂,可以 看"重新認識數組"中的如何區分什麼時候代表整個數據什麼時候代表首地址;
                     等價於 int (*a)[5]的寫法(數組指針),即a是指向數組的,
                     而ptr-1則是普通的整形指針向後偏移4字節,
7.說說下面的區別? 
   int (*p[10])(int);
   int  (*p)(int);
   int (* p)[10];
  釋義:   int  (*p)(int);  是一個函數指針,指向一個類似 int func(int ) 類型的函數;
             int  (*p[10])(int),是指向10個類似上面的函數指針的指針
             int (*p)[10]; //數組指針,存放指向數組的指針;
8.請問下面代碼有什麼結果?
	void get_memory(char *p)
	{
		p = (char *)malloc(sizeof(char) * 100);
	}

	void test(void)
	{
		char *str = NULL;
		
		get_memory(str);
		strcpy(str, "hello world");
		
		printf("%s\n", str);
	}

  答案: 段錯誤
  釋義:  char* str = NULL;也就是說str變量沒有任何指向;
            當其作爲參數傳入get_memory後形參作爲任然是一個野指針,分配空間後和實任何實參的str沒有任何關係;
            實參str仍然爲null,拷貝時當然會崩潰或者出現段錯誤;
  修改:  get_memory(&str);便可;











 


        
   


     








發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章