您的位置:首页 > 其它

那些年,做错的C语法题

2014-03-06 09:07 134 查看
语法题目考察的比较集中,基本上包括以下几个方面:

宏定义和预处理

结构体、功用体对齐、长度

sizeof/typedef

变量类型转换

指针运算

关键字

运算符优先级

语法解析


一、宏定义和预处理

1、写出下列代码的运行结果:

1

2

3

4

5

6

7

8

9

10

11

12

13

14
#include
<stdio.h>


#define
STRCPY(a, b) strcpy(a ## _p, #b)


int
main()


{


char
var1_p[20];


char
var2_p[30];


strcpy
(var1_p,
"aaaa"
;


strcpy
(var2_p,
"bbbb"
;


STRCPY(var1,
var2);


STRCPY(var2,
var1);


printf
(
"var1
= %s/n"
,
var1_p);


printf
(
"var2
= %s/n"
,
var2_p);


return
0;


}

答:var1 = var2/nvar2 = var1/n

析:#为字符串化操作符,讲锁连接的部分转化为一个字符串,##为字符串连接符,将两个字符串连接成一个字符串,均在预处理时完成字符串的替换。仔细点,应该错不了。

2、写出下列代码的运行结果:

1

2

3

4

5

6

7

8

9

10
#include
<stdio.h>


#define
f(a,b) a##b


#define
g(a) #a


#define
h(a) g(a)


int
main()


{


printf
(
"%sn"
,
h(f(1,2)));


printf
(
"%sn"
,
g(f(1,2)));


return
0;


}

答:12和f(1,2)。

析:本题考察字符串化操作符#得作用得执行过程,以及宏定义替换的次序。如果该宏为带#号的宏定义,则直接替换字符串,无需再嵌套替换,如果该宏不是带#的宏,则先替换括号内部的宏定义,然后替换外部的。

3、定义一个宏,求一个结构体struct中某个变量相对于struct的偏移量

1
#define
OFFSET(struct, member) ((unsignedint)&((struct *)0)->member)


二、指针运算

1、写出输出结果:

1

2

3

4

5

6

7

8

9

10

11

12

13

14
int
main()


{


int
a[3];


a[0]
= 0;


a[1]
= 1;


a[2]
= 2;


int
*p,
*q;


p
= a;


q
= &a[2];


int
c
= a[q - p];


printf
(
"value
c = %d/n"
,
c++);


printf
(
"value
c = %d/n"
,
c);


return
0;


}

答:value c =2/nvalue c=3/n

析:此处q-p=2,容易错,地址相减得除以类型,表面上差了8,实际上差了2。不同类型的地址,比如char *p,额int *p,p-q不能操作,报错。

2、写出下列函数运行结果:

1

2

3

4

5

6

7
#incude
<stdio.h>


void
main()


{


int
a[5]={1,2,3,4,5};


int
*ptr=(
int
*)(&a+1);


printf
(
"%d,%d"
,*(a+1),*(ptr-1));


}

答:结果为2,5

3、假如我们的a的地址是:0Xbfe2e100, 而且是32位机,那么这个程序会输出什么?

1

2

3

4

5

6

7

8

9

10
#include
<stdio.h>


int
main()


{


int
a[5];


printf
(
"%xn"
,
a);


printf
(
"%xn"
,
a+1);


printf
(
"%xn"
,
&a);


printf
(
"%xn"
,
&a+1);


return
0;


}

结果:0Xbfe2e100,0Xbfe2e104,0Xbfe2e100,0Xbfe2e114。

分析:分清除哪个表示数组结构,哪个表示数组元素,a表示第一个元素的地址,&a表示数组结构的地址。


三、关键字

1、一个指向有10个整型数数组的指针(Apointertoanarrayof10integers)

一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer as an argument and returns an integer)

答:int (*a)[10];int (*fn)(int);

2、const关键字的作用:

constinta;

intconsta;

constint*a;

int*consta;

intconst*aconst;

答:const一直理解的和初学者一样,什么东西被const修饰了,就只读了,无论你修饰的是变量、返回值或者指针。上面分别代表:

整形常量a,a的值只读;

整形常量a,a的值只读;

整形常量指针a,*a的值只读,a可以修改;

整形常量指针a,a的值只读,*a可以修改;

整形常量指针a,a的值只读,*a也只读;

3、写出打印结果:

1

2

3

4

5

6

7

8

9

10

11

12
char
str1[]
=
"abc"
;


char
str2[]
=
"abc"
;


const
char
str3[]
=
"abc"
;


const
char
str4[]
=
"abc"
;


const
char
*str5
=
"abc"
;


const
char
*str6
=
"abc"
;


char
*str7
=
"abc"
;


char
*str8
=
"abc"
;


cout
<< ( str1 == str2 ) << endl;


cout
<< ( str3 == str4 ) << endl;


cout
<< ( str5 == str6 ) << endl;


cout
<< ( str7 == str8 ) << endl;

答:0 0 1 1。

析:虽然都是常量,但是数组有空间,指针没空间。

4、volatile关键字什么用处?

答:volatile关键字修饰变量,提示编译器该变量是“易变”的,在执行与该变量有关的操作时,需要从变量中取值,而不要仅仅从寄存器中取,常用的情况有,状态寄存器变量、并发共享变量等等。


五、类型强制转换

1、下列代码输出是:

1

2

3

4

5

6

7

8

9

10

11

12
#include
<stdio.h>


void
foo(
void
)


{


unsigned
int
a
= 6;


int
b
= -20;


(a+b
> 6)?
puts
(
">
6"
)
:
puts
(
"<=
6"
);


}


int
main()


{


foo();


return
0;


}

答:>6。

析:主要考察不同类型的变量在一块运行的转化原则:有符号要向无符号的方向转化。因此>6。

2、下列操作没有任何打印,原因?

#include <stdio.h>

#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))

int array[] = {23,34,12,17,204,99,16};

int main()

{

int d;

for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)

printf("%dn",array[d+1]);

return 0;

}

答:由于TOTAL_ELEMENTS得出结果后为unsignedint类型,与-1比较时,将-1转化为无符号整形,也即0xFFFFFFFF,不满足条件退出。


六、优先级与左值

1、写出结果

1

2

3

4

5

6

7

8
#include
<stdio.h>


int
main()


{


int
a
= 5, b = 7, c;


c
= a+++b;


printf
(
"a=%d,b=%d,c=%dn"
,a,b,c);


return
0;


}

答:a=6,b=7,c=12。

析:这个题目考察语法解析。表面上可以理解为a++ + b,也可以理解为a+ ++b,因为编译器解析关键字是从左向右的,尽量包含更多的字符组成关键字,称为“贪心法”或者“大嘴法”。

2、A、B、C、D的运算结果分别是:

1

2

3

4

5
int
a
= 4;


(A)
a += (a++);


(B)
a += (++a) ;


(C)
(a++) += a;


(D)
(++a) += (a++);

答:前两个9,10没问题,后两个gcc报错左值问题。但网上有人说D位11

析:本题考察左值运算,即等号左面的不能是一个数,可以是变量。

3、写出运算结果:

1

2

3

4

5

6

7

8

9

10

11
#include
<stdio.h>


#define
SQUARE(a) ((a)*(a))


int
main(
void
)


{


int
a=5;


int
b1,b2;


b1
= SQUARE(a++);


b2
= SQUARE(++a);


printf
(
"b1=%d,
b2=%dn"
,b1,b2);


return
0;


}

答:25,81。

析:相当于b1=((a++)*(a++)),b2=((++a)*(++a))。编译器编译时,a++先用再加(所为先用再加,应该是=后面的部分),而++a,是先加再用。

4、写出结果

1

2

3

4

5

6

7
int
main()


{


int
i
= 6;


if
(
((++i < 7) && ( i++/6)) || (++i <= 9));


printf
(
"%dn"
,i);


return
0;


}

答:8

分析:本题目考察&&短路径求解问题,所为短路求值:对于(条件1 && 条件2),如果“条件1”是false,那“条件2”的表达式会被忽略了。对于(条件1 || 条件2),如果“条件1”为true,而“条件2”的表达式则被忽略了。

5、写出程序运行结果:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20
#include<stdio.h>


int
f(
int
n)


{


return
++n;


}


int
g(
int
*n)


{


return
++*n;


}


main
()


{


int
n=10;


int
k=0;


k=f(n);


printf
(
"k
is: %dn"
,
k);


printf
(
"n
is: %dn"
,
n);


k=g(&n);


printf
(
"k
is: %dn"
,
k++);


printf
(
"n
is: %dn"
,
n++);


}

答:11,10,11,11。


七、类型长度

1、下列代码执行结果:

1

2

3

4
typedef
union {long i; int k[5]; char c;}
DATE
;


struct
data { int cat;
DATE
cow;
double dog;} too;


DATE
max;


printf(
"%d"
,sizeof(struct
date
)+sizeof(max));

答:32为系统52,64位系统64.

分析:关于对齐,32位默认4byte对齐,64位默认8byte对齐,或者通过#pragma pack(N)来实现执行对齐。union共享功用体最长的空间,而struct是各成员空间相加。

2、下列代码运行结果:

1

2

3

4

5

6

7

8
#include
<stdio.h>


int
main()


{


int
i
= 1;


sizeof
(i++);


printf
(
"%dn"
,
i);


return
0;


}

答:1

分析:正因为sizeof是编译期求值的,所以如果它跟着表达式,那么表达式是不被计算的,只是根本表达式的类型得到它占用的空间。


八、其他

1、一语句实现x是否为2的若干次幂的判断(32位系统)

1
x|(x-1)=0xFFFFFFFF?
puts
(
"true"
):
puts
(
"false"
);

转载地址:http://www.kuqin.com/shuoit/20140104/337415.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: