歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

實現一個簡單的不定參數函數

一、基礎研究

寫一個函數showshr(char *,...)它可以接收不定數量的char *型參數,並打印這些指針所指向的字符串。這個題目也是要實現不定長參數的函數,而我們之前研究過printf()函數的打印機制,可以發現他們的原理是一樣的,只不過printf()函數是點對點打印,即通過說明符識別要打印的數據類型和要打印的數據個數,它的參數就是要打印的數據本身,而這裡要求的函數沒有說明符,它的參數是要打印的字符串的地址,只是在最後的參數為0以識別停止打印並返回。

那麼我覺得這裡有兩種思路:一種是在showstr()函數內部使用輸出函數函數,這樣就要求我們將參數即要打印的字符串的地址轉換成字符串的值,即轉換成一個字符數組,這需要我們把所有參數指向的空間當作是一段空間,並將它的大小即總的字符串長度計算出來,這樣才能定義字符串數組並打印。還有一種思路是直接將字符串打印到屏幕上的固定位置,即將字符串賦值到以b800為段地址的某個地址空間,這是更底層的寫法。但是我希望我在運行程序時能夠將將字符串打印到輸入命令的下一行,即打印位置是不固定的,所以我傾向於使用第一種思路。

那麼接下來可以開始寫程序了,首先我們把showstr的第一個形參命名為p,首先p的值是第一個字符串的首地址,判斷p是否為0,如果是則返回函數,如果不是則輸出p指向的字符串,在這裡我們用putchar()函數輸出,因為每次只能輸出一個字符,所以要循環輸出。那麼怎麼判斷字符串結束呢?我的辦法是判斷當前位置是否為符號,即是否為句號或感歎號,但這樣做的缺點是如果字符串不以符號結尾或者是中間出現符號的話輸出就會出現錯誤。

現在要跳到下一個參數來進行輸出,怎麼使p的值為下一個參數呢?我們知道形式參數是在棧裡存放的,而且是緊鄰的,所以如果傳遞的是p1、p2、p3,那麼入棧順序是p1、p2、

P3,因為他們的類型是char *型,所以p1的地址減2個字節就是p2的地址,所以我們對p取址再減2就是下一個參數的地址。

編寫程序如下:

 

因為發現程序停不下來,所以我把while循環換成了for循環打印有限個結果。這個程序的運行結果如下:

 

可以發現,程序存在的問題有兩個:

(1)不能調到第三條字符串,導致程序運行停不下來;

(2)打印的句號和問號有兩個。

對於第二個問題,是因為判斷語句裡面多了一條輸出語句。

在字符串的跳轉語句前面加一條輸出語句:

 

發現p只有第一次改變了:

 

這是因為p是在棧段中的存儲第一個參數的首地址,它的地址是不變的,所以po=&p+1;是不變的,所以第一次改變後,p的值就不變了。那麼把p的地址給po,讓po每次加1來跳到下一個參數的首地址,再將*po賦給p,即將下一個參數所指向的字符串的首地址賦給p,這樣p就指向下一個字符串。

修改後的程序如下:

 

這裡要注意的是po是存儲參數的地址,而p是存儲字符串的首地址,所以po應該是int *型。運行結果為:

 

但是我覺得只判斷最後的符號來判斷字符串是否結束不是很嚴謹,還有別的辦法判斷字符串是否結束嗎?查找資料可以發現字符串是以’\0’結尾的,所以我們應該可以判斷*(p+i)是否為‘\0’。修改後的程序如下:

 

二、擴展研究

1、我們之前是使用bp寄存器對棧進行操作來實現printf()函數,那麼如果用這種方法該怎麼實現這個題目?

答:我們可以用bp寄存器對棧操作來代替po指針的功能跳轉參數地址和字符串首地址。

修改後的程序如下:

 

這裡_BP還要加4是因為定義了兩個局部變量i和j,它們是存儲在棧中的,占4個字節。

2、如果不用printf函數輸出可以嗎?

答:我們常用的輸出函數還有puts函數、putchar()函數,但是他們都需要頭文件。我們也可以將結果輸出到屏幕上指定位置,即將每個字符串都輸出到b800段顯示。

三、研究總結

我們認識的輸出函數,都是將數據放進輸出流中,從底層看就是將數據放進一個緩存,之後再放到b800數據段來顯示,只不過我們寫的底層輸出函數只能將數據顯示在屏幕的固定位置,而我們使用的輸出函數會進行一些處理,使數據顯示在屏幕上合適的位置而已。

我們寫的這一��輸出函數只能輸出字符串,而且無法控制輸出的位數等,而printf函數就引入了說明符,這樣就可以人為地控制數據輸出的格式等,更加的方便。

字符串其實就是字符數組,只不過因為它是連續的,為了更方便地輸出,輸出函數為它提供了專門的輸出模式,這個模式也是以字符串的輸出為基礎的。

Copyright © Linux教程網 All Rights Reserved