《C和指標》第三章課後習題解答

woshixinhua發表於2020-09-29

 

 

1、在你的機器上,字元的範圍有多大?有哪些不同的證書型別,它們的範圍又是如何?

答:在main.c檔案#include <limits.h>,進入limits.h檔案即可看到各個資料型別的最大值最小值。

2、在你的機器上,各種不同的浮點數的範圍是怎樣的?

答:同1題。

3.假定你正編寫一個程式,它必須執行於兩臺機器之上。這兩臺機器的預設整型長度並不相同,一個是16位,另一個是32位。而這兩臺機器的長整型長度分別是32位和64位。程式所使用的的有些變數值並不太大,足以儲存於任何一臺機器的預設整型變數中,但有些變數的值卻較大,必須是32位的整型變數才能容納它。一種可行的解決方案是用長整型表示所有的值,但在16位機器上,對於那些用16位足以容納的值而言,時間和空間的浪費不可小視。在32位機上,也存在事件和空間的浪費問題。

如果想讓這些變數在任何一臺機器上的長度都合適的話,你該如何宣告它們呢?正確的方法是不應該在任何一臺機器中編譯程式前對程式進行修改。提示:試試包含一個標頭檔案,裡面包含每臺機器特定的宣告。

答:新建一個名為DataType.h的標頭檔案,在16位機和32位機上該標頭檔案的程式碼分別如下:

//16位機
typedef unsigned char	int8;
typedef int				int16;
typedef long int		int32;

// 32位機
typedef unsigned char	int8;
typedef short int		int16;
typedef int				int32;
typedef long int		int64;

4、假定你有一個程式,它把一個long整型變數賦值給一個short整型變數。當你編譯程式時會發生什麼情況?當你執行程式時會發生什麼情況?你認為其它編譯器的結果是否如此?

答:我使用的是Visual studio 2012,在上面編譯和執行程式都沒有問題。但是控制檯顯示一行警告資訊,提醒可能丟失資料。

警告	2	warning C4244: “=”: 從“long”轉換到“short”,可能丟失資料

其它編譯器不一定會是同樣的結果,有的可能編譯不通過。

5、假定你有一個程式,它把一個double變數賦值給一個float變數。當你編譯程式時會發生什麼情況?當你執行程式時會發生什麼情況?你認為其它編譯器的結果是否如此?

答:和上題一樣,編譯和執行程式都沒有問題。但是控制檯顯示一行警告資訊,提醒可能丟失資料。

警告	1	warning C4244: “=”: 從“double”轉換到“float”,可能丟失資料

6、編寫一個列舉宣告,用於定義硬幣的值,請使用符號PENNY,NICKEL等。

enum MONEY{PENNY=1, NICKEL = 5, DIME = 10, QUARTER = 25}

7、下列程式碼段會列印出什麼東西?

// 題目程式碼
enum Liquid
{
	OUNCE=1, CUP=8, PINT=16,QUART=32, GALLON=128
};
enum Liquid jar;
jar = QUART;
printf("%s\n",jar); 
jar = jar + PINT;
printf("%s\n",jar);

答:上述程式碼執行出錯,錯誤資訊如下:

	1	IntelliSense: 不能將 "int" 型別的值分配到 "Liquid" 型別的實體	

實際上錯誤的是列印資訊的資料格式%s,列舉型別在記憶體是以整型資料型別儲存,列印列舉型別變數應該使用整型資料格式%d,把printf裡的%s全部改成%d,程式就可以正常執行。上述報錯資訊是因為,C語言並不建議對列舉變數進行計算,所以報錯,但是居然不影響程式執行,不知道為啥??修改程式後以及執行結果如下:

// 修改程式碼後
enum Liquid
{
	OUNCE=1, CUP=8, PINT=16,QUART=32, GALLON=128
};
enum Liquid jar;
jar = QUART;
printf("%d\n",jar); 
jar = jar + PINT;
printf("%d\n",jar);

執行結果:
32
48

8、你所使用的C編譯器是否允許程式修改字串常量?是否存在編譯器選項,允許或禁止你修改字串常量?

答:我使用的VS 2012內建編譯器,允許我修改字串常量。且沒找到這樣的編譯器選項。

// 修改字串常量程式碼	
char mychar[] = "hello world";
printf("original string:%s\n",mychar);
mychar[1] = 'h';
printf("changed string:%s\n",mychar);

執行結果:
original string:hello world
changed string:hhllo world

9、如果整數型別在正常情況下是有符號型別,那麼signed關鍵字的目的何在呢?

答:整數型別分為有符號型別和無符號型別,分別用signed和unsigned關鍵字宣告。雖然整數型別在預設情況下預設為有符號型,但signed可以顯式定義為有符號型別,語義更清楚。還有萬一有的編譯器整型的預設值不是有符號呢???

10、一個無符號變數可不可以比相同長度的有符號變數容納更大的值?

答:我認為無符號變數比相同長度的有符號變數容納更大的值是必然的,相同長度下,有符號數的最高位是符號位,其它位是資料位,而無符號數的所有位都是資料位,所以無符號數的最大值總是有符號數最大值的2倍+1。

11、加入int和float型別都是32位長,你覺得哪種型別能容納的值精度更大一些?

答:int型別只能儲存整數,float能儲存小數,顯然float的值精度更大一些。

12、下面是兩個程式碼片段,取自一個函式的起始部分,它們完成任務的方式有何不同?

// 片段1
int a = 25;

// 片段2
int a;
a = 25;

答:它們完成任務的方式無任何不同,片段1和片段2的程式碼是等效的。

13、如果問題12中程式碼片段的宣告中包含有const關鍵字,它們完成任務的方式又有何不同?

答:加入const關鍵字的程式碼片段如下:

