クラシックC++面接問題

3868 ワード

1.++aとa++について
 
   int a = 5;では++(a++)の値はいくらですか?
         
この問題といえば、まず++aとa++の違いを研究します.コンパイラの++aに対する呼び出しは、int operator++(int)に相当します.
で、返すのはintタイプなので、aの左に何個++があってもいいです.一方、a++では異なり、コンパイラでは、
呼び出しconst int operator++()に相当し、ここでのconstは定数であるため、右の値としてのみ使用でき、++を行うことはできません.
a+++では合法ではありません.また++aの実行後の結果はaに保存され、すなわちa=++aに相当するが、a++の場合、実行後の結果は
一時変数に保存されます.この一時変数はconstの右の値で、すぐに消えます.だから、上の++(a++)コンパイル会
エラー.
 
では、上の分析を経て、次の問題はずっと簡単になりました.
   int a = 3;
   int b = (++a) + (++a);
   int c = (a++) + (a++);
bとcの値を求めます.
 
bにとって、私たちはまず++aを見て、それはa=++aに相当して、実行が終わった後に、もう1つの++aがあって、だからa=5を得て、最終的に
b=a+a=10
 
cにとって,a++は先に再+,すなわちc=a+a=6を用いるため,a++の結果は一時変数であり,その後すぐに消失し,
まったく役に立たなかった.
 
2.ポインタ
 
次のコード出力結果を求めます
   int a[5] = {1,2,3,4,5};
   int *p = (int *)(&a + 1);
   printf("%d %d",*(a+1),*(p-1));
 
ここでは(&a+1)ではなく(&a+1),&aは配列を指すポインタであり,行ポインタであることに注意してください.
上(&a+1)は境界を越えて、私たちのp-1はちょうど配列の最後の要素なので、2 5を出力するべきです.実際には1次元配列は特と見なすことができる
特別な2次元配列、すなわちa[1][5]では、上のコードは以下のコードと等価である.
   int a[1][5] = {1,2,3,4,5};
   int *p = (int *)(&a + 1);
   printf("%d %d",*(a[0]+1),*(p-1));
 
3.char s[]とchar*s
 
    char s1[] = "abc";
    char s2[] = "abc";
    char *s3 = "abc";
    char *s4 = "abc";
    cout<<(s1 == s2)<    cout<<(s3 == s4)<上のコードはどんな結果を出力しますか?
 
これはchar s[]とchar*sの違いを明らかにすることです.char s[]では、後続のメモリ領域を格納するために毎回メモリ領域を開きます.
文字列の内容は、文字列の内容が同じかどうかにかかわらず、独自のストレージスペースがあります.char*sにとっては、文字ポインタであり、記憶空を割り当てない
間、後の文字列の内容が静的記憶領域に格納されると、対応するすべてのsポインタがこの定数文字列を指すので、0 1を出力すべきである.
 
4.sizeofについて
    
sizeofは関数ではありませんが、sizeof(str)です.知らないかもしれませんが、sizeof strもできます.だから、sizeofはC++ではキーワードです.
 
 char s1[] = "abcdefg";
     char *s2 = "abcdefg";
 char s3[105] = "abcdefg";
 cout< cout< cout< 
出力結果は8 4 105の順
まずs 1については配列名であり、s 1[]についてはメモリに空間を開いているのでsizeof s 1は配列全体の長さを表し、配列に注意する
末尾にはもう一つ'0'があるので、長さは8です.s 2については、ポインタであり、ポインタが格納されているのはアドレスであり、C++のアドレスは
4バイトで格納されるので、s 2は永遠に4です.s 3[105]では、自身が105バイトの空間を開いているため、出力105となる.
 
5.文字列コピー関数
     
1つの関数を書いて、文字列のコピー機能を実現して、関数のポインタを返して、関数の原型は以下の通りです:
char *strcpy(char *strDest, const char *strSrc);
  char *strcpy(char *strDest,const char *strSrc)
  {
      assert(strDest != NULL && strSrc != NULL);
      char *address = strDest;
      while((*strDest++ = *strSrc++) != '\0');
      return address;
}

チェーン式を実現するためにaddressを返す理由.
    
上記のコピーでは完璧なようですが、メモリ容量が重複していない場合にのみ適用されます.メモリ領域が重複している場合は、状況に応じて順方向コピーまたは逆方向コピーを行う必要があります.
void *memcpy(void *strDest,const void *strSrc,size_t cnt)
    {     
           assert(strDest != NULL && strSrc != NULL);
           assert(cnt > 0);

           char *psrc = (char *)strSrc;
           char *pdest = (char *)strDest;
           if(pdest < psrc)
           {
                 while(cnt--)
                    *pdest++ = *psrc++;
           }
           else if(psrc < pdest)
           {
                 psrc += cnt - 1;
                 pdest += cnt - 1;
                 while(cnt--)
                    *pdest-- = *psrc--;
           }
           return strDest;
    }          

6.一般的なポインタ
 
    int *p[n];---各要素が整数データを指すポインタ配列.
    int (*)p[n];------pは1次元配列を指すポインタで、この1次元配列にはn個の整数データがある.
    int *p();------関数はポインタを返し、ポインタは返された値を指します.
    int (*)p();------pは、関数を指すポインタです.