[收集] 經典C/C++面試題(六)

來源:互聯網
上載者:User

1) 什麼是先行編譯,何時需要先行編譯:

  總是使用不經常改動的大型代碼體。

    程式由多個模組組成,所有模組都使用一組標準的包含檔案和相同的編譯選項。在這種情況下,可以將所有包含檔案先行編譯為一個先行編譯頭。

2)  char * const p;
  char const * p
  const char *p

  上述三個有什麼區別?

  char * const p; //常量指標,p的值不可以修改
  char const * p;//指向常量的指標,指向的常量值不可以改
  const char *p; //和char const *p

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) 以下代碼中的兩個sizeof用法有問題嗎?

  void UpperCase( char str[] ) // 將 str 中的小寫字母轉換成大寫字母
  {
      for( size_t i=0; i<sizeof(str)/sizeof(str[0]); ++i )
         if( 'a'<=str[i] && str[i]<='z' )
           str[i] -= ('a'-'A' );
  }
  char str[] = "aBcDe";
  cout << "str字元長度為: " << sizeof(str)/sizeof(str[0]) << endl;
  UpperCase( str );
  cout << str << endl;

 答:函數內的sizeof有問題。根據文法,sizeof如用於數組,只能測出靜態數組的大小,無法檢測動態分配的或外部數組大小。函數外的str是一個靜態定義的數組,因此其大小為6,函數內的str實際只是一個指向字串的指標,沒有任何額外的與數組相關的資訊,因此sizeof作用於上只將其當指標看,一個指標為4個位元組,因此返回4。

5) 一個32位的機器,該機器的指標是多少位?

 指標是多少位只要看地址匯流排的位元就行了。80386以後的機子都是32的資料匯流排。所以指標的位元就是4個位元組了。

6) main()
  {
   int a[5]={1,2,3,4,5};
   int *ptr=(int *)(&a+1);
   printf("%d,%d",*(a+1),*(ptr-1));
  }

  輸出:2,5

  *(a+1)就是a[1],*(ptr-1)就是a[4],執行結果是2,5
  &a+1不是首地址+1,系統會認為加一個a數組的位移,是位移了一個數組的大小(本例是5個int)
  int *ptr=(int *)(&a+1);
  則ptr實際是&(a[5]),也就是a+5
  
  原因如下:

  &a是數組指標,其類型為 int (*)[5];
  而指標加1要根據指標類型加上一定的值,不同類型的指標+1之後增加的大小不同。
  a是長度為5的int數組指標,所以要加 5*sizeof(int)
  所以ptr實際是a[5]
  但是prt與(&a+1)類型是不一樣的(這點很重要)
  所以prt-1隻會減去sizeof(int*)
  a,&a的地址是一樣的,但意思不一樣,a是數組首地址,也就是a[0]的地址,&a是對象(數組)首地址,a+1是數組下一元素的地址,即a[1],&a+1是下一個對象的地址,即a[5].

7) 請問以下代碼有什麼問題:

  int  main()
  {
   char a;
   char *str=&a;
   strcpy(str,"hello");
   printf(str);
   return 0;
  }

  沒有為str分配記憶體空間,將會發生異常。問題出在將一個字串複製進一個字元變數指標所指地址。雖然可以正確輸出結果,但因為越界進行內在讀寫而導致程式崩潰。

8)
  char* s="AAA";
  printf("%s",s);
  s[0]='B';
  printf("%s",s);

  有什麼錯?

  "AAA"是字串常量。s是指標,指向這個字串常量,所以聲明s的時候就有問題。

  cosnt char* s="AAA";

  然後又因為是常量,所以對是s[0]的賦值操作是不合法的。

9) 寫一個“標準”宏,這個宏輸入兩個參數並返回較小的一個。

  .#define Min(X, Y) ((X)>(Y)?(Y):(X))//結尾沒有;

10) 嵌入式系統中經常要用到無限迴圈,你怎麼用C編寫死迴圈。

  while(1){}或者for(;;)
軟體開發網 www.mscto.cn
11) 關鍵字static的作用是什嗎?

  定義靜態變數

12) 關鍵字const有什麼含意?

  表示常量不可以修改的變數。

13) 關鍵字volatile有什麼含意?並舉出三個不同的例子?

  提示編譯器對象的值可能在編譯器未監測到的情況下改變。

