一到筆試題就犯暈索性把詳解寫在博客裏

第一題、宏解析問題

#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

第二題、字節對齊問題 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個字節

(備註:什麼時候用1字節,什麼時候用4字節:

   當使用互聯網傳輸的時候用1字節對齊結構能夠得到精簡且數據規整的格式

   當內部調用運算時需要提高效率的時候用4字節對齊,4字節對齊不如1字節對齊節約空間,但是會提高讀取效率。

   有些平臺:一個int型如果存放在偶地址開始的地方,那麼一個讀週期就可以讀出32bit

   而如果存放在奇地址開始的地方,就需要2個讀週期,並對兩次讀出的結果高低字節進行拼湊才能得到該32bit數據。

    除了 float、double 以外:

    如果是1字節對齊,32位CPU與內存的最小交換數據爲1字節/次,所以 1 字節的變量是線程安全的。

    如果是4字節對齊,32位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 ]

                        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 + 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 的擠壓移向上或向下的位置。

           當指向某一個數據時,若該數比指向數小,排指向到最大的數據。

           若該數比指向數大,排指向到最小的數據,直到找到後返回。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章