14のC言語の迷題はhttp://blog.csdn.net/haoel/archive/2009/06/01/4231029.aspx
この文章「C言語のパズル」は14のC言語のパズルと答えを示しています.コードは十分にはっきりしているはずです.そして、私たちの日常の仕事で会える可能性があると信じています.これらの謎を通して、C言語をもっと理解してほしい.もしあなたが答えを見なければ、それぞれのパズルに答える自信がありますか?やってみましょう.
1、次のプログラムはhello-std-outを出力するとは限らないが、なぜか知っていますか.
参考答案:stdoutとstderrは同じデバイス記述子ではありません.stdoutはブロックデバイスであり、stderrはそうではない.ブロックデバイスについては,次のいくつかの場合にのみ入力され,1)リターンに遭遇し,2)バッファ満杯,3)flushが呼び出される.stderrはできません.
2、次のプログラムは正常に見えますが、カンマ式を使用して初期化します.残念ながらこのプログラムには問題があります.なぜか知っていますか.
参考答案:このプログラムではコンパイルエラー(構文エラー)が発生します.カンマ式は間違いありませんが、初期化や変数宣言ではカンマ式の意味ではありません.この点を区別するには、上記のプログラムを修正するには、カッコを付ける必要があります:int a=(1,2);
3、次のプログラムはどのような出力がありますか.
参考答案:プログラムは4321を出力します.なぜか知っていますか.なぜprintfの戻り値が何なのかを知る必要があります.printf戻り値は、出力される文字数です.
4、次のプログラムは何を出力しますか?
参考答案:プログラムの出力は、浮動小数点数が4バイト、12.5 fがバイナリに変換されたのは、01000001010010000000000億円、16進数が0 x 41480000、10進数が1095237632だったためです.だから、2番目と3番目の出力はみんなもなぜか知っていると信じています.1つ目は、なぜ0が出力されるのか、floatとdoubleのメモリレイアウトを理解する必要があります.以下のようにします. float:1ビットシンボルビット(s)、8ビット指数(e)、23ビット末尾数(m、計32ビット) double:1ビットシンボルビット(s)、11ビット指数(e)、52ビット末尾数(m、計64ビット) 次にprintfはタイプが一致しないため、floatを直接doubleに変換する必要があります.注意してください.12.5のfloatとdoubleのメモリバイナリは全然違います.x 86チップの下で使用される逆バイトシーケンスは、上位バイトと下位ビットが逆であることを忘れないでください.したがって、 float版:0 x 41480000(メモリでは:00 00 48 41) double版:0 x 4029000000000(メモリでは:00 00 00 00 00 00 29 40) 一方、%dの要件は4バイトのintであり、doubleのメモリレイアウトでは、最初の4バイトが00であることがわかり、出力は自然に0になります.この例ではprintfがタイプセキュリティではないことを説明します.これは、C++がcoutのように引用される理由です.
5、次に、クロスコンパイルの件を見てみましょう.次の2つのファイルはコンパイルできますか.もし通過できたら、結果は何ですか?
file1.c int arr[80]; file2.c extern int *arr; int main() { arr[1] = 100; printf("%d/n", arr[1]); return 0; }
参考答案:このプログラムはコンパイルできますが、実行中にエラーが発生します.どうしてですか.なぜなら、別のファイルでextern int*arrを使用して配列を外部に宣言すると、タイプが一致しないため、実際の期待値が得られないからです.したがって、ポインタは実際にその配列を指していない.注意:配列を指すポインタは、配列に等しくありません.変更:extern int arr[].(参考:ISO C言語6.5.4.2節)
6、次のプログラムの出力はいくらですか.なぜか説明します(なお、このプログラムは「b is 20」を出力しない)
参考答案:このプログラムはコンパイル時にwarning:unreachable code at beginning of switch statementが表示される可能性があります.switchに入ると変数bが初期化されると思っていましたが、そうではありません.switch-case文は変数bの初期化を直接スキップするからです.したがって、プログラムはランダムなメモリ値を出力します.
7、次のプログラムはどんな潜在的な危険がありますか?
本題は簡単です.このプログラムの潜在的な問題は、ユーザーが80文字以上の文字を入力すると、配列の境界を越える問題があり、あなたのプログラムはcrashに及ぶ可能性が高いということです.
8、次のプログラムは何を出力しますか?
参考答案:出力がそれぞれ、10,4,11だと思ったら、あなたは間違っています.3番目に間違っています.1番目は10で問題はありません.2番目は4で、問題もありません.32ビットマシンのintが4バイトあるからです.しかし、3つ目はなぜ11ではないのでしょうか.まだ10?なぜなら、sizeofは関数ではなく、i++のタイプのsizeを求めるオペレータであり、プログラムの実行前(コンパイル時)に完全なことができるので、sizeof(i++)は直接4に取って代わられ、実行時にi++という表現はありません.
9、次のプログラムの出力値は何ですか.
参考答案:PrintIntというマクロに問題がある場合は、「言語の曖昧さ」の4番目の例を見てみましょう.ただし、この例の問題はここではありません.この例の出力は:1,8,641000で、実は簡単です.C/C++で、0で始まる数字はすべて8進法です.
10、次のプログラムの出力は何ですか.(決して10ではありません)
本題の出力は100です.どうしてですか.問題はy=y/*pである.さて、私たちはもともとy/(*p)と思っていましたが、スペースと括弧を入れず、結果としてy/*pの/*が注釈の始まりと解釈されました.そして、これも悪夢の始まりです.
11、次の出力は何ですか.
参考答案:本題は簡単ではないのは接頭辞++または接尾辞++で、本題は主に&&||の短絡求値の問題を試験します.ショート評価:(条件1&&条件2)について、「条件1」がfalseの場合、「条件2」の式は無視されます.(条件1||条件2)については、「条件1」がtrueであり、「条件2」の式は無視されます.だから、私はあなたが本題の答えが何なのか知っていると信じています.
12、次のCプログラムは合法ですか.もしそうなら、出力は何ですか?
参考答案:この例は合法的で、出力は以下の通りです.
Hello! how is this? super That is C !
この例は主に別の使い方を示している.次の2つの方法は同じです.
"hello"[2] 2["hello"]
もしあなたが知っているならば:a[i]は実は*(a+i)つまり*(i+a)なので、i[a]と書けば理解しにくいはずです.
13、次のプログラムは何を出力しますか?(仮定:Hello,Worldと入力)
参考答案:この例の出力は「Hello,Wo」で、scanfの「%[^r]」は中から梗塞したものです.文字rに出会って終わりました.
14、次のプログラムは「ビット操作」を使って「5に乗る」操作を完成しようとしていますが、このプログラムにはBUGがあります.何か知っていますか.
問題は、関数FiveTimesの式「t=a<<2+a;」、a<<2というビット操作では加算より優先度が低いので、この式は「t=a<<(2+a)」となり、私たちが望む値が得られません.このプログラムは以下のように修正されます.
1、次のプログラムはhello-std-outを出力するとは限らないが、なぜか知っていますか.
#include <stdio.h>
#include <unistd.h>
int main()
{
while(1)
{
fprintf(stdout,"hello-std-out");
fprintf(stderr,"hello-std-err");
sleep(1);
}
return 0;
}
参考答案:stdoutとstderrは同じデバイス記述子ではありません.stdoutはブロックデバイスであり、stderrはそうではない.ブロックデバイスについては,次のいくつかの場合にのみ入力され,1)リターンに遭遇し,2)バッファ満杯,3)flushが呼び出される.stderrはできません.
2、次のプログラムは正常に見えますが、カンマ式を使用して初期化します.残念ながらこのプログラムには問題があります.なぜか知っていますか.
#include <stdio.h>
int main()
{
int a = 1,2;
printf("a : %d/n",a);
return 0;
}
参考答案:このプログラムではコンパイルエラー(構文エラー)が発生します.カンマ式は間違いありませんが、初期化や変数宣言ではカンマ式の意味ではありません.この点を区別するには、上記のプログラムを修正するには、カッコを付ける必要があります:int a=(1,2);
3、次のプログラムはどのような出力がありますか.
#include <stdio.h>
int main()
{
int i=43;
printf("%d/n",printf("%d",printf("%d",i)));
return 0;
}
参考答案:プログラムは4321を出力します.なぜか知っていますか.なぜprintfの戻り値が何なのかを知る必要があります.printf戻り値は、出力される文字数です.
4、次のプログラムは何を出力しますか?
#include <stdio.h>
int main()
{
float a = 12.5;
printf("%d/n", a);
printf("%d/n", (int)a);
printf("%d/n", *(int *)&a);
return 0;
}
参考答案:プログラムの出力は、浮動小数点数が4バイト、12.5 fがバイナリに変換されたのは、01000001010010000000000億円、16進数が0 x 41480000、10進数が1095237632だったためです.だから、2番目と3番目の出力はみんなもなぜか知っていると信じています.1つ目は、なぜ0が出力されるのか、floatとdoubleのメモリレイアウトを理解する必要があります.以下のようにします.
5、次に、クロスコンパイルの件を見てみましょう.次の2つのファイルはコンパイルできますか.もし通過できたら、結果は何ですか?
file1.c int arr[80]; file2.c extern int *arr; int main() { arr[1] = 100; printf("%d/n", arr[1]); return 0; }
参考答案:このプログラムはコンパイルできますが、実行中にエラーが発生します.どうしてですか.なぜなら、別のファイルでextern int*arrを使用して配列を外部に宣言すると、タイプが一致しないため、実際の期待値が得られないからです.したがって、ポインタは実際にその配列を指していない.注意:配列を指すポインタは、配列に等しくありません.変更:extern int arr[].(参考:ISO C言語6.5.4.2節)
6、次のプログラムの出力はいくらですか.なぜか説明します(なお、このプログラムは「b is 20」を出力しない)
#include <stdio.h>
int main()
{
int a=1;
switch(a)
{
int b=20;
case 1:
printf("b is %d/n",b);
break;
default:
printf("b is %d/n",b);
break;
}
return 0;
}
参考答案:このプログラムはコンパイル時にwarning:unreachable code at beginning of switch statementが表示される可能性があります.switchに入ると変数bが初期化されると思っていましたが、そうではありません.switch-case文は変数bの初期化を直接スキップするからです.したがって、プログラムはランダムなメモリ値を出力します.
7、次のプログラムはどんな潜在的な危険がありますか?
#include <stdio.h>
int main()
{
char str[80];
printf("Enter the string:");
scanf("%s",str);
printf("You entered:%s/n",str);
return 0;
}
本題は簡単です.このプログラムの潜在的な問題は、ユーザーが80文字以上の文字を入力すると、配列の境界を越える問題があり、あなたのプログラムはcrashに及ぶ可能性が高いということです.
8、次のプログラムは何を出力しますか?
#include <stdio.h>
int main()
{
int i;
i = 10;
printf("i : %d/n",i);
printf("sizeof(i++) is: %d/n",sizeof(i++));
printf("i : %d/n",i);
return 0;
}
参考答案:出力がそれぞれ、10,4,11だと思ったら、あなたは間違っています.3番目に間違っています.1番目は10で問題はありません.2番目は4で、問題もありません.32ビットマシンのintが4バイトあるからです.しかし、3つ目はなぜ11ではないのでしょうか.まだ10?なぜなら、sizeofは関数ではなく、i++のタイプのsizeを求めるオペレータであり、プログラムの実行前(コンパイル時)に完全なことができるので、sizeof(i++)は直接4に取って代わられ、実行時にi++という表現はありません.
9、次のプログラムの出力値は何ですか.
#include <stdio.h>
#include <stdlib.h>
#define SIZEOF(arr) (sizeof(arr)/sizeof(arr[0]))
#define PrintInt(expr) printf("%s:%d/n",#expr,(expr))
int main()
{
/* The powers of 10 */
int pot[] = {
0001,
0010,
0100,
1000
};
int i;
for(i=0;i<SIZEOF(pot);i++)
PrintInt(pot[i]);
return 0;
}
参考答案:PrintIntというマクロに問題がある場合は、「言語の曖昧さ」の4番目の例を見てみましょう.ただし、この例の問題はここではありません.この例の出力は:1,8,641000で、実は簡単です.C/C++で、0で始まる数字はすべて8進法です.
10、次のプログラムの出力は何ですか.(決して10ではありません)
#include <stdio.h>
#define PrintInt(expr) printf("%s : %dn",#expr,(expr))
int main()
{
int y = 100;
int *p;
p = malloc(sizeof(int));
*p = 10;
y = y/*p; /*dividing y by *p */;
PrintInt(y);
return 0;
}
本題の出力は100です.どうしてですか.問題はy=y/*pである.さて、私たちはもともとy/(*p)と思っていましたが、スペースと括弧を入れず、結果としてy/*pの/*が注釈の始まりと解釈されました.そして、これも悪夢の始まりです.
11、次の出力は何ですか.
#include <stdio.h>
int main()
{
int i = 6;
if( ((++i < 7) && ( i++/6)) || (++i <= 9))
;
printf("%d/n",i);
return 0;
}
参考答案:本題は簡単ではないのは接頭辞++または接尾辞++で、本題は主に&&||の短絡求値の問題を試験します.ショート評価:(条件1&&条件2)について、「条件1」がfalseの場合、「条件2」の式は無視されます.(条件1||条件2)については、「条件1」がtrueであり、「条件2」の式は無視されます.だから、私はあなたが本題の答えが何なのか知っていると信じています.
12、次のCプログラムは合法ですか.もしそうなら、出力は何ですか?
#include <stdio.h>
int main()
{
int a=3, b = 5;
printf(&a["Ya!Hello! how is this? %s/n"], &b["junk/super"]);
printf(&a["WHAT%c%c%c %c%c %c !/n"], 1["this"],
2["beauty"],0["tool"],0["is"],3["sensitive"],4["CCCCCC"]);
return 0;
}
参考答案:この例は合法的で、出力は以下の通りです.
Hello! how is this? super That is C !
この例は主に別の使い方を示している.次の2つの方法は同じです.
"hello"[2] 2["hello"]
もしあなたが知っているならば:a[i]は実は*(a+i)つまり*(i+a)なので、i[a]と書けば理解しにくいはずです.
13、次のプログラムは何を出力しますか?(仮定:Hello,Worldと入力)
#include <stdio.h>
int main()
{
char dummy[80];
printf("Enter a string:/n");
scanf("%[^r]",dummy);
printf("%s/n",dummy);
return 0;
}
参考答案:この例の出力は「Hello,Wo」で、scanfの「%[^r]」は中から梗塞したものです.文字rに出会って終わりました.
14、次のプログラムは「ビット操作」を使って「5に乗る」操作を完成しようとしていますが、このプログラムにはBUGがあります.何か知っていますか.
#include <stdio.h>
#define PrintInt(expr) printf("%s : %d/n",#expr,(expr))
int FiveTimes(int a)
{
int t;
t = a<<2 + a;
return t;
}
int main()
{
int a = 1, b = 2,c = 3;
PrintInt(FiveTimes(a));
PrintInt(FiveTimes(b));
PrintInt(FiveTimes(c));
return 0;
}
問題は、関数FiveTimesの式「t=a<<2+a;」、a<<2というビット操作では加算より優先度が低いので、この式は「t=a<<(2+a)」となり、私たちが望む値が得られません.このプログラムは以下のように修正されます.
int FiveTimes(int a)
{
int t;
t = (a<<2) + a;
return t;
}