14) int (*s[10])(int) 表示的是什嗎?

  int (*s[10])(int) 函數指標數組,每個指標指向一個int func(int param)的函數。

15) 有以下運算式:

  int a=248; b=4;
  int const c=21;
  const int *d=&a;
  int *const e=&b;
  int const *f const =&a;

  請問下列運算式哪些會被編譯器禁止?為什嗎?

  *c=32;d=&b;*d=43;e=34;e=&a;f=0x321f;
  *c 這是個什麼東東,禁止
  *d 說了是const, 禁止
  e = &a 說了是const 禁止
  const *f const =&a; 禁止

16) 交換兩個變數的值,不使用第三個變數。即a=3,b=5,交換之後a=5,b=3;

  有兩種解法, 一種用算術演算法, 一種用^(異或)
  a = a + b;
  b = a - b;
  a = a - b;
  or
  a = a^b;// 只能對int,char..
  b = a^b;
  a = a^b;
  or
  a ^= b ^= a;

17) c和c++中的struct有什麼不同?

  c和c++中struct的主要區別是c中的struct不可以含有成員函數,而c++中的struct可以。c++中struct和class的主要區別在於預設的存取許可權不同,struct預設為public,而class預設為private。

18) #include <stdio.h>
  #include <stdlib.h>
  void getmemory(char *p)
  { 
   p=(char *) malloc(100);
   strcpy(p,"hello world");
  } 
  int main( )
  {
   char *str=NULL;
   getmemory(str);
   printf("%s/n",str);
   free(str);
   return 0;
  }

  程式崩潰,getmemory中的malloc 不能返回動態記憶體, free()對str操作很危險

19) char szstr[10];
    strcpy(szstr,"0123456789");
    產生什麼結果?為什嗎?
 
  長度不一樣,會造成非法的OS

20) 列舉幾種進程的同步機制,並比較其優缺點。
  
  原子操作
  訊號量機制
  自旋鎖
  管程,會合,分布式系統

21) 進程之間通訊的途徑

  共用儲存系統
  訊息傳遞系統
  管道:以檔案系統為基礎

22) 進程死結的原因

  資源競爭及進程推進順序非法

23) 死結的4個必要條件

  互斥、請求保持、不可剝奪、環路

24) 死結的處理

  鴕鳥策略、預防策略、避免策略、檢測與解除死結

25) 作業系統中進程調度策略有哪幾種?

  FCFS(先來先服務),優先順序,時間片輪轉,多級反饋

26) 類的靜態成員和非靜態成員有何區別?

  類的靜態成員每個類只有一個,非靜態成員每個對象一個

27) 純虛函數如何定義?使用時應注意什嗎?

  virtual void f()=0;
  是介面,子類必須要實現

28) 數組和鏈表的區別

  數組:資料順序儲存,固定大小
  連表:資料可以隨機儲存,大小可動態改變

29) ISO的七層模型是什嗎?tcp/udp是屬於哪一層?tcp/udp有何優缺點?

  應用程式層
  展示層
  會話層
  運輸層
  網路層
  物理鏈路層
  物理層
  tcp /udp屬於運輸層
  TCP 服務提供了資料流傳輸、可靠性、有效流量控制、全雙工系統操作和多工技術等。
  與 TCP 不同, UDP 並不提供對 IP 協議的可靠機制、流量控制以及錯誤恢複功能等。由於 UDP 比較簡單, UDP 頭包含很少的位元組,比 TCP 負載消耗少。
  tcp: 提供穩定的傳輸服務,有流量控制,缺點是包頭大,冗餘性不好
  udp: 不提供穩定的服務,包頭小,開銷小 

30) (void *)ptr 和 (*(void**))ptr的結果是否相同?
        其中ptr為同一個指標(void *)ptr 和 (*(void**))ptr值是相同的

32)
  int main()
  {
   int x=3;
   printf("%d",x);
   return 1;
  }

  問函數既然不會被其它函數調用,為什麼要返回1?

  mian中,c標準認為0表示成功,非0表示錯誤。具體的值是某中具體出錯資訊

33) 要對絕對位址0x100000賦值,我們可以用(unsigned int*)0x100000 = 1234;那麼要是想讓程式跳轉到絕對位址是0x100000去執行,應該怎麼做?

  *((void (*)( ))0x100000 ) ( );
  首先要將0x100000強制轉換成函數指標,即:
  (void (*)())0x100000
  然後再調用它:
  *((void (*)())0x100000)();
  用typedef可以看得更直觀些:
  typedef void(*)() voidFuncPtr;
  *((voidFuncPtr)0x100000)();

34) 已知一個數組table,用一個宏定義,求出資料的元素個數

  #define NTBL
  #define NTBL (sizeof(table)/sizeof(table[0]))

35) 線程與進程的區別和聯絡? 線程是否具有相同的堆棧? dll是否有獨立的堆棧?

  進程是死的,只是一些資源的集合,真正的程式執行都是線程來完成的,程式啟動的時候作業系統就幫你建立了一個主線程。

  每個線程有自己的堆棧。DLL中有沒有獨立的堆棧?

  這個問題不好回答,或者說這個問題本身是否有問題。因為DLL中的代碼是被某些線程所執行,只有線程擁有堆棧,如果DLL中的代碼是EXE中的線程所調用,那麼這個時候是不是說這個DLL沒有自己獨立的堆棧?如果DLL中的代碼是由DLL自己建立的線程所執行,那麼是不是說DLL有獨立的堆棧?

  以上講的是堆棧,如果對於堆來說,每個DLL有自己的堆,所以如果是從DLL中動態分配的記憶體,最好是從DLL中刪除,如果你從DLL中分配記憶體,然後在EXE中,或者另外一個DLL中刪除,很有可能導致程式崩潰。

36) unsigned short A = 10;
  printf("~A = %u\n", ~A);

  char c=128;
  printf("c=%d\n",c);

 輸出多少?並分析過程

  第一題,~A =0xfffffff5,int值 為-11,但輸出的是uint。所以輸出4294967285

  第二題,c=0x10,輸出的是int,最高位為1,是負數,所以它的值就是0x00的補碼就是128,所以輸出-128。
這兩道題都是在考察二進位向int或uint轉換時的最高位處理。

 37) 分析下面的程式:

  void GetMemory(char **p,int num)
  {
   *p=(char *)malloc(num);
  }      
  int main()
  {
     char *str=NULL;
   GetMemory(&str,100);
   strcpy(str,"hello");
   free(str);
     if(str!=NULL)
     {
       strcpy(str,"world");
     }   
      printf("\n str is %s",str); 軟體開發網 www.mscto.com
     getchar();
  }  

  問輸出結果是什嗎?

  輸出str is world。

  free 只是釋放的str指向的記憶體空間,它本身的值還是存在的.所以free之後,有一個好的習慣就是將str=NULL.
此時str指向空間的記憶體已被回收,如果輸出語句之前還存在分配空間的操作的話,這段儲存空間是可能被重新分配給其他變數的,
儘管這段程式確實是存在大大的問題(上面各位已經說得很清楚了),但是通常會列印出world來。
這是因為,進程中的記憶體管理一般不是由作業系統完成的,而是由庫函數自己完成的。

  當你malloc一塊記憶體的時候,管理庫向作業系統申請一塊空間(可能會比你申請的大一些),然後在這塊空間中記錄一些管理資訊(一般是在你申請的記憶體前面一點),並將可用記憶體的地址返回。但是釋放記憶體的時候,管理庫通常都不會將記憶體還給作業系統,因此你是可以繼續訪問這塊地址的。

  char a[10],strlen(a)為什麼等於15?啟動並執行結果

38) #include "stdio.h"
  #include "string.h"

  void main()
  {
   char aa[10];
   printf("%d",strlen(aa));
  }

  sizeof()和初不初始化,沒有關係;
  strlen()和初始化有關。

39) char (*str)[20]; /*str是一個數組指標,即指向數組的指標.*/
  char *str[20];   /*str是一個指標數組,其元素為指標型資料.*/

40) long a=0x801010;
  a+5=?
  0x801010用二進位表示為:“1000 0000 0001 0000 0001 0000”,十進位的值為8392720,再加上5就是8392725羅

41) 給定結構
  struct A
  {
        char t:4;
        char k:4;
        unsigned short i:8;
        unsigned long m;
  };

  問sizeof(A) = ?
  
  給定結構
  struct A
  {
        char t:4; 4位
        char k:4; 4位
        unsigned short i:8; 8位    
        unsigned long m; // 位移2位元組保證4位元組對齊
  }; // 共8位元組

