面試經典題之C語言

問題一

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

不難看出,&a 得到的是 int(* )[5]。這時ptr已經又上面被強轉成被int* 了是一個數組指針,+1後即ptr 的指向應該是 5 後面的一個元素。
由於a+1時a被轉換成了指針指向這個數組的首元素地址,+1後指向2這個元素的地址,故解引用後得到2。而ptr-1後指向5這個元素的地址,解引用後得到元素5。所以這個打印出來的答案爲2, 5。

問題二

struct Test
{
	int Num;
	char *pcName;
	short sDate;
	char cha[2];
	short sBa[4];	
};
	struct Test* p = (struct Test*)0x100000;
	printf("%p\n", p + 0x1);
	printf("%p\n", (unsigned long)p + 0x1);
	printf("%p\n", (unsigned int*)p + 0x1);

值得注意的時這個結構體的大小爲20個字節。
所以p+0x1即爲加了一個結構體大小的字節,所以第一個打印的爲100020
而對於剩下的兩個,第一個(unsigned long)p把p強轉爲long類型的,而此時+0X1就相當於加一個整數1,故輸出爲100001。而(unsigned int*)p把p強轉換爲無符號int 型的一個指針。此時+0x1相當於加了一個int型指針的大小,我們知道在32爲機器下無論什麼指針都是4字節,所以結果應該爲100004。

問題三

	int a[4] = { 1, 2, 3, 4 };
	int *ptr1 = (int *)(&a + 1);
	int *ptr2 = (int *)((int)a + 1);
	printf("%x,%x", ptr1[-1], *ptr2);

這個問題與第一題有點像。
首先&a取的爲這個數組指針,再+1後指向4後面的元素地址。要注意,此時還是一個數組指針,而經過(int * )後此時ptr1爲一個int 型的指針而打印的ptr1[-1]即地址-1,指向4這個元素的地址。而%x打印一個16進制整數,故打印結果爲4。
而對於第二個取得a爲1這個元素的地址的首字節。將這個地址強轉爲int型再加1後,就爲一個整數。而得到的答案又被強轉爲int型的一個指針,故 *ptr2表示是從當前地址開始往後讀取四個字節並且當成int來理解,而又因爲大多數機器爲小端字節序,故答案爲2000000。

問題四

	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
	int *p;
	p = a[0];
	printf("%d", p[0]);

這個題是一道很經典的題型,首先看這個二維數組,這是一個長度爲3的一維數組,其中每個元素爲長度爲2的一維數組。不過你有沒有發現什麼不對,沒錯,裏面用到的是小括號,並且用逗號運算符隔開,我們知道逗號運算符所取得的是最後一個逗號右邊的數。故這個二維數組表示爲{ {1, 3}, {5, 0}, {0,0} },我們來看,p=a[0]得到的是一個長度爲二的一維數組的,此時p[0]則是取這個一維數組的首元素,故與a[0][0]所表達的意思一樣。即答案爲1。

問題五

	int a[5][5];	// 二維數組
	int(*p)[4];		// 數組指針
	p = a;
	printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);

首先創建了一個二維數組,又創建了一個數組指針。不過這個數組指針指向的是長度爲4的數組。而p=a這一句。使得p每次取四個元素,這樣一直存下取,而該數組是以五個元素爲一組一共五組。故所需要打印的分別是一個指針和一個整數,值得注意的是兩個指針相減是要求這兩個指針在同一個內存上,所得到的差值用%d打印則是這兩個地址之間的元素個數。由於在不同機器上打印結果不同故答案不在此展示。

問題六

int aa[2][5] = {
		{1, 2, 3, 4, 5},
		{6, 7, 8, 9, 10 }
	};
	int *ptr1 = (int *)(&aa + 1);
	int *ptr2 = (int *)(*(aa + 1));
	printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));

這道題與第一道也有類似的地方,&aa取的是這個二維數組的地址,故+1後指向這個二維數組的下一個地址,所以ptr1得到的是強轉爲int 型的指針。而aa+1中aa被隱式轉換爲一個長度爲5的一個數組指針,即指向{1, 2, 3, 4, 5}這個數組,此時再+1得到的是則指向{6, 7, 8, 9, 10 }這個數組。同樣ptr2也被強轉換爲int型的一個指針。而指針-1後則指向前一個元素的地址。故打印結果爲10,5。

問題七

	char *a[] = { "work","at","alibaba" };
	char**pa = a;
	pa++;
	printf("%s\n", *pa);

首先我們要知道a是個指針數組。而pa一個二級指針,指向a的首地址。我們知道a[0]指向 “work”,a[1]指向"at",a[2]指向"alibaba"。而pa指向a[0]這個地址,故pa++後指向"at”這個元素的地址,故%s打印後結果爲 at。

問題八

    char *c[] = { "ENTER","NEW","POINT","FIRST" };
	char**cp[] = { c + 3,c + 2,c + 1,c };
	char***cpp = cp;

	printf("%s\n", **++cpp);
	printf("%s\n", *--*++cpp + 3);
	printf("%s\n", *cpp[-2] + 3);

這道題給出的條件與上道題類似,首先我們知道a[0]指向"ENTER"的地址,a[1]指向"NEW"的地址,a[2]指向"POINT"的地址,a[3]指向"FIRST"的地址。而cp爲一個二級指針,不難看出cp[0]指向c[3]的地址,cp[1]指向c[2]的地址,cp[2]指向c[1]的地址,cp[3]指向c[0]的地址。而cpp爲一個三級指針,此時將cp賦給它,則它指向cp的首元素地址。分析過後,我們來看需要打印的結果。
首先通過運算優先級我們知道,先++cpp得到cp[1]的地址,解引用得到c[2]的地址,再解引用打印出"POINT"。
第二個同樣++cpp得到cp[2]的地址,解引用得到c[1]的地址再減減後得到c[0]的地址,此時指向"ENTER",而+3後則指向第二個字母E的地址,故5s打印得到"ER"。
第三個cpp[-2]即cpp-2指針減2後指向cp[0]的地址,解引用得到cp[0]即c[3]的地址,此時指向"FIRST"首字母地址,+3後指向S,故%s打印得到"S"。

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