14のC言語の迷題はhttp://blog.csdn.net/haoel/archive/2009/06/01/4231029.aspx


この文章「C言語のパズル」は14のC言語のパズルと答えを示しています.コードは十分にはっきりしているはずです.そして、私たちの日常の仕事で会える可能性があると信じています.これらの謎を通して、C言語をもっと理解してほしい.もしあなたが答えを見なければ、それぞれのパズルに答える自信がありますか?やってみましょう.
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のメモリレイアウトを理解する必要があります.以下のようにします.
  • 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」を出力しない)
    #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;
    
    
    
    }