// 片段1
int const a = 25;

// 片段2
int const a;
a = 25;

片段1能正常完成整型常量a的宣告和初始化。片段2的程式碼編譯器報錯,因為宣告一個整型常量必須在宣告的時候完成初始化,並且之後的不能修改它的值,所以兩行都報錯。

14、在一個程式碼塊內部宣告的變數可以從該程式碼塊的任何位置根據名字來訪問,對還是錯?

答:錯。必須在變數宣告之後才可以訪問,如果在變數宣告以前的程式碼塊內部是不可以訪問的。如果程式碼塊內部再巢狀一個子程式碼塊,且子程式碼塊宣告瞭一個同名的同型別變數,那麼這個外部的變數就會被遮蔽,不能在子程式碼塊中根據名字訪問這個變數。

15、假定函式a宣告瞭一個自動整型變數x,你可以在其它函式內訪問x,只要你是用來下面這樣的宣告:

extern int x;

 對還是錯?

 答:錯。函式a宣告的自動變數x的作用域只是函式a的程式碼塊內部,其它函式無法訪問。另一個函式中extern宣告表示可以呼叫外部已經定義的x變數,要求x的連結屬性是外部連結屬性,而a函式內的x變數的連結屬性為none。

16、假定15題中的變數x被宣告為static,你的答案會不會有所變化?

答:不會。x變數是a函式內的區域性變數,被宣告為static只是改變了它的儲存方式,並不會改變它的作用域。

17、假定檔案a.c的開始部分有下面這樣的宣告:

int x;

如果你希望從不同的原始檔的函式中訪問這個變數,需不需要新增額外的宣告,如果需要的話,應該新增怎樣的宣告?

答:x在開頭部分定義,預設連結屬性為external,可以從不通過的原始檔的函式中訪問這個變數。在a.c檔案不需要新增額外的宣告,但是為了更好的程式設計風格,最好在int前加上extern宣告外外部變數。而在不同的原始檔的函式中訪問,必須加上extern進行宣告,表示變數x已經在外部定義。

20、假定19題中的宣告包含了關鍵字static。你的答案會不會有所變化?

答:如果x的宣告包含了關鍵字static,表示x的連結屬性為internal,則外部的原始檔不可以訪問。

21、假定一個函式包含了一個自動變數,這個函式在同一行中被呼叫了兩次。試問,在函式第2次呼叫開始時該變數的值和函式第一次呼叫即將結束時的值有無可能相同?

答:函式內的自動變數儲存於堆疊區,每次函式被呼叫時自動分配記憶體,函式結束自動釋放。如果函式執行會改變自動變數的值,則在函式第2次呼叫開始時該變數的值和函式第一次呼叫即將結束時的值,是不同的;如果函式執行不改變自動變數的值,那麼在函式第2次呼叫開始時該變數的值和函式第一次呼叫即將結束時的值,是相同的。

22、當下面的宣告出現於某個程式碼塊內部和出現於任何程式碼塊外部時,它們在行為上有何不同?

int a = 5;

答:出現於某個程式碼塊內部:a是一個自動變數,變數的值儲存於堆疊,程式執行到該語句時,會在堆疊上給a變數分自動分配一個地址並進行初始化,程式碼塊執行完畢a的記憶體就被釋放。

出現於任何程式碼塊外部:a是一個靜態變數,變數的值儲存於靜態區,在程式啟動前a就被分配記憶體並初始化,變數一直存在直到程式結束。

23、假定你想在用一個原始檔中編寫兩個函式x和y,需要使用下面的變數:

名字型別儲存型別連結屬性作用域初始化為
aintstaticexternalx可以訪問,y不能訪問1
bcharstaticnonex和y都可以訪問2
cintautomaticnonex的區域性變數3
dfloatstaticnonex的區域性變數4

你應該怎樣編寫這些變數?應該在什麼地方編寫?注意:所有初始化必須在宣告中完成,我不是通過函式中的任何可執行語句來完成。

答:程式碼如下:我覺得題目是有問題的,b變數我沒有辦法讓它既是static儲存型別又是none連結屬性,知道的朋友歡迎評論區討論。

#include <stdio.h>

char b = '2'; // char static none ??????
void y()
{
	printf("b=%c\n",b);
}

int a = 1;  // int static external

void x()
{
	int c = 3;					// int automatic none
	static float d = 4.0;		// float static none
	printf("a=%d, b=%c, c=%d, d=%f",a,b,c,d);
}

24、確認下面程式中存在的任何錯誤(你可能想動手編譯一下,這樣能夠踏實一些)。在去除所有錯誤之後,確定所有識別符號的儲存型別、作用域和連結屬性。每個變數的初始值會是什麼?程式中存在許多同名的識別符號,它們所代表的是相同的變數還是不同的變數?程式中的每個函式從哪個位置起可以被呼叫?

static int w = 5;
extern int x;
static float
	func1(int a, int b, int c)
{
	int c,d,e = 1;
	// ...
	{
		int d,e,w;
		// ...
		{
			int b,c,d;
			static int y = 2;
			// ...
		}
	}
	// ...
	{
		register int a,d,x;
		extern int y;
	}

}
static int y;
float
	func2(int a)
{
	extern int y;
	static int z;
	// ...
}

答:第6行int c,d,e = 1; c變數與形參重定義,把它刪了程式就沒有報錯了。

static int w = 5;
extern int x;
static float
	func1(int a, int b, int c)
{
	int d,e = 1;
	// ...
	{
		int d,e,w;
		// ...
		{
			int b,c,d;
			static int y = 2;
			// ...
		}
	}
	// ...
	{
		register int a,d,x;
		extern int y;
	}

}
static int y;
float
	func2(int a)
{
	extern int y;
	static int z;
	// ...
}

 

相關文章