你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

14个C语言的迷题以及答案

[复制链接]
gaosmile 发布时间:2021-1-15 11:27
本文展示了14个C语言的迷题以及答案,代码应该是足够清楚的,而且有相当的一些例子可能是我们日常工作可能会见得到的。通过这些迷题,希望你能更了解C语言。
) V( `+ Z% q5 J
如果你不看答案,不知道是否有把握回答各个谜题?让我们来试试。

( i7 W' I& l7 V! m* z, n
/ k3 b: m( L: h- C- \
1
$ R+ d9 ]9 V6 I" G, ]

& {9 a# O) L8 `
下面的程序并不见得会输出"hello-std-out",你知道为什么吗?

  1. % L% s, P6 B$ A$ P6 p
  2. #include# p" L' v0 z9 h, k
  3. #include
    9 h+ I8 Z# K. `: Z) h" ~
  4. int main()
    $ Y9 ~- F/ L% Z( c
  5. {
    - K/ z7 X" O$ Q$ g) N- m
  6.       while(1)
    ! ^% ^3 _9 P# S% p% k) M+ J( G
  7.       {
    ! v3 @* s! E- p! O- L! H" H
  8.             fprintf(stdout,"hello-std-out");! Q" ~# ~3 J, z$ Z% ]
  9.             fprintf(stderr,"hello-std-err");5 B# T4 c, H' E7 j9 J
  10.             sleep(1);
    ' r' I4 K; l0 Z7 Z( c
  11.       }
    & b! d9 |4 \4 p9 }5 E
  12.       return 0;
    : i: T3 q) V" N2 n6 c0 v0 U( _
  13. }
复制代码

4 Y3 E# Z1 O# N  E  x, P- x) S; E
: e1 Y' V: E7 m9 s$ l
参考答案
stdout和stderr是不同设备描述符。stdout是块设备,stderr则不是。对于块设备,只有当下面几种情况下才会被输入:遇到回车;缓冲区满;flush被调用。而stderr则不会。
; u: T# Z  ^5 d" |
1 e+ U) A) c- K( f4 [+ g
2
6 Y. v' d' V2 q+ G6 c% v
. ~. f5 `5 B% x8 R" W* v
下面的程序看起来是正常的,使用了一个逗号表达式来做初始化。可惜这段程序是有问题的。你知道为什么吗?
  1. : b' ]. A8 K$ p) g( K; G
  2. #include
    0 b! Q% e9 p; T  I) A+ D# k
  3. int main()
    & w" H& n; R* R$ c
  4. {' S7 W. \" f) i0 B
  5.       int a = 1,2;
    ! g9 {% Q/ i. C# M
  6.       printf("a : %d\n",a);
    4 U# l; k( \. X
  7.       return 0;
    9 U7 F- U& l+ o6 N) J! [
  8. }
复制代码

; G3 f$ N, l1 r; u) t  c: V) c: Z" u- _4 G0 }5 f
参考答案
这个程序会得到编译出错(语法出错)。逗号表达式是没错,可是在初始化和变量声明时,逗号并不是逗号表达式的意义。这点要区分,要修改上面这个程序,你需要加上括号:"int a = (1,2);"。
* ?& y. l# P- X7 M7 S
3 ~- }" a# J0 O" a
3
7 A% w3 A* H7 f! g0 s! K/ \4 ?

# |4 ^* G% d. Y2 j0 W5 M  }
下面的程序会有什么样的输出呢?
  1. 8 j: W0 f: i* v! h" M
  2. #include/ ]- p% A/ `4 U, a  p( g
  3. int main()6 c! Y3 x. T( I- v# `
  4. {2 x1 @2 Q+ k( Q7 F6 Z0 y
  5.       int i=43;
    ) ]; m" ~4 i+ p
  6.       printf("%d\n",printf("%d",printf("%d",i)));
    $ O3 V3 p5 F6 k; h/ G& Y8 @3 ^
  7.       return 0;* _3 \/ v9 ^9 N: X% ?
  8. }
复制代码

9 m8 ~/ i$ O5 w( i+ N4 Z* s5 ~: M
参考答案
程序会输出4321,你知道为什么吗?要知道为什么,你需要知道printf的返回值是什么。printf返回值是输出的字符个数。

7 w- Y& {7 S& K, F
7 {: S# A$ b8 w
4  h, ?8 L' }, k5 {& E7 x' \: k

& v" A$ C0 A) E8 s, k! Y7 o
下面的程序会输出什么?
  1. / o* K  W, Z- L/ d& v2 B9 E2 q
  2. #include% _7 b! ~- z& s0 a4 Z$ T
  3. int main()+ P' r! ?0 Q4 Z9 f" h
  4. {1 o0 F: u  K& A2 g+ U& M+ n
  5.       float a = 12.5;
    2 B0 F; h1 L8 j- J5 ?
  6.       printf("%d\n", a);8 M! Z3 f# w( J/ Z
  7.       printf("%d\n", (int)a);
    & c. n& n' e) j
  8.       printf("%d\n", *(int *)&a);& c) m, E$ b0 M: w$ v
  9.       return 0;/ X. N( S- c! r7 l% M. l
  10. }
复制代码

4 w3 ^8 e1 [  O6 \. H$ A) r! R0 b. B
参考答案
该项程序输出:"0 12 1095237632"。
7 ]. T% q" H) \
原因是:浮点数是4个字节,12.5f转成二进制是:01000001010010000000000000000000,十六进制是:0x41480000,十进制是:1095237632。所以,第二和第三个输出相信大家也知道是为什么了。
" l5 N* E% k" D; G3 @! \5 ~
而对于第一个,为什么会输出0,我们需要了解一下float和double的内存布局,如下:
* V( F5 r' ]: \8 @
• float: 1位符号位(s)、8位指数(e),23位尾数(m,共32位)。
• double: 1位符号位(s)、11位指数(e),52位尾数(m,共64位)。
) P) s# j- t/ n
然后,我们还需要了解一下printf由于类型不匹配,所以,会把float直接转成double,注意,12.5的float和double的内存二进制完全不一样。别忘了在x86芯片下使用是的反字节序,高位字节和低位字位要反过来。所以:
• float版:0x41480000 (在内存中是:00 00 48 41)。
( Z' x  t! X5 w" m
• double版:0x4029000000000000 (在内存中是:00 00 00 00 00 00 29 40)。2 r, s; _& \6 }
6 a% r5 X: K& M% }# _, o
而我们的%d要求是一个4字节的int,对于double的内存布局,我们可以看到前四个字节是00,所以输出自然是0了。这个示例向我们说明printf并不是类型安全的,这就是为什么C++要引如cout的原因了。
6 @7 J+ ?) y+ M; ~+ E+ y+ T

2 [; {% O2 A% M6 [7 S* `4 o7 d
5: B5 D* M$ O8 M6 \2 C

3 z  w& c) m! v6 u+ F! z
下面,我们再来看一个交叉编译的事情,下面的两个文件可以编译通过吗?如果可以通过,结果是什么?

  1. 5 ?) k- `: ], D( x
  2. //file1.cint arr[80];
    + C' H6 N. G+ |6 |
  3. //file2.cextern int *arr;
    # e5 g  l8 M6 _  Y/ ]9 n
  4. int main()
    6 ]+ r! _0 P% @1 x8 q
  5. {
    0 s1 j- S% T, U7 F* L, C; r' f
  6.       arr[1] = 100;( ~& C1 T& m, W( [7 g6 e
  7.       printf("%d\n", arr[1]);
    4 Q) q2 ^* g* d( @9 E
  8.       return 0;
    * g) u* f) J  C) y  }/ A
  9. }
复制代码
% N  [8 R/ I3 v& ^1 I2 ]; o( Q
参考答案
该程序可以编译通过,但运行时会出错。为什么呢?原因是,在另一个文件中用 extern int *arr来外部声明一个数组并不能得到实际的期望值,因为他们的类型并不匹配。所以导致指针实际并没有指向那个数组。
* |8 [! Z% @7 j! |" w
注意:一个指向数组的指针,并不等于一个数组。

; [0 D1 R8 P" K" |, y  a
修改:"extern int arr[]"。
2 O9 {. P1 O$ g
# N) I* j2 |" _& m& x4 I: L5 m$ b
60 q0 j. ]( g  g& o' p, t0 A; x
. _( O2 w5 q; F: A
请说出下面的程序输出是多少?并解释为什么?(注意,该程序并不会输出"b is 20")

  1. 5 a7 ~1 I. A; W$ z& N9 j( n) k
  2. #include
    1 I8 E8 \: d! ^, ^2 t" ?3 N
  3. int main()
    0 I5 \* n* |7 o% v  }; F* b
  4. {( z7 w" N* I2 W: w: n
  5.       int a=1;
    9 N" G) a9 [  {7 H. f
  6.       switch(a)- ^* N8 I8 U4 b5 h" L& S
  7.       {0 }# F' c8 x0 C
  8.             int b=20;+ J+ M* A' c! S3 S
  9.             case 1:
    * `' B( k. {) U, Q
  10.                   printf("b is %d\n",b);/ J! o- @  b& w
  11.                   break;
    ' m9 J; I/ f. C" p" L- i/ }- S2 `
  12.             default:% W. i* n! v$ |. A2 s: t
  13.                   printf("b is %d\n",b);3 K2 v4 i5 R- M0 o# u7 [1 k
  14.             break;" c+ `5 O# _7 X5 m4 U) S3 [& T
  15.       }" o; _2 `: P. l$ [3 S. T
  16.       return 0;' _9 U, [% u& d* H: R  Z
  17. }
复制代码
9 M$ ^, t2 R3 l+ @2 g
参考答案
该程序在编译时,可能会出现一条warning: unreachable code at beginning of switch statement。我们以为进入switch后,变量b会被初始化,其实并不然,因为switch-case语句会把变量b的初始化直接就跳过了。所以,程序会输出一个随机的内存值。

( Z3 S. c1 y9 R5 d; e" S& @, E

7 v; m) E; ~8 N' d0 c' q
72 D* E2 H- U& f3 l0 |+ o! H
' x5 Q9 K' w  X
请问下面的程序会有什么潜在的危险?

  1. ! e" C# F8 c& |: W$ ?, {& g- Y
  2. #include
    $ k- e/ O4 ~* e5 B5 m% e
  3. int main()/ c: A: j  i3 o! c; ]! {$ _. H/ G
  4. {8 ^* \% L+ s3 X+ o
  5.       char str[80];) ^8 k8 y9 D( N3 ]7 D
  6.       printf("Enter the string:");5 W4 N$ H& h( E- O% o4 w
  7.       scanf("%s",str);- Q7 T- ^3 g; Q; Q$ w" _; Q0 F+ y# a. x
  8.       printf("You entered:%s\n",str);
    5 k7 D. ?; X1 o  K" Y- `
  9.       return 0;
    : E( S  p0 j8 t2 h7 Q! `6 I# i+ m
  10. }
复制代码
: B2 g8 N: @- k; [! V
参考答案
本题很简单了。这个程序的潜在问题是,如果用户输入了超过80个长度的字符,那么就会有数组越界的问题了,你的程序很有可能会crash了。

1 k" o8 s) W% i, E: c
7 O. Q, [6 v* D' T+ w2 z+ V
8
: k4 g& @, ~3 U5 d1 Z% E5 J

) f2 |# H' G9 V6 l" F/ x/ M
请问下面的程序输出什么?

  1. ; `. B- G+ b# T
  2. #include0 o) l! o& I6 R& X
  3. int main()
    ; q# x; t4 K0 i
  4. {
    5 h3 A) |8 P( e; H/ H* X
  5.       int i;
    - m; p% Q% e7 h4 F) D- J4 u6 ?( [
  6.       i = 10;( m+ `- B1 F" V9 I8 n
  7.       printf("i : %d\n",i);8 I7 r) K2 A9 r0 G/ a
  8.       printf("sizeof(i++) is: %d\n",sizeof(i++));  s2 F$ |$ F8 W3 {
  9.       printf("i : %d\n",i);; y7 c' l3 h0 `& C" s
  10.       return 0;
    + W. Y; [2 i0 @  \
  11. }
复制代码

: L) Q: l/ d, @7 g: w% Y
参考答案
如果你觉得输出分别是:10,4,11。那么你就错了。
& G4 b) z: V4 L4 X! a( f
错在了第三个,第一个是10没有什么问题,第二个是4,也没有什么问题,因为是32位机上一个int有4个字节。但是第三个为什么输出的不是11呢?居然还是10?原因是,sizeof不是一个函数,是一个操作符,其求i++的类型的size,这是一件可以在程序运行前(编译时)完全的事情,所以,sizeof(i++)直接就被4给取代了,在运行时也就不会有了i++这个表达式。
- X. u5 ]) P- d0 I; G( W8 e
9 ~* K) v! {* j+ E
9
. p0 Y+ @( c! N0 ]8 ~4 Z# x9 |

4 p) l! \& f8 S
请问下面的程序的输出值是什么?

  1. $ i/ o5 X/ x# o& b( ?- U- z5 x
  2. #include
    0 F/ G; z2 ]# V$ d& \$ ^
  3. #include6 |0 x3 D0 V8 J  H* o# {
  4. 3 O3 T# T/ ~* r+ L! G
  5. #define SIZEOF(arr) (sizeof(arr)/sizeof(arr[0]))
    ! d; z+ M! U  w
  6. #define PrintInt(expr) printf("%s:%d\n",#expr,(expr))$ [' ]7 b3 @8 X# l4 \
  7. 0 s# n: j0 _5 ?; Z) h: `4 l
  8. int main()" I) V% \+ f2 l/ L# w- ~5 i
  9. {# a4 l/ R9 `4 i& t+ }9 S. y, F% Z
  10. /* The powers of 10 */
    3 M- ]9 Q0 F4 |. g' m# X
  11.       int pot[] = {
    & Z7 [$ P" o9 J& Y3 E8 g! k2 ]- c: O5 I
  12.       0001,6 v3 k% e+ h- o
  13.       0010,( T- y/ Q" `/ p4 |
  14.       0100,6 z( s6 ]6 q* q: q( ~  g' {
  15.       1000) ~! W" T% m0 X. H" S
  16.       };7 z3 A# e, |! I  ^1 i  V9 [
  17. * }6 p' h! h5 f  y
  18.       int i;6 i# X6 S6 d2 J7 w/ |
  19.       for(i=0;i<SIZEOF(pot);i++)PrintInt(pot[i]);
    3 N) I" Y+ t7 C& Z+ s
  20.       return 0;! P$ s2 r! Z0 `, L$ d0 O
  21. }
复制代码

8 ]; N! {9 n& M# v4 V
参考答案
如果你对于PrintInt这个宏有问题的话,可以去看一看资料。不过,本例的问题不在这里,本例的输出会是:1,8,64,1000。其实很简单了,在C/C++中,以0开头的数字都是八进制的。

: h: o1 x* v4 q, @

: P4 I8 A) p, `8 Q
104 v# v+ S+ X' w* Z; B" i& i

( C( Y& l6 u1 |8 e+ ?2 _# u" T
请问下面的程序输出是什么?(绝对不是10)

  1. 8 h1 R7 _: k( ?2 s2 Z+ F* i, V8 p
  2. #include0 F) g6 `/ ]* {0 n! x' a
  3. #define PrintInt(expr) printf("%s : %dn",#expr,(expr))
    7 J) @4 H* Y# K% K9 V! p" n
  4. int main()3 F- |& G+ ?% O8 G6 T6 _% P
  5. {+ ?  U( I0 I9 y! x7 u
  6.       int y = 100;" N. a& J% T+ Q+ S* {
  7.       int *p;0 e6 _& l( o2 ]9 K9 D1 ~. W/ w
  8.       p = malloc(sizeof(int));5 f* `! L# P3 J
  9.       *p = 10;! `; a$ F0 a! z: r1 M/ h
  10.       y = y/*p; /*dividing y by *p */;6 O- N6 F/ H" h/ Q: w8 @% p$ ^
  11.       PrintInt(y);% S5 w' F, h8 D+ [
  12.       return 0;
    ' q+ D, M0 m8 N
  13. }
复制代码

$ U9 {$ m  B) m. K% S
参考答案
本题输出的是100。为什么呢?问题就出在"y = y/*p;"上了,我们本来想的是"y / (*p)",然而,我们没有加入空格和括号,结果"y/*p"中的"/*"被解释成了注释的开始。于是,这也是整个恶梦的开始。

, Z8 @+ [* q; ?2 G, n# M" v/ P% P

2 o: U2 D7 T3 v$ |0 A- L! g4 x
11' ~; n/ A" ?# X) v* d. k

* C) g- t; W2 e( {
下面的输出是什么?
  1. 1 ~5 M7 w& M% L! s3 Q  m
  2. #include% E0 U5 e1 T/ `) G1 X" g8 l
  3. int main()7 a+ H9 Y! P3 }- S
  4. {$ C" E) W$ E* C, v; n' J
  5.       int i = 6;
    # H0 ?2 v/ p5 ~7 c$ w, ^
  6.       if( ((++i < 7) && ( i++/6)) || (++i <= 9));
    ' w+ I* E# e, X
  7.       printf("%d\n",i);
    ( p0 C. Y5 O) u/ F( Z8 u( P
  8.       return 0;$ ^, _4 ], u+ x  A+ H4 I, Y
  9. }
复制代码
7 _- r. Z1 B! U8 X  S% Z
参考答案
本题并不简单的是考前缀++或反缀++,本题主要考的是&&和||的短路求值的问题。
5 x- ]# d* X! {) i
所谓短路求值:对于(条件1 && 条件2),如果“条件1”是false,那“条件2”的表达式会被忽略了。对于(条件1 || 条件2),如果“条件1”为true,而“条件2”的表达式则被忽略了。

7 F5 T2 }2 \) q4 b# f4 C
所以,我相信你会知道本题的答案是什么了。

3 F3 E9 G8 X! `# C8 z* d( _  S
3 Q9 G& Z0 \6 h4 }
12; A- N2 B$ q8 }9 n- t

! d" S9 p6 m" Y
下面的C程序是合法的吗?如果是,那么输出是什么?

  1. ' k% W/ H5 N5 Q# }1 t. u6 w
  2. #include/ @# T" d% u7 M, d! y* c- M8 a- j
  3. int main()% T' ~* y5 d- u; j1 J7 }! {6 z
  4. {: ?' e: i! m1 a: \3 D4 r2 Z
  5.       int a=3, b = 5;& ^0 K6 X1 Y$ g+ E2 E" M! J5 k% E
  6.       printf(&a["Ya!Hello! how is this? %s\n"], &b["junk/super"]);9 p8 x" i5 z' o: g1 S" x2 R* |
  7.       printf(&a["WHAT%c%c%c %c%c %c !\n"], 1["this"],2["beauty"],0["tool"],0["is"],3["sensitive"],4["CCCCCC"]);
    , Z1 [: z; a+ M8 R' u
  8.       return 0;6 O8 |# y& ]/ b$ {
  9. }
复制代码

4 v3 J9 z% ]9 W" v2 F/ \, w+ `' o
参考答案
本例是合法的,输出为:"Hello! how is this? super That is C !"
& Q; s1 S# r  K
本例主要展示了一种另类的用法。下面的两种用法是相同的:
• "hello"[2]
• 2["hello"]

/ R6 S& Q" y9 `/ n" S. \
如果你知道:a 其实就是 *(a+i)也就是 *(i+a),所以如果写成 i[a] 应该也不难理解了。

0 v$ V2 \+ M& j7 t% k& Y: s- u/ K
; \" T! A/ g) [% g& c
134 B9 P/ G1 \0 ~; G  _" J! P
7 N5 D6 b# s: G: K: e/ R
请问下面的程序输出什么?(假设:输入"Hello, World")

  1. * _. C2 ?8 [+ k) Q
  2. #include
    : L* ^% f3 K$ H4 r  T
  3. int main()% b5 D/ m1 v. p/ i+ u8 a% M
  4. {
    0 J; N5 A1 n$ {3 v" X
  5.       char dummy[80];
    . t9 S/ C4 \7 u( z
  6.       printf("Enter a string:\n");* h8 N$ J1 T* O2 b/ ~
  7.       scanf("%[^r]",dummy);% ~4 e# T* B4 _3 X& ^
  8.       printf("%s\n",dummy);6 g. p, j# H' e" h- G* h6 n
  9.       return 0;
    4 J& @! i* e+ P
  10. }
复制代码
$ m, L4 T/ r% P) \
参考答案
本例的输出是"Hello, Wo"。scanf中的"%[^r]"是从中作梗的东西,意思是遇到字符r就结束了。

: ], O: |& e1 j( L) X' P% J
' Z, C0 [+ t7 v( a+ ]
146 m% f) p9 V( w. n8 S# J
: U  q% h& G; Q4 I
下面的程序试图使用"位操作"来完成"乘5"的操作,不过这个程序中有个BUG,你知道是什么吗?
  1. 3 Q+ w$ {0 A0 C) r4 U
  2. #include6 G4 ?' \% D7 N. n
  3. #define PrintInt(expr) printf("%s : %d\n",#expr,(expr))# \" O5 x. _& q* o( t
  4. int FiveTimes(int a)
    2 z& v( l; l! ?- }8 L8 T
  5. {% _9 J8 z$ D4 p1 q- H
  6.       int t;( [7 b- N( l! z) c4 ?* J" A
  7.       t = a<<2 + a;2 p2 c: t. F- r# Y
  8.       return t;1 e; y' Q0 W# {) h
  9. }1 w. B8 B7 I' ?3 r  A+ L5 N
  10. int main()* k; p& s4 _, d% d0 n
  11. {
    6 z! O6 i' Y# Q2 A6 C
  12.       int a = 1, b = 2,c = 3;: n7 n( {+ m1 W' f. Y4 p5 \' z6 q
  13.       PrintInt(FiveTimes(a));! Y5 c, V5 y7 P
  14.       PrintInt(FiveTimes(b));
    4 V/ R. T( A) n# N( a
  15.       PrintInt(FiveTimes(c));) {9 M: }, |" F' }1 U: k7 R5 l1 p
  16.       return 0;5 N5 T! H3 T+ n" X
  17. }
复制代码
: N7 A5 Q+ M9 H6 K# ?0 `5 T
参考答案
本题的问题在于函数FiveTimes中的表达式"t = a<<2 + a;"。对于a<<2这个位操作,优先级要比加法要低,所以这个表达式就成了"t = a << (2+a)",于是我们就得不到我们想要的值。

; T7 d' m, F* M
该程序修正如下:

  1. % |1 C5 |2 l3 V% x7 _7 r3 H% X
  2. int FiveTimes(int a)
      }* s* B6 M3 G% X7 [, M; W
  3. {
    2 n8 Q! k5 I0 @+ @( h/ ^. c3 l
  4.       int t;
    ( `$ X# H* s9 L1 `& C8 K; O
  5.       t = (a<<2) + a;, c8 U; W! Y' t1 J2 f3 I
  6.       return t;
    9 s, _3 s( {8 [5 u# l9 v% U: X* ?
  7. }
复制代码
% I5 B* z6 h  d. |" m1 R# {+ k4 ~, g
赞 收藏 评论1 发布时间:2021-1-15 11:27

举报

1个回答
goyhuan 回答时间:2021-1-15 11:51:40
长知识了

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版