?? c.txt
字號:
?
+
}
其中的“=”符號是輸入錯誤。如果在說明str時沒有使用const修飾符,那么相應的程序能通過編譯但不能被正確執行。
第二個原因是效率。如果編譯程序知道某個變量不會被修改,那么它可能會對生成的代碼進行某些優化。
如果一個函數參數是一個指針,并且你不希望它所指向的數據被該函數或該函數所調用的函數修改,那么你應該把該參數說明為const指針。如果一個函數參數通過值(而不是通過指針)被傳遞給函數,并且你不希望其值被該函數所調用的函數修改,那么你應該把該參數說明為const。然而,在實際編程中,只有在編譯程序通過指針存取這些數據的效率比拷貝這些數據更高時,才把這些參數說明為const。
--------------------------------------------------------------------------------
-- 作者:PrOve
-- 發布時間:2005-4-5 23:11:23
--
10.對不同類型的變量進行算術運算會有問題嗎?
C有三類固有的數據類型:指針類型、整數類型和浮點類型;
指針類型的運算限制最嚴,只限于以下兩種運算:
- 兩個指針相減,僅在兩個指針指向同一數組中的元素時有效。運算結果與對應于兩個指針的數組下標相減的結果相同。
+ 指針和整數類型相加。運算結果為一個指針,該指針與原指針之間相距n個元素,n就是與原指針相加的整數。
浮點類型包括float,double和longdouble這三種固有類型。整數類型包括char,unsigned char,short,unsigned short,int,unsigned int,long和unsigned long。對這些類型都可進行以下4種算術運算:
+ 加
- 減
* 乘
/ 除
對整數類型不僅可以進行上述4種運算,還可進行以下幾種運算:
% 取模或求余
>> 右移
<< 左移
& 按位與
| 按位或
^ 按位異或
! 邏輯非
~ 取反
盡管C允許你使用“混合模式”的表達式(包含不同類型的算術表達式),但是,在進行運算之前,它會把不同的類型轉換成同一類型(前面提到的指針運算除外)。這種自動轉換類型的過程被稱為“運算符升級(operator promotion)”。
--------------------------------------------------------------------------------
-- 作者:PrOve
-- 發布時間:2005-4-6 12:27:15
--
11.什么時候應該使用類型強制轉換(typecast)?
在兩種情況下需要使用類型強制轉換。第一種情況是改變運算分量的類型,從而使運算能正確地進行。下面的程序與2.12中的例子相似,但有不同之處。變量n被賦值為整數i除以整數j的結果,因為是整數相除,所以結果為0。變量f2也被賦值為i除以j的結果,但本例通過(float)類型強制轉換把i轉換成一個float類型,因此執行的是浮點數除法運算(見2.11),結果為0.75。
#include <stdio.h>
main ( )
{
int i = 3;
int j = 4
float f1 =i/j;
float f2= (float) i/j;
printf("3/4== %g or %g depending on the type used. \\n",f1, f2);
}
第二種情況是在指針類型和void * 類型之間進行強制轉換,從而與期望或返回void指針的函數進行正確的交接。例如,下述語句就把函數malloc()的返回值強制轉換為一個指向foo結構的指針:
struct foo *p=(struct foo *)malloc(sizeof(struct foo));
--------------------------------------------------------------------------------
-- 作者:PrOve
-- 發布時間:2005-4-6 12:27:35
--
12.什么時候不應該使用類型強制轉換(typecast)?
不應該對用const或volatile說明了的對象進行類型強制轉換,否則程序就不能正確運行。
不應該用類型強制轉換把指向一種結構類型或數據類型的指針轉換成指向另一種結構類型或數據類型的指針。在極少數需要進行這種類型強制轉換的情況下,用共用體(union)來存放有關數據能更清楚地表達程序員的意圖。
--------------------------------------------------------------------------------
-- 作者:PrOve
-- 發布時間:2005-4-6 12:28:10
--
13.可以在頭文件中說明或定義變量嗎?
被多個文件存取的全局變量可以并且應該在一個頭文件中說明,并且必須在一個源文件中定義。變量不應該在頭文件中定義,因為一個頭文件可能被多個源文件包含,而這將導致變量被多次定義。如果變量的初始化只發生一次,ANSIC標準允許變量有多次外部定義;但是,這樣做沒有任何好處,因此最好避免這樣做,以使程序有更強的可移植性。
--------------------------------------------------------------------------------
-- 作者:PrOve
-- 發布時間:2005-4-6 13:06:19
--
14.哪一種排序方法最方便?
答案是C標準庫函數qsort(),理由有以下三點:
(1)該函數是現成的;
(2)該函數是已通過調試的;
(3)該函數通常是已充分優化過的。
qsort()函數通常使用快速排序算法,該算法是由C. A.R.Hoare于1962年提出的。以下是qsort()函數的原型:
void qsort(void *buf,size_t hum,size_t size,
int(*comp)(const void *ele1,const void *ele2));
qsort()函數通過一個指針指向一個數組(buf),該數組的元素為用戶定義的數據,數組的元素個數為num,每個元素的字節長度都為size。數組元素的排序是通過調用指針comp所指向的一個函數來實現的,該函數對數組中由ele1和ele2所指向的兩個元素進行比較,并根據前者是小于、等于或大于后者而返回一個小于、等于或大于0的值。
例3.1中給出了一個函數sortStrings(),該函數就是通過qsort()函數對一個以NULL指針結束的字符串數組進行排序的。將例3.1所示的代碼和本章結尾的有關代碼一起編譯成一個可執行程序后,就能按字母順序對一個以NULL指針結束的字符串數組進行排序了。
1:#include<stdlib. h>
2:
3: /*
4: * This routine is used only by sortStrings(), to provide a
5: * string comparison {unction to pass to qsort().
6: */
7: static int comp(const void * elel, const void * ele2)
8: {
9: return strcmp( * (const char * * ) ele1,
10: * (const char * * ) ele2);
11: }
12:
13: / * Sort strings using the library function qsort() * /
14: void sortStrings(const char * array[-\'])
15: {
16, /* First, determine the length of the array * /
17: int num;
18:
19: for (num=O; array[num]; num++)
20:
21: qsort(array, num, sizeof( * array), comp) ;
22: }
在例3.1中,第19行和第20行的for循環語句用來計算傳遞給qsort()函數的數組元素個數,函數comp()的作用是將函數qsort()傳遞給它的類型(const void *)轉換為函數strcmp()
所要求的類型(const char *)。因為在函數qsort()中,ele1和ele2是指向數組元素的指針,而在例3.1中這些數組元素本身也是指針,因此,應該先將ele1和ele2轉換為const char **類型,然后在轉換結果前加上指針運算符“*”,才能得到函數strcmp()所要求的類型。
盡管有qsort()函數,但程序員經常還要自己編寫排序算法程序,其原因有這樣幾點:第一,在有些異常情況下,qsort()函數的運行速度很慢,而其它算法程序可能會快得多;第二,qsort()函數是為通用的目的編寫的,這給它帶來了一些不利之處,例如每次比較時都要通過用戶提供的一個函數指針間接調用一個函數;第三,由于數組元素的長度在程序運行時才能確定下來,因此用來在數組中移動數組元素的那部分代碼沒有針對數組元素長度相同的情況進行優化;第四,qsort()函數要求所有數據都在同一個數組中,而在實際應用中,數據的長度和性質千變萬化,可能很難甚至無法滿足這一要求;第五,qsort()函數通常不是一種穩定的排序方法。
--------------------------------------------------------------------------------
-- 作者:PrOve
-- 發布時間:2005-4-6 13:07:41
--
15.哪一種排序方法最快?
首先,對大多數包含排序應用的程序來說,排序算法的速度并不重要,因為在程序中排序 的工作量并不是很多,或者,與排序相比,程序中其它操作所花費的時間要多得多。
實際上,沒有哪一種排序算法永遠是最快的,在運行程序的軟硬件環境相同的情況下,不同排序算法的速度還與數據的長度、性質以及數據的初始順序有關。
在筆者的“工具箱”中,有三種算法在不同的情況下都是最快、最有用的,這三種算法分別是快速排序、歸并排序和基數排序。
快速排序
快速排序是一種分割處理式的排序算法,它將一個復雜的排序問題分解為若干較容易處理的排序問題,然后逐一解決。在快速排序算法中,首先要從數據集的數據中選擇一個數據作為分割值,然后將數據分成以下3個子集:
(1) 將大于分割值的數據移到分割值前面,組成子集1;
(2) 分割值本身為子集2;
(3) 將小于分割值的數據移到分割值后面,組成子集3。
等于分割值的數據可以放在任意一個子集中,這對快速排序算法沒有任何影響。
由于子集2已經是有序的,所以此后只需對子集1和子集3進行快速排序。
需要注意的是,當數據集很小時,無法進行快速排序,而要使用其它排序算法。顯然,當數據集中的數據只有兩個或更少時,就不可能將數據集再分割成三個子集。實際上,當數據集比
較小時,程序員就應該考慮是否仍然采用快速排序算法,因為在這種情況下另外一些排序算法往往更快。
例3. 2a用快速排序算法重寫了例3.1中的字符串數組排序程序,你同樣可以將它和本章末尾的有關代碼一起編譯成一個可執行程序。程序中定義了一個宏,它可使程序更易讀,并能加快執行速度。
快速排序算法是由程序中的myQsort()函數實現的,它是按升序對一個字符串數組進行排序的。函數myQsort()的具體工作過程如下:
(1)首先檢查最簡單的情況。在第17行,檢查數組中是否沒有或只有一個元素——在這種情況下,數組已經是有序的,函數就可以返回了。在第19行,檢查數組中是否只有兩個元素——在這種情況下,要么數組已經是按升序排列的,要么交換這兩個元素的位置,使它們按升序排列。
(2)在第28行至第53行,將數組分割為兩個子集:第一個子集中的數據大于或等于分割值,第二個子集中的數據小于分割值。
在第28行,選擇數組中間的元素作為分割值,并將其和數組中的第一個元素交換位置。
在第37行至第39行,在數組中找到屬于第二個子集的第一個元素;在第45行至第47行,在數組中找到屬于第一個子集的最后一個元素。
在第49行,檢查屬于第二個子集的第一個元素是否位于屬于第一個子集的最后一個元素的后面,如果是,則第一個子集的所有元素都已在第二個子集的所有元素的前面,數據已經劃分好了;否則,交換這兩個元素的位置,然后重復上述這種檢查。
(3)當兩個子集分割完畢后,在第55行,將分割值和第一個子集中的最后一個元素交換位置,排序結束時這個分割值將仍然排在現在這個位置。在第57行和第58行,分別調用myQsort()函數對分割所得的子集進行排序。當所有的子集都經過排序后,整個數組也就排好序了。
例一個不使用qsort()函數的快速排序算法程序
1: #include <stdlib.h>
2:
3: #define exchange(A, B, T) ((T) = (A), (A) = (B),(B)=(T))
4:
5:
6: / * Sorts an array of strings using quick sort algorithm * /
7: static void myQsort(const char * array[], size_t num)
8: {
9: const char * temp
10: size_t i, j;
11:
12: /*
13: * Check the simple cases first:
14: * If fewer than 2 elements, already sorted
15: * If exactly 2 elements, just swap them (if needed).
16: * /
17: if (num <2)
18: return;
19: else if (num==2)
20: {
21: if (strcmp(array[O], array[1])>O)
22: exchange (array[0], array[1] ,temp)
23: }
24: / *
25: * Partition the array using the middle (num/2)
26: element as the dividing element.
27: * /
28: exchange (array[0], array[num / 2], temp)
29: i=1;
30: j=num;
31: for (; ;)
32: {
33: / *
34: * Sweep forward until and element is found that
35: * belongs in the second partition.
36: * /
37: while (i<j && strcmp (array, array[0])
38: <=0)
39: i++;
40: / *
41: * Then sweep backward until an element
42: * is found that belongs in the first
43: * partition.
44: * /
45: while (i<j&& strcmp(array[j-1], array[O]
46: >=0)
47: j--;
48: / * If no out-of-place elements, you\'re done * /
49: if (i>=j)
50: break
51: / * Else, swap the two out-of-place elements * /
52: exchange(array, array[j-l], temp)
53: }
54: / * Restore dividing element * /
55: exchange(array[O], array[i-1], temp)
56: / * Now apply quick sort to each partition * /
57: myQsort (array, i-1 )
58: myQsort (array + i, num-i)
59: }
60:
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -