原文:「c語言 多重排序」html
原代碼:程序員
#include<stdio.h>
#include<string.h>
struct A
{
char name[100];
int gread;
} stu[100];
void fact(int n)
{
int i,j,teap;
char w[100];
for(i=1;i<=n;i++)
for(j=2;j<=n;j++)
{
if(stu[j-1].gread>stu[j].gread)
teap=stu[j-1].gread,stu[j-1].gread=stu[j].gread,stu[j].gread=teap;
else
{
if(strcmp(stu[j-1].name,stu[j].name)>0)
strcpy(w,stu[j-1].name),strcpy(stu[j-1].name,stu[j].name),strcpy(stu[j].name,w);
}
}
}
int main( void )
{
int n,i;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%s",&stu[i].name);
scanf("%d",&stu[i].gread);
}
fact(n);
for(i=1;i<=n;i++)
printf("%s\n",stu[i].name);
return 0;
}
原代碼格式很亂,多是做者初學,也多是由於不懂得如何排版,這裏從新排了一下。數組
首先, 函數
struct A { char name[100]; int gread; } stu[100];
這明顯是譚氏代碼的垃圾寫法,在譚書中處處都有這種垃圾寫法。特色是不假思索地順手就定義外部變量,頃刻間就把代碼的結構毀於一旦。測試
這個外部變量非但毀了代碼的結構,並且廢了fact()函數。使得fact()函數只能用於這個特定的外部數組。這種不具有必定通用性的函數是不合格的函數。spa
這種寫法徹底是爲了圖省事,在聲明結構體類型的同時直接定義變量,之後就不用再寫一遍雍長的結構體類型的名字了。初學者很難理解這種圖省事的方式有什麼很差,由於感受這很方便。這就是譚書給初學者帶來的隱蔽毒害,讓初學者很開心地掉入譚書挖的大坑。code
實際上這種方便就如同把衛生間裏用的手紙不但放在了衛生間,同時也放到客廳、餐廳、臥室和廚房同樣,不管在客廳仍是在餐廳、臥室和廚房只要有了便意,馬上就能夠拿到手紙。會不會也有人以爲也很方便呢?htm
並非絕對不能使用外部變量,就如同並不是絕對不能使用goto語句同樣。但高手對使用這種可能傷人又害己的「七傷拳」老是慎之又慎的。只有在無可奈何、有充分理由的前提下才動用這種武器。blog
濫用外部變量就如同把程序的代碼都寫在一個main()中同樣,是初學者常見的幼稚病。而從程序效率方面來講,濫用外部變量還不如把全部代碼都寫在main()當中。排序
通常來講,變量應該定義在局部,只要可能,越局部越好。對於目前這個問題而言,stu數組應該定義在main()之中。
此外,struct的tag——A,這名字實在是太過隨意了,也是譚氏風格。
int n,i;
這個 i 壓根不該該出如今main()中。
scanf("%d",&n);
這種赤裸裸的scanf()也是初學者代碼中常見的毛病。寫成下面樣子比較好:
puts("請輸入人數"); scanf("%d",&n);
for(i=1;i<=n;i++) { scanf("%s",&stu[i].name); scanf("%d",&stu[i].gread); }
這段問題較多。
首先,數組下標應該是從0開始的,但這裏數組的下標倒是從1開始的;
其次專業程序員的for語句通常這樣寫
for( i = 0 ; i < n ; i++ )
第三,這段代碼寫成一個函數爲好。
fact(n);
感受這個函數的功能是排序,但名字竟然是「fact」,實在使人莫名其妙。前面結構體的成員名gread一樣使人困惑不解。英文很差,能夠用漢語拼音,不丟人。一些四不像的英語才丟人。可是提及來很奇怪,有很多假洋鬼子反對用漢語拼音作標識符,但他們對那種蹩腳的、錯誤連篇的英文(好比老譚書中的)卻歷來一聲不吭。那是一羣很奇怪的動物,他們反對使用國家法定的母語拼音,但不反對使用垃圾甚至錯誤的非母語。
這個函數的參數也不完整。它是要對數組排序,卻沒有數組名這個實參。這也是外部變量惹的禍。這樣的函數沒有什麼實用價值,一點可複用性都談不上。若是問題中另有一個數組須要排序,難道再寫一個函數不成?
因爲這個函數要完成所謂的「多重排序」,因此它的比較規則要更加複雜。所以還應該有第三個參數——一個用於比較的函數做爲參數。
void fact(int n) { int i,j,teap; char w[100]; for(i=1;i<=n;i++) for(j=2;j<=n;j++) { if(stu[j-1].gread>stu[j].gread) teap=stu[j-1].gread,stu[j-1].gread=stu[j].gread,stu[j].gread=teap; else { if(strcmp(stu[j-1].name,stu[j].name)>0) strcpy(w,stu[j-1].name),strcpy(stu[j-1].name,stu[j].name),strcpy(stu[j].name,w); } } }
這個函數定義被寫在了調用以前,從而沒有寫函數類型聲明。這也是一種偷懶的寫法,貪小便宜。不管把函數定義寫在哪裏都應該寫函數類型聲明。
int i,j,teap;
teap這個標識符也很詭異,歷來沒見過這個單詞。
for(i=1;i<=n;i++)
這個屬於一錯再錯,結果是負負得正,歪打正着。
teap=stu[j-1].gread,stu[j-1].gread=stu[j].gread,stu[j].gread=teap; strcpy(w,stu[j-1].name),strcpy(stu[j-1].name,stu[j].name),strcpy(stu[j].name,w);
這種寫法很垃圾,是對逗號運算的濫用。它除了使代碼變模糊以外,沒有任何好處。不但害人,並且害己。由於不但別人難以看懂,本身也難以看明白。一旦這裏有錯,哭都來不及。
此外這應該用函數完成,而不是在當地寫。
if(stu[j-1].gread>stu[j].gread) teap=stu[j-1].gread,stu[j-1].gread=stu[j].gread,stu[j].gread=teap; else { if(strcmp(stu[j-1].name,stu[j].name)>0) strcpy(w,stu[j-1].name),strcpy(stu[j-1].name,stu[j].name),strcpy(stu[j].name,w); }
這個邏輯是錯誤的。由於按照第二個指標比較的前提是第一個指標相同。而else部分則包括了前一個元素的第一指標小於第二個元素的第一指標的情形(即stu[j-1].gread<=stu[j].gread的狀況)。
另外一個讓人感受詭異的是,這裏的代碼只交換告終構體變量的成員,而不是交換整個結構體變量。不知道這表達的是什麼邏輯。
for(j=2;j<=n;j++)
感受是在寫冒泡法排序,但這個「j<=n」代表冒泡法還沒學懂。
最後,main()中的
for(i=1;i<=n;i++) printf("%s\n",stu[i].name);
錯誤同前。這裏只輸出name成員也不對,這根本沒法測試程序是否完成了功能。此外這段也應該寫成一個函數。
下面是重構的代碼。
#include<stdio.h> #include<string.h>
struct xuesheng { char xingming[100] ; int chengji ; } ; void shuru( struct xuesheng [] , int ); void shuchu( struct xuesheng [] , int ); void paixu( struct xuesheng [] , int , int (*)( struct xuesheng , struct xuesheng ) ); void jiaohuan( struct xuesheng * , struct xuesheng * ); int dayu( struct xuesheng , struct xuesheng ); int main( void ) { int renshu ; struct xuesheng ban[100] ; puts("請輸入人數"); scanf("%d",& renshu ); shuru( ban , renshu ); paixu( ban , renshu , dayu ); shuchu( ban , renshu ); return 0; } int dayu( struct xuesheng xs1 , struct xuesheng xs2 ) { if ( xs1.chengji > xs2.chengji ) { return 1; } if ( xs1.chengji < xs2.chengji ) { return -1; } if ( xs1.chengji == xs2.chengji ) { return strcmp(xs1.xingming ,xs2.xingming ); } } void jiaohuan(struct xuesheng * p1 , struct xuesheng * p2 ) { struct xuesheng tmp = * p1 ; * p1 = * p2 ; * p2 = tmp ; } void paixu( struct xuesheng b[] , int rs , int (*dy)( struct xuesheng , struct xuesheng ) ) { int i ; for ( i = 1 ; i < rs ; i ++ ) { int j ; for ( j = 0 ; j < rs - i ; j ++ ) { if ( dy( b[ j ] , b[ j + 1 ] ) == 1 ) { jiaohuan( &b[j] , &b[j+1] ); } } } } void shuchu( struct xuesheng b[] , int rs ) { int i ; for ( i = 0 ;i < rs ; i++ ) { printf("%s ", b[i].xingming); printf("%d \n" ,b[i].chengji); } } void shuru ( struct xuesheng b[] , int rs ) { int i ; for ( i = 0 ;i < rs ; i++ ) { puts("姓名?"); scanf("%s",b[i].xingming); puts("成績?"); scanf("%d",&b[i].chengji); } }