42) 下面的函數實現在一個數上加一個數,有什麼錯誤?請改正。
  int add_n ( int n )
  {
      static int i = 100;
      i += n;
      return i;
  }

  當你第二次調用時得不到正確的結果,難道你寫個函數就是為了調用一次?問題就出在 static上?

43) 分析一下
  #include<iostream.h>
  #include <string.h>
  #include <malloc.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <memory.h>
  typedef struct  AA
  {
         int b1:5;
         int b2:2;
  }AA;
  void main()
  {
   AA aa;
   char cc[100];
   strcpy(cc,"0123456789abcdefghijklmnopqrstuvwxyz");
   memcpy(&aa,cc,sizeof(AA));
   cout << aa.b1 <<endl;
   cout << aa.b2 <<endl;
  }

  答案是 -16和1

  首先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是有正負之分  

  所以:答案是-16和1

44) 求函數傳回值,輸入x=9999;
  int func ( x )
  {
      int countx = 0;
      while ( x )
      {
          countx ++;
          x = x&(x-1);
      }
      return countx;
  }

  結果呢?

  知道了這是統計9999的位元值中有多少個1的函數,且有9999=9×1024+512+256+15

  9×1024中含有1的個數為2;
  512中含有1的個數為1;
  256中含有1的個數為1;
  15中含有1的個數為4; 軟體開發網 www.mscto.com
  故共有1的個數為8,結果為8。
  1000 - 1 = 0111,正好是原數取反。這就是原理。
  用這種方法來求1的個數是很效率很高的。
  不必去一個一個地移位。迴圈次數最少。

  int a,b,c 請寫函數實現C=a+b ,不可以改變資料類型,如將c改為long int,關鍵是如何處理溢出問題
  bool add (int a, int b,int *c)
  {
   *c=a+b;
   return (a>0 && b>0 &&(*c<a || *c<b) || (a<0 && b<0 &&(*c>a || *c>b)));
  }

45) 分析:
  struct bit
  { 
     int a:3;
     int b:2;
      int c:3;
  };
  int main()
  {
    bit s;
    char *c=(char*)&s;
     cout<<sizeof(bit)<<endl;
    *c=0x99;
     cout << s.a <<endl <<s.b<<endl<<s.c<<endl;
     int a=-1;
    printf("%x",a);
    return 0;
  }

  輸出為什麼是
  4
  1
  -1
  -4
  ffffffff

    因為0x99在記憶體中表示為 100 11 001 , a = 001, b = 11, c = 100。當c為有符合數時, c = 100, 最高1為表示c為負數,負數在電腦用補碼錶示,所以c = -4;同理 b = -1;當c為有符合數時, c = 100,即 c = 4,同理 b = 3。

46) 位域 : 

  有些資訊在儲存時,並不需要佔用一個完整的位元組, 而只需占幾個或一個二進位位。例如在存放一個開關量時,只有0和1 兩種狀態, 用一位二進位即可。為了節省儲存空間,並使處理簡便,C語言又提供了一種資料結構,稱為“位域”或“位段”。所謂“位域”是把一個位元組中的二進位劃分為幾個不同的地區, 並說明每個地區的位元。每個域有一個網域名稱,允許在程式中按網域名稱進行操作。 這樣就可以把幾個不同的對象用一個位元組的二進位位域來表示。一、位域的定義和位域變數的說明位域定義與結構定義相仿,其形式為:   

  struct 位域結構名 { 位域列表 };  其中位域列表的形式為: 類型說明符 位網域名稱:位域長度
  
  例如:   
  struct bs  
  {  
   int a:8;  
   int b:2;  
   int c:6;  
  };  

  位域變數的說明與結構變數說明的方式相同。 可採用先定義後說明,同時定義說明或者直接說明這三種方式。例如:   
  struct bs  
  {  
   int a:8;  
   int b:2;  
   int c:6;  
  }data;  

  說明data為bs變數,共佔兩個位元組。其中位域a佔8位,位域b佔2位,位域c佔6位。對於位域的定義尚有以下幾點說明:  

  一個位域必須儲存在同一個位元組中,不能跨兩個位元組。如一個位元組所剩空間不夠存放另一位域時,應從下一單元起存放該位域。也可以有意使某位域從下一單元開始。例如:   
  
  struct bs  
  {  
   unsigned a:4  
   unsigned :0 /*空域*/  
   unsigned b:4 /*從下一單元開始存放*/  
   unsigned c:4  
  }  

  在這個位域定義中,a占第一位元組的4位,後4位填0表示不使用,b從第二位元組開始,佔用4位,c佔用4位。  

  由於位域不允許跨兩個位元組,因此位域的長度不能大於一個位元組的長度,也就是說不能超過8位二進位。  

  位域可以無位網域名稱,這時它只用來作填充或調整位置。無名的位域是不能使用的。例如:   

  struct k  
  {  
   int a:1  
   int :2 /*該2位不能使用*/  
   int b:3  
   int c:2  
  };  

  從以上分析可以看出,位域在本質上就是一種結構類型, 不過其成員是按二進位分配的。  

  位域的使用位域的使用和結構成員的使用相同,其一般形式為: 位域變數名?位網域名稱 位域允許用各種格式輸出。  

  main()
  {  
   struct bs  
   {  
    unsigned a:1;  
    unsigned b:3;  
    unsigned c:4;  
   }
   bit,*pbit;  
   bit.a=1;  
   bit.b=7;  
   bit.c=15;  
   pri

47) 改錯:
  #include <stdio.h>
  int main(void)
  {
    int **p;
     int arr[100];
    p = &arr;
    return 0;
  }

  解答:搞錯了,是指標類型不同,int **p; //二級指標&arr; //得到的是指向第一維為100的數組的指標
  
  #include <stdio.h>
  int main(void)
  {
   int **p, *q;
   int arr[100];
   q = arr;
   p = &q;
   return 0;
  }

48) 下面這個程式執行後會有什麼錯誤或者效果:

  #define MAX 255
  int main()
  {
     unsigned char A[MAX],i;//i被定義為unsigned char
     for (i=0;i<=MAX;i++)
      A[i]=i;
       return 0;   
  }

  解答:死迴圈加數組越界訪問(C/C++不進行數組越界檢查)MAX=255 數組A的下標範圍為:0..MAX-1,這是其一..
    其二.當i迴圈到255時,迴圈內執行:A[255]=255;這句本身沒有問題..但是返回for (i=0;i<=MAX;i++)語句時,由於unsigned char的取值範圍在(0..255),i++以後i又為0了..無限迴圈下去。

49) struct name1
  {
     char  str;
     short x;
     int   num;
  }
  struct name2
  {
     char str;
     int num;
     short x;
  }

  sizeof(struct name1)=8,sizeof(struct name2)=12

  在第二個結構中,為保證num按四個位元組對齊,char後必須留出3位元組的空間;同時為保證整個結構的自然對齊(這裡是4位元組對齊),在x後還要補齊2個位元組,這樣就是12位元組。

50) intel:

  A.c 和B.c兩個c檔案中使用了兩個相同名字的static變數,編譯的時候會不會有問題?這兩個static變數會儲存到哪裡(棧還是堆或者其他的)?
    static的全域變數,表明這個變數僅在本模組中有意義,不會影響其他模組。他們都放在資料區,但是編譯器對他們的命名是不同的。如果要使變數在其他模組也有意義的話,需要使用extern關鍵字。

51) struct s1
  {
     int i: 8;
     int j: 4;
     int a: 3;
     double b;
  };

  struct s2
  {
     int i: 8;
     int j: 4;
     double b;
     int a:3;
  };

  printf("sizeof(s1)= %d\n", sizeof(s1));
  printf("sizeof(s2)= %d\n", sizeof(s2));
  result: 16, 24
  第一個struct s1
  {
     int i: 8;
     int j: 4;
     int a: 3;
     double b;
  };

  理論上是這樣的,首先是i在相對0的位置,佔8位一個位元組,然後,j就在相對一個位元組的位置,由於一個位置的位元組數是4位的倍數,因此不用對齊,就放在那裡了,然後是a,要在3位的倍數關係的位置上,因此要移一位,在15位的位置上放下,目前總共是18位,折算過來是2位元組2位的樣子,由於double 是8位元組的,因此要在相對0要是8個位元組的位置上放下,因此從18位開始到8個位元組之間的位置被忽略,直接放在8位元組的位置了,因此,總共是16位元組。 

  第二個最後會對照是不是結構體內最大資料的倍數,不是的話,會補成是最大資料的倍數。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.