无知乱吃药
據說,聯合國曾提出過一個口號:“不要死于無知”。無知的一種情況就是只知道“對癥下藥”,卻不知道很多藥物都有各自的禁忌,比如孕婦忌用,高血壓忌服等等。不顧禁忌亂吃藥,即使對癥也會造成對身體的傷害。
寫代碼也是如此,僅僅知道函數的功能是遠遠不夠的,還必須知道什么情況下函數在什么情況下能使用什么情況下不能使用。比如說,你不能用sqrt()函數去求一個負數的平方根。下面的代碼中,就存在著類似的錯誤。
View Code #include <stdio.h>#include <string.h>
#define N 10
int main( void )
{/*……*/
void sort(int num[],char name[][8]);
int num[N]
char name[N][8];
/*……*/
sort(num,name);
/*……*/
return 0;
}
void sort(int num[],char name[N][8])
{int i,j,min,temp1;
char temp2[8];
for(i=0;i<N-1;i++)
{min=i;
for(j=i;j<N;j++)
if(num[min]>num[j])min=j;
temp2=num[i];
strcpy(temp2,name[i]);
num[i]=num[min];
strcpy(name[i],name[min]);
num[min]=temp1;
strcpy(name[min],temp2);
}
printf("\n result:\n");
for(i=0;i<N;i++)
printf("\n %5d%10s",num[i],name[i]);
}
——譚浩強 ,《C程序設計(第四版)學習輔導》,清華大學出版社,2010年7月,p92
這段代碼的毛病很多。包括sort()函數夾帶輸出功能,sort()函數參數不完整等等等等。為了便于閱讀查找錯誤,首先把這些極為刺眼的毛病改掉。
View Code #include <stdio.h>#include <string.h>
#define N 10
void sort (int num[],char name[][8],int);
void output(int num[],char name[][8],int);
int main( void )
{
int num[N]
char name[N][8];
/*……*/
sort(num,name,N);
output(num,name,N);
/*……*/
return 0;
}
void sort(int num[],char name[][8],int size)
{
int i,j,min,temp1;
char temp2[8];
for( i = 0 ; i < size-1 ; i++)
{
min=i;
for( j = i ; j< size ; j++ )
if(num[min]>num[j])
min=j;
temp2=num[i];
num[i]=num[min];
num[min]=temp1;
strcpy(temp2,name[i]);
strcpy(name[i],name[min]);
strcpy(name[min],temp2);
}
}
修改后的代碼中依然保留著原來就有的錯誤。這個錯誤就是
strcpy(name[i],name[min]);
這條語句。
為什么說這條語句是錯誤的呢?因為從代碼中不難看到,min可能與i的值相同,在min與i值相等的情況下,就成了字符串向自身拷貝自身,這時strcpy()函數調用就是一個錯誤的調用,它違背了使用strcpy()函數的禁忌——源字符串不可與目標字符串重疊。
在C89中對strcpy()函數是這樣描述的:
char *strcpy(char *sl, const char *s2);
strcpy()函數拷貝s2所指向的字符串(含結尾的null字符)至s1指向的數組。如果兩個對象重疊(overlap),函數行為是未定義的(undefined)。
未定義行為的代碼就是一種錯誤的代碼,也就是說使用strcpy()函數的前提條件是目標字符串與源字符串之間不可以有重疊,否則代碼就是錯誤的代碼。在兩個對象存在重疊時使用strcpy()就和無知地不顧藥物禁忌亂吃藥一樣荒唐。
在C99中,用了一個新的關鍵字——restrict來明確地表明strcpy()函數的使用前提條件是不容許重疊:
char *strcpy(char * restrict s1,const char * restrict s2);
這里的restrict的含義是s1和s2這兩個指針是訪問它們所指向的對象的唯一途徑或手段。
如果兩個字符串有重疊,應該使用memmove()函數而不能使用strcpy()函數。當然,就前面的代碼而言,不使用memmove()函數也可以避免這個錯誤。只需將sort()做如下改動即可:
void sort(int num[],char name[][8],int size) {int i,j,min,temp1;char temp2[8];for( i = 0 ; i < size-1 ; i++){min=i;for( j = i ; j< size ; j++ )if(num[min]>num[j])min=j;if( min != i ) {temp2=num[i];num[i]=num[min];num[min]=temp1; strcpy(temp2,name[i]);strcpy(name[i],name[min]); strcpy(name[min],temp2);} } }?
總結
- 上一篇: (android硬件应用实战)摄像头拍照
- 下一篇: linux ssh密钥认证