文章大部分内容来源网络(伪原创,从网上下载的题目)
考查一个初级嵌入式系统开发人员的C基本功,附有答案。题目由资深嵌入式系统专家拟定,目的是考查入门级的嵌入式软件开发人员 。Gavin Shaw提供详细解答
.
编者按:非常基本关于C语言的问题,一个信息类(计算机,资讯工程,电子工程, 通信工程)专业的本科毕业生应该达到的水平。题目不难,全部都能快速地答完,当然也需要一定的知识储备。
对于大多数人,我们预期你可能答错 3) 4) 15)题,所以答错3道以内的,我们认为你很棒
答错5道题以内,我们认为你还不错(你还可能答错第9题)
如果你有6道以上的题目不能答对,基本上我们都不好说什么了…约定:
下面的测试题中,认为所有必须的头文件都已经正确的包含了
数据类型
char 一个字节 1 byte
int 两个字节 2 byte (16位系统,认为整型是2个字节)
long int 四个字节 4 byte
float 四个字节4 byet
double 八个字节 8 byte
long double 十个字节 10 byte
pointer 两个字节 2 byte(注意,16位系统,地址总线只有16位)
第1题: 考查对volatile关键字的认识
#include<setjmp.h>
static jmp_buf buf;
main()
{
volatile int b;
b =3;
if(setjmp(buf)!=0)
{
printf("%d ", b);
exit(0);
}
b=5;
longjmp(buf , 1);
}
请问,这段程序的输出是
(a) 3
(b) 5
(c) 0
(d) 以上均不是
知识补充:
与刺激的abort()和exit()相比,goto语句看起来是处理异常的更可行方案。不幸的是,goto是本地的:它只能跳到所在函数内部的标号上,而不能将控制权转移到所在程序的任意地点(当然,除非你的所有代码都在main体中)。
为了解决这个限制,C函数库提供了setjmp()和longjmp()函数,它们分别承担非局部标号和goto作用。头文件<setjmp.h>申明了这些函数及同时所需的jmp_buf数据类型。
原理非常简单:
1.setjmp(j)设置“jump”点,用正确的程序上下文填充jmp_buf对象j。这个上下文包括程序存放位置、栈和框架指针,其它重要的寄存器和内存数据。当初始化完jump的上下文,setjmp()返回0值。
2. 以后调用longjmp(j,r)的效果就是一个非局部的goto或“长跳转”到由j描述的上下文处(也就是到那原来设置j的setjmp()处)。当作为长跳转的目标而被调用时,setjmp()返回r或1(如果r设为0的话)。(记住,setjmp()不能在这种情况时返回0。)
通过有两类返回值,setjmp()让你知道它正在被怎么使用。当设置j时,setjmp()如你期望地执行;但当作为长跳转的目标时,setjmp()就从外面“唤醒”它的上下文。你可以用longjmp()来终止异常,用setjmp()标记相应的异常处理程序。
——百度百科
个人简单理解(setjmp):
setjmp(j)
相当于跳转的目标行(把它想象成goto语句的跳转行LOOP
),第一次运行时返回0,longjmp(j,r)
相当于goto LOOP
,即跳转到j
被设置的位置,同时让setjmp(j)
返回值变为r(如果r填0,则返回1,总之只有在初始化时才返回0)。
我的解答
偷偷编译运行了一下,发现不管加不加volatile,都是返回5,(选b),那这是考什么呢?
参考答案
第1题: (b)
volatile字面意思是易于挥发的。这个关键字来描述一个变量时,意味着 给该变量赋值(写入)之后,马上再读取,写入的值与读取的值可能不一样,所以说它"容易挥发"的。
这是因为这个变量可能一个寄存器,直接与外部设备相连,你写入之后,该寄存器也有可能被外部设备的写操作所改变;或者,该变量被一个中断程序,或另一个进程改变了.
volatile 不会被编译器优化影响,在longjump 后,它的值 是后面假定的变量值,b最后的值是5,所以5被打印出来.
第2题:考查类型转换
main()
{
struct node
{
int a;
int b;
int c;
};
struct node s= { 3, 5,6 };
struct node *pt = &s;
printf("%d" , *(int*)pt);
}
这段程序的输出是:
(a) 3
(b) 5
(c) 6
(d) 7
我的解答
这个简单,选a,*(int*)pt
为结构体第一个整型元素。
参考答案
第2题: (a)
结构题的成员在内存中的地址是按照他们定义的位置顺序依次增长的。如果一个结构体的指针被看成它的第一个成员的指针,那么该指针的确指向第一个成员
第3题:考查递归调用
int foo ( int x , int n)
{
int val;
val =1;
if (n>0)
{
if (n%2 == 1) val = val *x;
val = val * foo(x*x , n/2);
}
return val;
}
这段代码对x和n完成什么样的功能(操作)?
(a) x^n (x的n次幂)
(b) x*n(x与n的乘积)
(c) n^x(n的x次幂)
(d) 以上均不是
我的解答
原文作者说第三题容易答错,那我得用心了。
这道题的作者脑洞真大,不过这种题最简单的方法就是直接设值求解,设x=2
,n=5
,最后推得结果为32
,所以结果选(a)
参考答案
第3题: (a)
此题目较难.
这个程序的非递归版本int what ( int x , int n) { int val; int product; product =1; val =x; while(n>0) { if (n%2 == 1) product = product*val; /*如果是奇数次幂, x(val) 要先乘上一次,; 偶数次幂,最后返回时才会到这里 乘以1*/ val = val* val; n = n/2; } return product; } /* 用二元复乘策略 */ 算法描述 (while n>0) { if next most significant binary digit of n( power) is one then multiply accumulated product by current val , reduce n(power) sequence by a factor of two using integer division . get next val by multiply current value of itself }
外国人写的解答?好像是诶。。。
第4题:考查指针,这道题只适合于那些特别细心且对指针和数组有深入理解的人
main()
{
int a[5] = {1,2,3,4,5};
int *ptr = (int*)(&a+1);
printf("%d %d" , *(a+1), *(ptr-1) );
}
这段程序的输出是:
(a) 2 2
(b) 2 1
(c) 2 5
(d) 以上均不是
我的解答(错得离谱!!!)
又是一道易错题?让我瞧瞧
a
是数组的首地址,那&a
是啥?指向地址(指针)的指针?ptr
指向&a+1
,那ptr-1
就应该指向&a
了吧,也就是说*(ptr-1)=a
? a
可是一个地址,所以printf
里第二个整型应该是个地址,答案选(d)。
参考答案
第4题: (c)
a的类型是一个整型数组,它有5个成员
&a的类型是一个整型数组的指针
所以&a + 1指向的地方等同于 a[6]
所以*(a+1) 等同于a[1]
ptr等同 a[6], ptr-1就等同与a[5]
第5题:考查多维数组与指针
void foo(int [][3] );
main()
{
int a [3][3]= { { 1,2,3} , { 4,5,6},{7,8,9}};
foo(a);
printf("%d" , a[2][1]);
}
void foo( int b[][3])
{
++ b;
b[1][1] =9;
}
这段程序的输出是:
(a) 8
(b) 9
(c) 7
(d)以上均不对
我的解答
这题简单!foo
函数里++b
后,b[1][1]
对应原来的b[2][1]
,所以结果选(b)。
参考答案
第5题: (b)
题目自身就给了足够的提示
b[0][0] = 4
b[1][0] = 7
第6题目:考查逗号表达式
main()
{
int a, b,c, d;
a=3;
b=5;
c=a,b;
d=(a,b);
printf("c=%d" ,c);
printf("d=%d" ,d);
}
这段程序的输出是:
(a) c=3 d=3
(b) c=5 d=3
(c) c=3 d=5
(d) c=5 d=5
我的解答(答案对了,但理解不全!)
c=a,b;
可不是逗号表达式,答案选(c)。
参考答案
第6题: (c)
考查逗号表达式,逗号表达式的优先级是很低的,比 赋值(=)的优先级 低. 逗号表达式的值就是最后一个元素的值
逗号表达式的还有一个作用就是分割函数的参数列表…
E1, E2, …, En
上面这个表示式的左右是,E1, E2,… En的值被分别计算出来,En计算出来的结构赋给整个逗号表达式
c=a,b; /*yields c=a */
d=(a,b); /* d =b */
第7题:考查指针数组
main()
{
int a[][3] = { 1,2,3 ,4,5,6};
int (*ptr)[3] =a;
printf("%d %d " ,(*ptr)[1], (*ptr)[2] );
++ptr;
printf("%d %d" ,(*ptr)[1], (*ptr)[2] );
}
这段程序的输出是:
(a) 2 3 5 6
(b) 2 3 4 5
(c) 4 5 0 0
(d) 以上均不对
我的解答
(*ptr)[3]
是数组指针,数组长度为3,由于ptr
指向a
,所以(*ptr)[0]=a[0][0]
,(*ptr)[1]=a[0][1]
,(*ptr)[2]=a[0][2]
,
++ptr
后,(*ptr)[0]=a[1][0]
,(*ptr)[1]=a[1][1]
,(*ptr)[2]=a[1][2]
,结果选(a)。
参考答案
第7题: (a)
ptr是一个数组的指针,该数组有3个int成员