C語言printf壓棧問題

1. 事出有因

       今天在刷面試題的時候遇到如下一個面試題:

#include <stdio.h>
#include <stdlib.h>


int main() {

	int arr[] = { 6, 7, 8, 9, 10 };

	int *ptr = arr;

	*(ptr++) += 123;

	printf("%d, %d\n", *ptr, *(++ptr));

	system("pause");
	return 0;
}

        本以爲這道面試題普普通通,沒什麼特別的,剛開始以爲僅僅是考察++i,但是發現答案並非是那麼簡單,很天真,以爲代碼循序是從左到右,但是沒意識到printf還有壓棧問題。提前公佈答案吧,這道題輸出 

程序輸出:8,8

該題在某程序猿面試寶典中,也僅僅說了:C中的printf計算參數時是從右到左壓棧的。

但是並沒有詳細細說,剛好對其有興趣就又去網上搜索相關大牛的博文學習,發現壓棧並不是那麼簡單,還是有些學問,比如如下壓棧問題:

1 i=1;   printf("%d %d\n",i,i++);         //結果 2 1
2 i=1;   printf("%d %d\n",i++,i);          //結果 1 2
3 i=1;   printf("%d %d %d\n",i,i++,i);      //結果 2 1 2
4 i=1;   printf("%d %d %d %d\n",i,++i,i++,i);  //結果 3 3 1 3

      大家可以試着去分析其中的規律。。。。。

      這時候大家就發現,這根本就沒有計算順序可言,確實,表面上看無論哪個方向計算都好像無法全部滿足如上輸出,但是我還是可以十分確定的告訴你,printf依舊是從右向左壓棧,然後再從棧頂逐個輸出的。

2. 結合(i++、++i)走進printf壓棧問題

       printf的壓棧問題通常出現在輸出列表中有++相關的計算,瞭解這個問題,我們應該明白兩個知識點

       (1). printf壓棧順序從右到左,入棧計算;然後再從棧頂逐個輸出,出棧直接輸出。

       (2). i++會拷貝一份副本,++i直接在原數據操作。

        大家都知道,使用 i++ 通常被稱爲先使用後++, 這種解釋十分通俗易懂,但是卻容易讓人誤入歧途,正確的解釋應該是,i會拷貝一份副本,i真值加一,但是原來的計算操作變量變成原來的拷貝出來的副本(可以認爲是一個全新的變量)。而++i則不會出現中間變量。

所以這是個printf壓棧與++碰撞出現的問題

接下來通過一個例子分析:

	int a = 1;
	printf("%d %d %d %d %d %d %d\n", a++, ++a, a++, ++a, a, a++, ++a);

這裏有一個規律,上面已經說到,僅僅只有 a++會拷貝,並且把輸出變量替換,而其他則都是操作 a變量,所以很容易得出如下輸出結果:

a3 a a2 a a a1 a

接下來逐步分析其中變量的值

首先是壓棧,這裏會涉及到計算以及 ++a 拷貝副本的問題:

int a = 1;	
printf("%d %d %d %d %d %d %d\n", a++, ++a, a++, ++a, a, a++, ++a);
操作次數 操作說明 壓棧變量 當前棧
1 ++a, a值加1,壓棧 a = 2  a = 2

 

a

2 a++, 拷貝副本a1 = 2,將副本壓棧,a值加1, a = 3 a1 = 2

a1

a

3 a, 無計算操作,直接壓棧 a = 3 a = 3

a

a1

a

4 ++a, a值加1,壓棧 a = 4  a = 4

a

a

a1

a

5 a++, 拷貝副本a2 =4,將副本壓棧,a值加1, a = 5 a2 = 4

a2

a

a

a1

a

6 ++a, a值加1,壓棧 a = 6 a = 6

a

a2

a

a

a1

a

7 a++, 拷貝副本a3 =6,將副本壓棧,a值加1, a = 7 a3 = 6

a3

a

a2

a

a

a1

a

所以看出,最後輸出

a3 a a2 a a a1 a

 通過表可以看出:a = 7; a3 = 6; a2 = 4; a1 = 2

所以輸出就是

6 7 4 7 7 2 7

 

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