【C语言】几道C/C++面试题解析

最近不务正业啊,下周就要考试了,书还没看,瞎做了几道C语言的面试题,发现C语言真是博大精深啊!

一、结构体

1、(2013年大华笔试)Intel X86 PC 以下程序运行输出的结果是:

#include <stdio.h>
int main()
{
	union{
		struct{
			unsigned short s1:3;
			unsigned short s2:3;
			unsigned short s3:3;
		}x;
		char c;
	}v;
	v.c = 103;
	printf("%d\n", v.x.s1);
	return 0;
}

我的理解:共用体能够存储不同的数据类型,而只能同时存储其中的一种类型,故共用体所占的内存空间为x或者c中较长的一个。

                     结构体中可以用特定的位数存储某个数据类型,故结构体x的内存空间为9。

      共用体v占据了9个比特,故v.c(103)(0x67)存储为001100111,因而输出v.x.s1只占用最低的3个比特,故输出111

       所以结果为:7

验证:系统:Ubuntu 11.10 32位  编译器:gcc


2、(微软笔试)以下程序在X86 PC下的运行结果:

#include <stdio.h>
struct _test
{
	unsigned short a:4;
	unsigned short b:5;
	unsigned short c:7;
}test;
void main()
{
	int i;
	test.a = 2;
	test.b = 3;
	test.c = 0;
	i = *((short*)&test);
	printf("%d\n", i);
}

我的理解:跟上题的思路一致,结构体test在内存中的长度为2个字节,数据存储为0000000000110010,i为结构体低两个字节的数据即00110010(0x32)所以答案为

       50

验证:软硬件环境与上题相同。



二、指针

指针问题很复杂,一直以来都搞不清楚,不过指针当属C语言中最有魅力的一部份的东西了,下面看一道简单的例子:

1、(2011年谷歌笔试)运行以下程序后,输出结果是什么?

#include <stdio.h>
void foobar(int a, int *b, int **c)
{
	int *p = &a;
	*p = 101;
	*c = b;
	b = p;
}

int main()
{
	int a = 1;
	int b = 2;
	int c = 3;
	int *p = &c;
	foobar(a, &b, &p);
	printf("%d %d %d %d\n", a, b, c, *p);
	return 0;
}

我的想法:指针的问题最好方法借助于画图,直观、易懂!做法如下:

main函数中:

100               104                       108                       10c

1                     2                            3                           108(104)

a                     b                            c                            p

传递给子函数的是a = 1, &b = 104,&p = 108;

foobar函数中:(注意:*c=b更改了内存空间为10c的值)

200               204                         208                      20c

101                200                                                       200

a                    b                            c                               p

所以可见在main函数中a,b,c,*p分别为1,2,3,2

验证:软硬件环境如上

2、(2013年阜博通面试题)

题目:你熟悉memcpy函数吗?该怎么实现这个函数?这个函数有什么问题?

思考过程:-听到这道题其实比较意外?memcpy用的很少,更别说有什么问题了!其实memcpy实现跟strcpy基本一样,memcpy适用范围更广。以下是代码:

#include <stdio.h>
#define SIZE 10
void *memcpy(void *dst, const void *src, int length);
//void *memmove(void *dst, const void *src, int length);
int main()
{
//      static int Dst[SIZE];
        int Src[SIZE] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        static int Dst[SIZE];
        memcpy(Dst, Src, 4 * SIZE);
        for(int index = 0; index < SIZE; index++)
                printf("%d ", Dst[index]);
        printf("\n");
/*      memmove(Dst, Src, 4 * SIZE);
        for(int index = 0; index < SIZE; index++)
        printf("%d ", Dst[index]);*/
        return 0;
}

void *memcpy(void *dst, const void *src, int length)
{
        char *d = (char *)dst;
        const char *s = (char *)src;
        while(length--)
                *d++ = *s++;
        return dst;
}

当然这个代码似乎是没问题的,而且一般情况下用基本不成问题的。但是,当源地址与目的地址有重合的时候,特别是当源地址在低,目的地址在高的情形下,很有可能会出现问题,故应该采用memmove这个函数实现,代码如下:

#include <stdio.h>
#define SIZE 10
void *memcpy(void *dst, const void *src, int length);
void *memmove(void *dst, const void *src, int length);
int main()
{
//	static int Dst[SIZE];
	int Src[SIZE] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
	static int Dst[SIZE];
	memcpy(Dst, Src, 4 * SIZE);
	for(int index = 0; index < SIZE; index++)
		printf("%d ", Dst[index]);
	printf("\n");
	memmove(Dst, Src, 4 * SIZE);
        for(int index = 0; index < SIZE; index++)
        printf("%d ", Dst[index]);
	return 0;
}

void *memcpy(void *dst, const void *src, int length)
{
	char *d = (char *)dst;
	const char *s = (char *)src;
	while(length--)
		*d++ = *s++;
	return dst;
}


void *memmove(void *dst, const void *src, int length)
{
	char *d = (char *)dst;
	char *s = (char *)src;
	if(s > d){
		while(length--)
			*d++ = *s++;
	}
	else if(s < d){
		d = d + length -1;
		s = s + length -1;
		while(length --){
			*d -- = *s --;
		}
	}
	return dst;
}


三、派生类

涉及到派生类构造函数与析构函数的顺序问题,如下例:

1、(2012年大华笔试)写出下列程序的运行结果。

#include <cstdio>
using namespace std;
class Base
{
public:
	int m_a;
	Base(int a = 2) : m_a(a){}
	virtual ~Base(){
		printf("A %d ", m_a);
	}
};

class Derived:public Base
{
public:
	Derived(int a = 4) : Base(a){}
	virtual ~Derived(){
		printf("B %d ", m_a);
	}
};

int main(int argc, char *argv[])
{
	Base *aa, bb;
	Derived cc(3);
	aa = new Derived;
	delete aa;
	return 0;	
}

我的理解:对于局部变量是存储在栈中的,所以该函数中应该按照aa、cc、bb的顺序析构的。(对于指针变量要先初始化后才能使用)

                    而对于派生类的析构是按照先子类、后基类的顺序析构的。

所以结果为:B 4 A 4 B 3 A 3 A 2

验证:

四、运算符

1、(2013年虹软笔试)以下程序输出的结果是?

#include <stdio.h>
int main()
{
	int x = 99999;
	int count = 0;
	while(x){
		x = x & (x-1);
		count++;
	}
	printf("%d\n", count);
	return 0;
}

我的理解:当时想得比较复杂,浪费了很多时间。其实很简单,主要是要能区别位与 与 逻辑与,这道题应该是位与,并且,x的众多位1中总有一个并且唯独一个x-1的位0与之对应,因此求出99999包含多少位1即可得出正确答案。

99999的二进制表示为:11000011010011111,1的个数为10,因而为10.

验证:

未完待续!!!!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值