c/c++笔试题(2)(转载的)

时间:2022-06-22 03:03:41

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
  int date_1;
 
   struct val *next;
}*p;
void main(void)
  char c;
 
  
 
   for(c=122;c>=97;c--)
 
      { p.date=c;
 
        p="p-">next;
 
       }
 
   p.next=NULL;
}
}
方法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{
 
      char a;
 
      int b;
 
      unsigned short c;
 
      long d;
 
      unsigned long long e;
 
      char f;
};

struct B{
 
      char a;
 
      int b;
 
      unsigned short c;
 
      long d;
 
      unsigned long long e;
 
      char f;
}__attribute__((aligned));

struct C{
 
      char a;
 
      int b;
 
      unsigned short c;
 
      long d;
 
      unsigned long long e;
 
      char f;
}__attribute__((aligned(1)));


struct D{
 
      char a;
 
      int b;
 
      unsigned short c;
 
      long d;
 
      unsigned long long e;
 
      char f;
}__attribute__((aligned(4)));

struct E{
 
      char a;
 
      int b;
 
      unsigned short c;
 
      long d;
 
      unsigned long long e;
 
      char f;
}__attribute__((aligned(8)));

struct F{
 
      char a;
 
      int b;
 
      unsigned short c;
 
      long d;
 
      unsigned long long e;
 
      char f;
}__attribute__((packed));

int main(int argc, char **argv)
{
 
      printf("A = %d, B = %d, C = %d, D = %d, E = %d, F = %d/n",
 
              sizeof(struct A), sizeof(struct B), sizeof(struct C), sizeof(structD), sizeof(struct E), sizeof(struct F));
 
      return0;
}
在fedora 7下的测试结果:
A = 28, B = 32, C = 28, D = 28, E = 32, F = 20
A:不使用__attribute__ 默认4字节对齐
B:__attribute__((aligned))
 
    the compiler automatically sets the alignment for the declaredvariable or field to the largest alignment which is ever used forany data type on the target machine you are compiling for. Doingthis can often make copy operations more efficient, because thecompiler can use whatever instructions copy the biggest chunks ofmemory when performing copies to or from the variables or fieldsthat you have aligned this way.
 
 最大对齐方式,此例中为16字节对齐,同E
C:__attribute__((aligned(1))) 不支持,除了packed 不能减小对齐字节数,以默认对齐方式对齐
D:__attribute__((aligned(4))) 四字节对齐
E:__attribute__((aligned(8)))八字节对齐
F:__attribute__((packed))
 
   the aligned attribute can only increase the alignment; but you candecrease it by specifying packed as well.
 
   The packed attribute specifies that a variable or structure fieldshould have the smallest possible alignment―one byte for avariable, and one bit for a field, unless you specify a largervalue with the aligned attribute.
Here is a structure in which the field x is packed, so that itimmediately follows a:
 
        struct foo
 
        {
 
          char a;
 
          int x[2] __attribute__ ((packed));
 
        };
 
 变量以字节对齐,结构体域以位对齐 
cygwin下的测试结果:
A = 32, B = 32, C = 32, D = 32, E = 32, F =20
从测试结果上看默认8字节对齐?或是只支持packed,未知

8、一个递规反向输出字符串的例子,可谓是反序的经典例程.
void inverse(char *p)
{
 
   if( *p = = '/0' )
return;
 
   inverse( p+1 );
 
   printf( "%c", *p );
}
int main(int argc, char *argv[])
{
 
   inverse("abc/0");
 
   return 0;
}

9、输出和为一个给定整数的所有组合
例如n=5
5=1+4;5=2+3(相加的数不能重复)
则输出
1,4;2,3。
答案:
#include<stdio.h>
 
#include<stdio.h>
void main()
{
unsigned long int a,i=1;
scanf("%d",&a);
if(a%2==0)
{
 
    for(i=1;i<a/2;i++)
 
    printf("%d",a,a-i);
}
else
for(i=1;i<=a/2;i++)
 
       printf(" %d, %d",i,a-i);
}

10、在对齐为4的情况下
struct BBB
{
 
  long num;
 
  char *name;
 
  short int data;
 
  char ha;
 
  short ba[5];
}*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=____;
 
   = 0x1000000 + 0x200*24
(Ulong)p+0x200=____;
 
   = 0x1000000 + 0x200
(char*)p+0x200=____;
 
   = 0x1000000 + 0x200*4

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 MAX = 10;
int *a = (int *)malloc(MAX * sizeof(int));
int *b;
 
 
FILE *fp1;
FILE *fp2;
fp1 = fopen("a.txt","r");
if(fp1 == NULL)
{printf("error1");
 
   exit(-1);
}
 
   fp2 = fopen("b.txt","w");
if(fp2 == NULL)
{printf("error2");
 
   exit(-1);
}
int i = 0;
 
   int j = 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;)
 
  fprintf(fp2,"%d/n",a[j]);
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
{
 
       int b1:5;
 
       int b2:2;
}AA;
void main()
{
 
      AA aa;
 
      char cc[100];
 
      strcpy(cc,"0123456789abcdefghijklmnopqrstuvwxyz");
 
      memcpy(&aa,cc,sizeof(AA));
 
      cout << aa.b1<<endl;
 
      cout << aa.b2<<endl;
}

答案: -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 )
{
 
   int countx = 0;
 
   while ( x )
 
   {
 
       countx ++;
 
       x = x&(x-1);
 
   }
 
   return countx;
}
结果呢?

答案:知道了这是统计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;
 
   int arr[100];
 
   p = &arr;
 
   return 0;
}
答案:搞错了,是指针类型不同,
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 ) = 
    (2分)

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*GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
请问运行Test函数会有什么样的结果?
答:可能是乱码。 
            charp[] = "hello world";     
 
   return p;
的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 )
 
{
 
 ...//进行申请内存失败处理
 }
 
 

 
voidTest(void)
{
char *str = (char *) malloc(100);
 
strcpy(str,“hello”);
 
free(str);   
 
if(str !=NULL)
 
{
 
 strcpy(str, “world”);
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[]) {

    char a[] = "abc";
 
   char b[] = {'d', 'e', 'f'};

    printf("a slen=%d,b slen=%d/n", strlen(a),strlen(b));
 
    printf("a = %s, b = %s/n", a, b);
 
   printf("asize len = %d, bsize len = %d/n",sizeof(a),sizeof(b));
 
   return 0;

/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() {
 
  char str[10];
 
  char* str1 = "0123456789";//alloc in the only read data area
 
  strcpy(str, str1); //array index overflow
 
Strcpy(str1,str) //because str1 alloced in the only read data area
}
注:数组越界
20、说出错误
void test() {
 
  char str[10], str1[10];
 
  for( int = 0; i < 10; i++){//memset(str,0,sizeof(str))
//modif 
i< 10-1
 
          str[i] = 'a';
 
  }
 
  strcpy(str1, str);//find not string file end descripe
}

21、写出运行结果
#include <stdio.h>
#include <string.h>

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

intmain(void) {
 
      char var1_p[20];
 
      char var2_p[30];

       strcpy(var1_p, "aaaa");
 
      strcpy(var2_p, "bbbb");

       STRCPY1(var1, var2);
 
      STRCPY(var2, var1);

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

       return 0;
}

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;   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) 以上均不是