一到笔试题就犯晕索性把详解写在博客里

第一题、预处理宏解析问题

#define MUL(a,b) a * b
printf("%d", MUL(1 + 2, 1 + 2));  

 考察的是宏解析后的代码是什么样子的:

MUL(a,b) 解析后为   a * b

a 转换为 1 + 2 、b转换为 1 + 2

a * b 转换为 1 + 2 * 1 + 2  = 1 + 2 + 2 = 5

掌握要领:宏 MUL( a , b ) 表示 MUL( 1 + 2 , 1 + 2 ),是代码编译层面上的,最终根据编译器的逻辑来转换宏的形态,证明如下:

a 表示 1 + 2,b 表示 1 + 2  a * b 表示 1 + 2 * 1 + 2 

另外:宏描述其他用法:

1、分隔符: \  用于连接上代码与下代码的描述,让代码更清晰

#define DEMO_STRING1 "1234567\
                     7654321"

#define DEMO_STRING2 "12345677654321"

DEMO_STRING1 == DEMO_STRING2

2、连接符:# 、##

#define STR_CONVERT(num) #num
STR_CONVERT(123) == "123"

#define STR_CONVERT1(num,oth) #num##oth
STR_CONVERT1(123,"4") == "1234"

#define STR_CONVERT2(a,b) a##b
int STR_CONVERT2(i,dex) = 1; == int idex = 1; 

#define fua1(a,b) a##b 
#define fub1(a) #a 
#define begin(a) fub1(a) 

puts(fub1(fua1(a, b)));
fub1() a = [fua1(a, b)] = #[fua1(a, b)] ==> "fua1(a, b)"

puts(begin(fua1(a, b)));
begin() a = [fub1(a)] = fub1() a = # 同时 fua1(a,b) ==> #a##b

 #,是把#后面的内容看成字符串;

 ##,是连接前面的类型与后面的类型在编译前并起来;

第二题、字节对齐问题

1、32位环境下定义结构体

#pragma pack(1)
struct stu1
{
    char  a;          
    short s;           
    int   i;              
    char str[5];      
    void* p;           
};
#pragma pack()

一字节对齐:

struct stu1

    char a;       //1
    short s;      //2
    int i;           //4
    char str[5]; //5
    void* p;      //4

stu1 的结构体长度为 16个字节

pragma pack(4)
struct stu2
{
	char  a;
	short s;
	int   i;
	char str[5];
        void* p;
};
#pragma pack()

四字节对齐:

struct stu2

          char a;                  [char(1) -  -  -]      char 和 short 合并占3个字节,因下一个为4个字节的int,所以补位 1字节为 4字节

         short s;                  [char(1)  short(2) 补位(1)]    为 4字节对齐

         int     i;                   [int(4)]                                  为4字节

         char str[5];             [char(5) 补位(3)]                  为8字节

         void* p;                  [void*(4)]                              为4字节

stu2 的结构体长度为 20个字节

2、64位环境下定义结构体

#pragma pack(1)
struct stu1
{
    char  a;          
    short s;           
    int   i;              
    char str[5];      
    void* p;           
};
#pragma pack()

一字节对齐:

struct stu1

    char a;       //1
    short s;      //2
    int i;           //4
    char str[5]; //5
    void* p;      //8

stu1 的结构体长度为 20个字节 ( *  64位程序指针表示8个字节 )

pragma pack(4)
struct stu2
{
	char  a;
	short s;
	int   i;
	char str[5];
        void* p;
};
#pragma pack()

四字节对齐:

struct stu2

          char a;                  [char(1) -  -  -]      char 和 short 合并占3个字节,因下一个为4个字节的int,所以补位 1字节为 4字节

         short s;                  [char(1)  short(2) 补位(1)]    为 4字节对齐

         int     i;                   [int(4)]                                  为4字节

         char str[5];             [char(5) 补位(3)]                  为8字节

         void* p;                  [void*(8)]                              为8字节

stu2 的结构体长度为 24个字节

(备注:什么时候用1字节,什么时候用4字节:

   当使用互联网传输的时候用1字节对齐结构能够得到精简且数据规整的格式

   当内部调用运算时需要提高效率的时候用4字节对齐,4字节对齐不如1字节对齐节约空间,但是会提高读取效率。

   有些平台:一个int型如果存放在偶地址开始的地方,那么一个读周期就可以读出32bit

   而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果高低字节进行拼凑才能得到该32bit数据。

    除了 float、double 以外:

    如果是1字节对齐,CPU与内存的最小交换数据为1字节/次,所以 1 字节的变量是线程安全的。

    如果是4字节对齐,CPU与内存的最小交换数据为4字节/次,所以 4 字节的变量是线程安全的。)

Lock();
int count = g_test/1024;
int mod= g_test%1024;
UnLock();

//如果不想加锁  可以写成

int temp = g_test;
int count = temp/1024;
int mod = temp%1024;

第三题、关于静态变量 static int i 在全局区的解读

int fun(int x) 
{
	static int i = 0;
	if (x <= i) 
	{
		i = -x;
	}
	else
	{
		i = x;
	}
	return i;
}
void main()
{
  int a = fun(5);
  int b = fun(3);
}

   答案:fun(5); 输出为:_5_

              fun(3);输出为:_-3_

