c/c++笔试题(2)(转载的)
1.尽管不像非嵌入式计算机那么常见,嵌入式系统还是有从堆(heap)中动态分配内存的过程的。那么嵌入式系统中,动态分配内存可能发生的问题是什么?
这里,我期望应试者能提到内存碎片,碎片收集的问题,变量的持行时间等等。这个主题已经在ESP杂志中被广泛地讨论过了(主要是P.J.Plauger, 他的解释远远超过我这里能提到的任何解释),所有回过头看一下这些杂志吧!让应试者进入一种虚假的安全感觉后,我拿出这么一个小节目:下面的代码片段的输出是什么,为什么?
char *ptr;
if ((ptr = (char *)malloc(0)) == NULL)
puts("Got a null pointer");
else
puts("Got a valid pointer");
这是一个有趣的问题。最近在我的一个同事不经意把0值传给了函数malloc,得到了一个合法的指针之后,我才想到这个问题。这就是上面的代码,该代码的输出是“Got a valid pointer”。我用这个来开始讨论这样的一问题,看看被面试者是否想到库例程这样做是正确。得到正确的答案固然重要,但解决问题的方法和你做决定的基本原理更重要些。
Typedef
2. Typedef在C语言中频繁用以声明一个已经存在的数据类型的同义字。也可以用预处理器做类似的事。例如,思考一下下面的例子:
#define dPS struct s *
typedef struct s * tPS;
以上两种情况的意图都是要定义dPS 和 tPS 作为一个指向结构s指针。哪种方法更好呢?(如果有的话)为什么?
这是一个非常微妙的问题,任何人答对这个问题(正当的原因)是应当被恭喜的。答案是:typedef更好。思考下面的例子:
dPS p1,p2;
tPS p3,p4;
第一个扩展为
struct s * p1, p2;
上面的代码定义p1为一个指向结构的指,p2为一个实际的结构,这也许不是你想要的。第二个例子正确地定义了p3 和p4 两个指针。
晦涩的语法
3.C语言同意一些令人震惊的结构,下面的结构是合法的吗,如果是它做些什么?
int a = 5, b = 7, c;
c = a+++b;
这个问题将做为这个测验的一个愉快的结尾。不管你相不相信,上面的例子是完全合乎语法的。问题是编译器如何处理它?水平不高的编译作者实际上会争论这个问题,根据最处理原则,编译器应当能处理尽可能所有合法的用法。因此,上面的代码被处理成:
c = a++ + b;
因此, 这段代码持行后a = 6, b = 7, c =12。
如果你知道答案,或猜出正确答案,做得好。如果你不知道答案,我也不把这个当作问题。我发现这个问题的最大好处是:这是一个关于代码编写风格,代码的可读性,代码的可修改性的好的话题。
4、用递归算法判断数组a[N]是否为一个递增数组。
递归的方法,记录当前最大的,并且判断当前的是否比这个还大,大则继续,否则返回false结束:
bool fun( int a[], int n )
{
if( n= =1 )
return true;
if( n= =2 )
return a[n-1] >= a[n-2];
return fun( a,n-1) && ( a[n-1]>= a[n-2] );
}
5、编写算法,从10亿个浮点数当中,选出其中最大的10000个。
用外部排序,在《数据结构》书上有
《计算方法导论》在找到第n大的数的算法上加工
6.单连表的建立,把'a'--'z'26个字母插入到连表中,并且倒叙,还要打印!
方法1:
typedef struct val
{
}*p;
void main(void)
{
}
}
方法2:
node *p = NULL;
node *q = NULL;
node *head = (node*)malloc(sizeof(node));
head->data = '';head->next=NULL;
node *first = (node*)malloc(sizeof(node));
first->data ='a';first->next=NULL;head->next =first;
p = first;
int longth = 'z' - 'b';
int i="0";
while ( i<=longth )
{
node *temp = (node*)malloc(sizeof(node));
temp->data ='b'+i;temp->next=NULL;q=temp;
head->next = temp;temp->next=p;p=q;
i++;
}
print(head);
测试程序
#include <stdio.h>
struct A{
};
struct B{
}__attribute__((aligned));
struct C{
}__attribute__((aligned(1)));
struct D{
}__attribute__((aligned(4)));
struct E{
}__attribute__((aligned(8)));
struct F{
}__attribute__((packed));
int main(int argc, char **argv)
{
}
在fedora 7下的测试结果:
A = 28, B = 32, C = 28, D = 28, E = 32, F = 20
A:不使用__attribute__ 默认4字节对齐
B:__attribute__((aligned))
C:__attribute__((aligned(1))) 不支持,除了packed 不能减小对齐字节数,以默认对齐方式对齐
D:__attribute__((aligned(4))) 四字节对齐
E:__attribute__((aligned(8)))八字节对齐
F:__attribute__((packed))
Here is a structure in which the field x is packed, so that itimmediately follows a:
cygwin下的测试结果:
A = 32, B = 32, C = 32, D = 32, E = 32, F =20
从测试结果上看默认8字节对齐?或是只支持packed,未知
8、一个递规反向输出字符串的例子,可谓是反序的经典例程.
void inverse(char *p)
{
return;
}
int main(int argc, char *argv[])
{
}
9、输出和为一个给定整数的所有组合
例如n=5
5=1+4;5=2+3(相加的数不能重复)
则输出
1,4;2,3。
答案:
#include<stdio.h>
void main()
{
unsigned long int a,i=1;
scanf("%d",&a);
if(a%2==0)
{
}
else
for(i=1;i<=a/2;i++)
}
10、在对齐为4的情况下
struct BBB
{
}*p;
p=0x1000000;
p+0x200=____;
(Ulong)p+0x200=____;
(char*)p+0x200=____;
答案:假设在32位CPU上,
sizeof(long) = 4 bytes
sizeof(char *) = 4 bytes
sizeof(short int) = sizeof(short) = 2 bytes
sizeof(char) = 1 bytes
由于是4字节对齐,
sizeof(struct BBB) = sizeof(*p)
= 4 + 4 + 4((2 + 1 )+ 1补齐为4)+ 12(2*5 + 2补齐为12) = 24 bytes
p=0x1000000;
p+0x200=____;
(Ulong)p+0x200=____;
(char*)p+0x200=____;
11、写一段程序,找出数组中第k大小的数,输出数所在的位置。例如{2,4,3,4,7}中,第一大的数是7,位置在4。第二大、第三大的数都是4,位置在1、3随便输出哪一个均可。函数接口为:int find_orderk(const int*narry,const int n,const int k)
要求算法复杂度不能是O(n^2)
答案:可以先用快速排序进行排序,其中用另外一个进行地址查找
代码如下,在VC++6.0运行通过。给分吧^-^
//快速排序
#include<iostream>
usingnamespacestd;
intPartition (int*L,intlow,int high)
{
inttemp = L[low];
intpt = L[low];
while (low < high)
{
while (low < high &&L[high] >= pt)
--high;
L[low] = L[high];
while (low < high &&L[low] <= pt)
++low;
L[low] = temp;
}
L[low] = temp;
returnlow;
}
voidQSort (int*L,intlow,int high)
{
if (low < high)
{
intpl = Partition (L,low,high);
QSort (L,low,pl - 1);
QSort (L,pl + 1,high);
}
}
intmain ()
{
intnarry[100],addr[100];
intsum = 1,t;
cout << "Input number:"<< endl;
cin >> t;
while (t != -1)
{
narry[sum] = t;
addr[sum - 1] = t;
sum++;
cin >> t;
}
sum -= 1;
QSort (narry,1,sum);
for (int i = 1; i <= sum;i++)
cout << narry[i]<< '/t';
cout << endl;
intk;
cout << "Please input place youwant:" << endl;
cin >> k;
intaa = 1;
intkk = 0;
for (;;)
{
if (aa == k)
break;
if (narry[kk] != narry[kk + 1])
{
aa += 1;
kk++;
}
}
cout << "The NO."<< k <<"number is:" << narry[sum - kk]<< endl;
cout << "And it's place is:" ;
for (i = 0;i < sum;i++)
{
if (addr[i] == narry[sum - kk])
cout << i<< '/t';
}
return0;
}
intmain(void)
{
int *a = (int *)malloc(MAX * sizeof(int));
int *b;
FILE *fp1;
FILE *fp2;
fp1 = fopen("a.txt","r");
if(fp1 == NULL)
{printf("error1");
}
if(fp2 == NULL)
{printf("error2");
}
int i = 0;
while(fscanf(fp1,"%d",&a[i]) != EOF)
{
i++;
j++;
if(i >= MAX)
{
MAX = 2 * MAX;
b = (int*)realloc(a,MAX * sizeof(int));
if(b == NULL)
{
printf("error3");
exit(-1);
}
a = b;
}
}
for(;--j >= 0;)
fclose(fp1);
fclose(fp2);
return 0;
}
12、运行的结果为什么等于15
#include"stdio.h"
#include "string.h"
void main()
{
char aa[10];
printf("%d",strlen(aa));
}
答案:sizeof()和初不初始化,没有关系;strlen()和初始化有关。
13、分析一下
#include<iostream.h>
#include<string.h>
#include<malloc.h>
#include<stdio.h>
#include<stdlib.h>
#include<memory.h>
typedef struct
{
}AA;
void main()
{
}
答案: -16和1
首先sizeof(AA)的大小为4,b1和b2分别占5bit和2bit.
经过strcpy和memcpy后,aa的4个字节所存放的值是:
0,1,2,3的ASC码,即00110000,00110001,00110010,00110011
所以,最后一步:显示的是这4个字节的前5位,和之后的2位
分别为:10000,和01
因为int是有正负之分,所以是-16和1
14、求函数返回值,输入x=9999;
int func ( x )
{
}
结果呢?
答案:知道了这是统计9999的二进制数值中有多少个1的函数,且有
9999=9×1024+512+256+15
9×1024中含有1的个数为2;
512中含有1的个数为1;
256中含有1的个数为1;
15中含有1的个数为4;
故共有1的个数为8,结果为8。
1000 - 1 = 0111,正好是原数取反。这就是原理。
用这种方法来求1的个数是很效率很高的。
不必去一个一个地移位。循环次数最少。
15、int a,b,c 请写函数实现C=a+b ,不可以改变数据类型,如将c改为long int,关键是如何处理溢出问题
答案:bool add (int a, int b,int *c)
{
*c=a+b;
return (a>0 &&b>0&&(*c<a ||*c<b) || (a<0&& b<0&&(*c>a ||*c>b)));
}
16、改错:
#i nclude<stdio.h>
int main(void) {
}
答案:搞错了,是指针类型不同,
int **p; //二级指针
&arr; //得到的是指向第一维为100的数组的指针
应该这样写#i nclude<stdio.h>
int main(void) {
int **p, *q;
int arr[100];
q = arr;
p = &q;
return 0;
标准答案示例:
const float EPSINON = 0.00001;
if ((x >= - EPSINON)&& (x <=EPSINON)
void *p = malloc(100 );
请计算
sizeof ( p ) =
17、在C++ 程序中调用被 C编译器编译后的函数,为什么要加extern“C”?
答:C++语言支持函数重载,C语言不支持函数重载。函数被C++编译后在库中的名字与C语言的不同。假设某个函数的原型为:voidfoo(int x, int y);
该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。
C++提供了C连接交换指定符号extern“C”来解决名字匹配问题。
18、
void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
请问运行Test函数会有什么样的结果?
答:试题传入GetMemory( char *p)函数的形参为字符串指针,在函数内部修改形参并不能真正的改变传入形参的值,执行完
char *str = NULL;
GetMemory( str );
后的str仍然为NULL;
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
请问运行Test函数会有什么样的结果?
答:可能是乱码。
的p[]数组为函数内的局部自动变量,在函数返回后,内存已经被释放。这是许多程序员常犯的错误,其根源在于不理解变量的生存期。
void GetMemory2(char **p, int num)
{
*p = (char *)malloc(num);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
请问运行Test函数会有什么样的结果?
答:
(1)能够输出hello
(2 )Test函数中也未对malloc的内存进行释放。
(3)GetMemory避免了试题1的问题,传入GetMemory的参数为字符串指针的指针,但是在GetMemory中执行申请内存及赋值语句
*p = (char *) malloc( num );
后未判断内存是否申请成功,应加上:
if ( *p == NULL )
}
{
char *str = (char *) malloc(100);
printf(str);
}
}
请问运行Test函数会有什么样的结果?
答:执行
char *str = (char *) malloc(100);
后未进行内存是否申请成功的判断;另外,在free(str)后未置str为空,导致可能变成一个“野”指针,应加上:
str = NULL;
19、写出运行结果
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[]) {
/0
c
b
a
f
e
d
}
a slen = 3,b slen =6
a
a = abc, b = defabc
asize len = 4, bsize len = 3
注:栈分配原则:从高地址->低地址分配;
b
It is not the aboveresult when I test in Vmware Linux.
4.说出错误
void test() {
}
注:数组越界
20、说出错误
void test() {
//modif
}
21、写出运行结果
#include <stdio.h>
#include <string.h>
#define STRCPY(a,b)
#define STRCPY1(a, b)
intmain(void)
}
var1 = bbbb
var2 = var1
22、宏中"#"和"##"的用法
一、一般用法
我们使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起.
用法:
#include<cstdio>
#include<climits>
using namespace std;
#define STR(s) #s
#define CONS(a,b) int(a##e##b)
int main()
{
printf(STR(vck)); // 输出字符串"vck"
printf("%d/n", CONS(2,3)); // 2e3 输出:2000
return 0;
}
二、当宏参数是另一个宏的时候
需要注意的是凡宏定义里有用'#'或'##'的地方宏参数是不会再展开.
a, 非'#'和'##'的情况
#define TOW (2)
#define MUL(a,b) (a*b)
printf("%d*%d=%d/n", TOW, TOW,MUL(TOW,TOW));
这行的宏会被展开为:
printf("%d*%d=%d/n", (2), (2), ((2)*(2)));
MUL里的参数TOW会被展开为(2).
b,当有'#'或'##'的时候
#define A (2)
#define STR(s) #s
#define CONS(a,b) int(a##e##b)
printf("int max: %s/n", STR(INT_MAX)); // INT_MAX#include<climits>
这行会被展开为:
printf("int max: %s/n", "INT_MAX");
printf("%s/n",CONS(A, A)); // compile error
这一行则是:
printf("%s/n", int(AeA));
A不会再被展开, 然而解决这个问题的方法很简单. 加多一层中间转换宏.
加这层宏的用意是把所有宏的参数在这层里全部展开, 那么在转换宏里的那一个宏(_STR)就能得到正确的宏参数.
#define A (2)
#define _STR(s) #s
#define STR(s) _STR(s) // 转换宏
#define _CONS(a,b) int(a##e##b)
#define CONS(a,b) _CONS(a,b) // 转换宏
printf("int max: %s/n", STR(INT_MAX)); //INT_MAX,int型的最大值,为一个变量#include<climits>
输出为: int max: 0x7fffffff
STR(INT_MAX)--> _STR(0x7fffffff) 然后再转换成字符串;
printf("%d/n", CONS(A, A));
输出为:200
CONS(A, A) --> _CONS((2), (2)) -->int((2)e(2))
三、'#'和'##'的一些应用特例
1、合并匿名变量名
#define ___ANONYMOUS1(type, var, line) type var##line
#define __ANONYMOUS0(type, line) ___ANONYMOUS1(type, _anonymous,line)
#define ANONYMOUS(type) __ANONYMOUS0(type, __LINE__)
例:ANONYMOUS(static int); 即: static int _anonymous70; 70表示该行行号;
第一层:ANONYMOUS(static int);--> __ANONYMOUS0(static int,__LINE__);
第二层:--> ___ANONYMOUS1(static int, _anonymous,70);
第三层:--> static int_anonymous70;
即每次只能解开当前层的宏,所以__LINE__在第二层才能被解开;
2、填充结构
#define FILL(a) {a, #a}
enum IDD{OPEN, CLOSE};
typedef struct MSG{
IDD id;
const char * msg;
}MSG;
MSG _msg[] ={FILL(OPEN), FILL(CLOSE)};
相当于:
MSG _msg[] = {{OPEN, "OPEN"},
{CLOSE, "CLOSE"}};
3、记录文件名
#define _GET_FILE_NAME(f) #f
#define GET_FILE_NAME(f) _GET_FILE_NAME(f)
static char FILE_NAME[] = GET_FILE_NAME(__FILE__);
4、得到一个数值类型所对应的字符串缓冲大小
#define _TYPE_BUF_SIZE(type) sizeof #type
#define TYPE_BUF_SIZE(type) _TYPE_BUF_SIZE(type)
char buf[TYPE_BUF_SIZE(INT_MAX)];
--> char buf[_TYPE_BUF_SIZE(0x7fffffff)];
--> char buf[sizeof"0x7fffffff"];
这里相当于:
char buf[11];-
第3题:考查递归调用
int foo ( int x ,int n) { int val; val =1;
这段代码对x和n完成什么样的功能(操作)?
(a) x^n (x的n次幂)
(b) x*n(x与n的乘积)
(c) n^x(n的x次幂)
(d) 以上均不是