クラシック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);
チェーン式を実現するためにaddressを返す理由.
上記のコピーでは完璧なようですが、メモリ容量が重複していない場合にのみ適用されます.メモリ領域が重複している場合は、状況に応じて順方向コピーまたは逆方向コピーを行う必要があります.
6.一般的なポインタ
int *p[n];---各要素が整数データを指すポインタ配列.
int (*)p[n];------pは1次元配列を指すポインタで、この1次元配列にはn個の整数データがある.
int *p();------関数はポインタを返し、ポインタは返された値を指します.
int (*)p();------pは、関数を指すポインタです.
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)<
これは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<
出力結果は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は、関数を指すポインタです.