解析路由:

                   int fun(int x)            //第一轮 [1][ x = 5,i = 0] ↓ 第二轮 [2][x = 3 , i = 5] ↓
                   static int i = 0;

                   if (x <= i)                // [1][ 5 <= 0 false ] ↓ [2][ 3 <= 5 true ] ↓

                       i = -x;                 // [2] [ i = -3 ]

                   else                       // [1] [ 5 > 0 true ] ↓

                        i = x;                 // [1] [ i = 5 ]

                    return i;                 // [1][i = 5] ↓ [2][ i = -3] ↓

第四题、关于数组定位 字节定位
 

int a[5] = {1,2,3,4,5};
int* ptr = (int*)(&a + 1);
printf("%d,%d", *(a + 1), *(ptr - 1));

[解析:a 的字节长度 等于 sizeof(int[5])] 指针位移的长度也为 sizeof(int(5))个字节

// *(a+1) 1, 2, 3, 4, 5
//        a  ↑
//a -> sizeof is 5 * int = 20
// 1, 2, 3, 4, 5 []
// ----------------
//        &a
// 1, 2, 3, 4, 5 |_______________
//                    &a + 1
int* ptr = (int*)(&a + 1);
//1, 2, 3, 4, 5 | a, b, c, d, e
//                ↑           
//               ptr
//1, 2, 3, 4, 5 | a, b, c, d, e
//            ↑   ↑
//        ptr - 1
printf("%d,%d", *(a + 1), *(ptr - 1));

  &a == sizeof(int[5]) 

  输出:*(a + 1) = 2*(ptr - 1) = 5

第五题、多态虚拟继承[掌握调用顺序]

class A
{
public:
	A(){ a = 5; }
	virtual void fun(int x){ a += x; }
	void fun2(int x){ a -= x; }
	int a;
};
class B :public A
{
public:
	B(){ a = 10;}
	void fun(int x){ a -= x; }// fun 已实现 A的 fun 重载 
	virtual void fun2(int x){ a += x; }
};
void main()
{
   A* p = new B;
   p->fun(1);          // 调用顺序 B : fun()
   printf("%d", p->a); // 9 
   p->fun2(3);         //调用顺序 A:fun2 [因为操作对象是A::fun2 没有和B::fun2 建立继承关系]
   printf("%d", p->a); // 6 
   delete p;
   p = NULL;
}

解析:virtual 是向下继承的 ↓

//a                          fun   无继承关系
//b             virtual   fun↓ 开始继承关系
//c                          fun   继承于b
//d                          fun   继承于b

创建者为B、调用对象为A,fun(1)由于继承关系,使用B::fun继承于A::fun重载作为函数对象;

fun2(3)由于多态是向下继承的,类A::fun2 与 B::fun2 是两个独立的函数,由A对象操作则使用A的调用;

 

第六题、遍历断链问题 

调用存在运行bug,链路在遍历的过程中当前节点需要被删除,要把it移动到下一个节点,删除上一段数据

#include <map>
std::map<int, int> maplint;
void main()
{
 for (int i = 0; i < 10; ++i)
 {
	 maplint[i] = i;
 }

  for (std::map<int, int>::iterator it = maplint.begin(); it != maplint.end(); ++it)
  {
  	 printf("%d\n", it->second);
	 if (it->second % 2 == 0)
	 {
	 	//std::map<int, int>::iterator ierase = it;//需要保留上一位
		//++it;			                   //推移
		//maplint.erase(ierase);                   //删除上一个位置

		//命题改写 返回it,再执行it+1,再执行 maplint.erase,到下一轮 再执行返回 it + 1 
		maplint.erase(it++);//0 -> 位移 1 遍历到 2; 2 -> 位移 3 遍历到 4 等等
	 }
  }
}

第七题、C语言标准函数strcpy的实现

char * _strcpy(char* dst,const char* src)
{
	//原始写法
	//char* tmp = dst;
	//while ((*dst++ = *src++) != '\0');
	//return tmp;

	//清晰写法
	char* tmp = dst;
	while (*src != '\0')
	{
		*dst = *src;
		src++;
		dst++;
	}
	return tmp;
}
void main()
{
   char src[] = "administrator";
   char dst[20] = "";
   _strcpy(dst, src);
}

第八题、有序数组的二分查找算法(长度为len的升序数组arr中查找x)

int searchBin(int arr[], int len, int x)
{
	int low, high, mid;
	low = 0;
	high = len - 1;
	while (low <= high)
	{
		mid = (low + high)/2;
		//printf("%d\n",mid);
		if (x == arr[mid])
		{
			return mid;
		}
		else if (x < arr[mid])
		{
			high = mid - 1;
		}
		else
		{
			low  = mid + 1;
		}
	}
	return -1;
}
void main()
{
   int arr[10] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
   int step = searchBin(arr, 10, 0);
}

解析:主要考的内容:从中定位,向上或向下查找

           mid为指向数据的位置,根据数据的大小受low 和 high 的挤压移向上或向下的位置。

           当指向某一个数据时,若该数比指向数小,排指向到最大的数据。

           若该数比指向数大,排指向到最小的数据,直到找到后返回。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值