正確(AC: Accept 即表示程序通過)
恭喜你了
答案錯誤(Wrong Answer)
答案不對,僅僅通過樣例數據的測試並不一定是正確答案。如果你的程序有錯誤自然只能改正后再交。
但是初學者還有一個常見的錯誤是計算結果已經正確了,但是輸出格式不按樣例來導致錯誤。
本學校OJ上一個結果如下:
263281 | 1505020241 |
C
|
答案錯誤 |
1084
|
1
|
C/Edit | 243 B | 2015-11-25 17:18:29 |
點擊答案的地方可以一定程度上幫助你發現問題所在。
例如看到下面的信息:
=================/test.out Right: 8 ----------------- Your: p=8 =================
很明顯這位同學畫蛇添足,多輸出了"p="
再如下面的結果,明顯搞錯了大小寫。
=================/harmonious.out Right: triangle ----------------- Your: Triangle =================
編譯錯誤 (Compile Error Error,簡稱CE)
246070 | 1505020146 |
C
|
編譯錯誤(點擊看詳細) |
0
|
0
|
C/Edit | 432 B | 2015-11-07 17:00:10 |
提交可以看到上面的結果,可以在 編譯錯誤(點擊看詳細) 點擊看到更詳細的信息。
犯這種錯誤的原因一般有:
1. 你在本地(就是你的編程環境下)都沒有編譯成功就直接提交了,這種做法是錯誤的。必須本地編譯通過,而且要運行通過了你的樣例和額外的測試數據后才能交
2. 你本地的程序正確,但是你提交時的拷貝漏掉了一些內容
3. 編譯器選擇錯誤。在提交(submit)時可以選擇C/C++/JAVA編譯器,選擇錯了有時候會導致編譯錯誤。大部分情況下,C程序選擇C或C++編譯器都沒有問題。但是C++程序選擇C編譯器一般都會有問題。
4. 編譯器不兼容。你本地的程序編譯通過,但是你的程序提交到服務器,服務器的編譯器跟你的不兼容,導致你的程序編譯出錯。一般說來,這種情況比較少見
格式錯誤 (Presentation Error,簡稱PE)
這種情況下一般意味着數據都對了。但是可能多了/少了空格, 或者多了/少了 換行。
示例一:實驗三問題 B: 最大數與最小數之差, 下面的代碼明顯多出了一個空格
1 printf("%d \n",max-min);
示例二:實驗四問題 H: 兩數之和。 注意從第9行跳至第16行,會多一次換行。
1 while (scanf ("%d %d",&sum,&n)!=EOF) 2 { 3 for (...) 4 { 5 for (.....) 6 { 7 if (...) 8 { 9 printf ("%d %d\n",a,b); 10 goto out; 11 } 12 } 13 14 } 15 printf ("No Solution"); 16 out: 17 ; 18 printf ("\n");
示例三: 實驗五問題 D: 實驗4-1:編求素數的函數,題目要求是“多個結果之間由空行隔開”,樣例也非常清晰,但是有些同學就是無視於此,忘記空行,導致PE錯誤。
時間超限 (TLE,Time Limit Exceeded,超時)
每一個程序給了一個時間限制,最常見的是1秒,如果你的程序在規定時間內沒有運行完畢,可能就會得到一個TLE.
導致TLE的主要原因有:
1. 你程序所用的方法不夠快,運行效率低,導致超時。
OJ上通常10^8規模的計算就需要1s,如果你的循環體運行總數 * 測試數據數量達到了該數量級,你的程序很可能超時。
典型的例子如實驗四的質數分解,有些同學還適用如下低效率的做法導致超時。更好的做法是 i *i <=n
for(i=2;i<n;i++){
if(n%i==0)
break;
}
2. 你的程序出現了死循環。
例如實驗二B, 有同學試圖用循環來做,很遺憾的 循環結束條件!='\0'寫錯了,程序一直運行導致TLE.
for (i=0;getchar()!='\0';i++);
輸出超限(Output Limit Exceeded)
一般是輸入控制沒有處理好,更少見的情況是涉及輸出的地方沒有控制好(如死循環);最終導致輸出的信息過多超出了限制。
問題 G: 進制轉換
題目描述
給出一個十進制的正整數,輸出它的二進制表示。
輸入
有多行數據,每一行一個正整數,整數值在[1-100000000]之間。
輸出
輸出相應的二進制數.每一行輸出對應每一行輸入
樣例輸入
樣例輸出
1 int main() 2 { 3 int n,a; 4 int p[31]; 5 for (;scanf ("%d",&n);) 6 { 7 8 ... 9 while (j--) 10 printf ("%d",p[j]); 11 printf ("\n"); 12 13 } 14 return 0; 15 }
原因非常簡單,正確的控制應該是
問題 C: 實驗4-3:編求階乘的函數
輸入
每行輸入一組測試數據:2個正整數m和n。m與n均為非負整數。
m和n均為0時,結束輸入。
輸出
...
樣例輸入
下面的代碼會產生輸出超限
1 int main() 2 { 3 int m, n; 4 float y; 5 while(scanf("%d%d", &m, &n) != EOF) { 6 if(m == 0 && n == 0) 7 break; 8 printf(...); 9 }
錯誤的原因是兩個%d之間缺了一個逗號,但為什么會導致輸出超限呢?因為輸入的逗號scanf無法接收,scanf的輸入流一直處於錯誤狀態,所以無法繼續接收下面的數據。
比如輸入"11,10", m的結果是10,但隨后的逗號scanf無法處理,出錯,n此時的值是隨機值。 scanf返回1,不等於EOF.第5行為真,執行第8行。然后回到第5行,此時,輸入流處於錯誤狀態,scanf只會返回0,依然不等於EOF,繼續為真,又執行第8行,如此往復輸出導致輸出超限。感興趣的同學可以用下面的代碼運行然后輸入"11,10"
1 #include <stdio.h> 2 int main() 3 { 4 int m, n; 5 6 int ret; 7 while((ret =scanf("%d%d", &m, &n)) != EOF) { 8 if(m == 0 && n == 0) 9 break; 10 printf("%d %d %d\n",ret, m, n); 11 } 12 return 0; 13 }
再給出一段scanf的說明
“When a matching failure occurs, scanf
returns immediately, leaving the first non-matching character as the next character to be read from the stream. The normal return value from scanf
is the number of values that were assigned, so you can use this to determine if a matching error happened before all the expected values were read.”
在HUST OJ, 如果你的輸出到了標准輸出的兩倍就會產生該錯誤,筆者曾經有一個程序因為溢出錯誤導致了很大的整數輸出,正確的答案是數據規模很小,最后judge判題的結果是輸出超限,而不是wrong answer。
Runtime Error (RE) : 運行時錯誤
這個一般是程序在運行期間執行了非法的操作造成的。下面是常見的錯誤類型:
1. 數組下標越界或指針指向無效地址
學校OJ的輔助信息有
“Runtime Error:Segmentation fault
Segmentation fault:段錯誤,檢查是否有數組越界,指針異常,訪問到不應該訪問的內存區域”
有時候,還有如下的輔助信息
“
Runtime Error:[ERROR] A Not allowed system call: runid:262244 callid:20 TO FIX THIS , ask admin to add the CALLID into corresponding LANG_XXV[] located at okcalls32/64.h ,and recompile judge_client
A Not allowed system call: runid:262244 :使用了系統禁止的操作系統調用,看看是否越權訪問了文件或進程等資源”
示例代碼1, 第二行n應該是&n(指針類型).
1 int n, h, i, s; 2 scanf("%d",n);
示例代碼2, 這個代碼更為詭異,scanf多一個%d,會導致指針誤用,但是CB在編譯時可以提供警告,被同學放過了。
1 int a,b,c,n; 2 3 scanf("%d",&n); 4 while(n>0) 5 { 6 scanf("%d%d%d%d",&a,&b,&c);
示例代碼3, 下面代碼的問題在於第一行的數組開小了,如果n比較大, i的值絕對會超過9。
1 int n, a[10] = {0}, i; 2 i = 0; 3 do 4 { 5 a[i++] = n % 2; 6 n = n / 2; 7 } while(n > 0);
再如下面的代碼,n無初值,當然可能越界。
1 int n,i; 2 int fib[40] = {1,1}; 3 for(i=2; i<n; i++) 4 { 5 fib[i] = fib[i-1]+fib[i-2]; 6 }
2. 除以0
學校OJ的輔助信息有
“Runtime Error:Floating point exception
Floating point exception:浮點錯誤,檢查是否有除以零的情況”
如下的示例代碼,第3行j=2應該是i=2, 所以i沒有賦初值(可能是負的,也可能是0)。總而言之,第4行就有i值為0的可能,除0的情況就出現了。
1 int i,j; 2 scanf("%d",&j); 3 for(j = 2; i * i <= j; i ++) 4 if(!(j%i)) 5 { 6 break; 7 }
3. 開了大數組
示例如下,數組太大了,函數內的數組建議空間不要超過2MB,實在需要大數組可以定義在函數的外面。
1 int main() 2 { 3 int a[10000000], m, n, x, i = 0; 4 5 return 0; 6 }
4. 遞歸導致的棧溢出
下例是求斐波那契數列的代碼,但是第12行的輸入不符合要求,導致-1也會處理,fib(-1)會導致遞歸反復進行下去耗盡棧空間
輸入
輸入包括若干行,每行輸入一個正整數n,若輸入-1則結束。
輸出
對於每行輸入的n的值,對應輸出f(n),每個輸出單獨占一行。若輸入是-1,則不輸出任何結果。
樣例輸入
1 #include <stdio.h> 2 int fib(int n) 3 { 4 if(n == 0 || n == 1) 5 return 1; 6 else 7 return fib(n-1)+fib(n-2); 8 } 9 int main (void) 10 { 11 int n; 12 while(scanf("%d",&n) != EOF) 13 printf("%d\n",fib(n-1)); 14 return 0; 15 }
5 調用庫函數但不滿足前提條件
例如兩次調用棧的pop函數,但是第二次調用之前已經是空棧。
6 嫁接的錯誤
非常少見,但是有可能。HUST OJ因為是TLE,反而報出了RE
ACCESS_VIOLATION 您的程序想從一些非法的地址空間讀取或向其中寫入內容。一般例如指針、數組下標越界都會造成這個錯誤的。
ARRAY_BOUNDS_EXCEEDED 您的程序試圖訪問一個超出硬件支持范圍的數組單元。 FLOAT_DENORMAL_OPERAND 進行了一個非正常的浮點操作。一般是由於一個非正常的浮點數參與了浮點操作所引起的,比如這個數的浮點格式不正確。 FLOAT_DIVIDE_BY_ZERO 浮點數除法出現除數為零的異常。
FLOAT_OVERFLOW 浮點溢出。要表示的數太大,超出了浮點數的表示范圍。 FLOAT_UNDERFLOW 浮點下溢。要表示的數太小,超出了浮點數的表示范圍。 INTEGER_DIVIDE_BY_ZERO 在進行整數除法的時候出現了除數為零的異常。 INTEGER_OVERFLOW 整數溢出。要表示的數值太大,超出了整數變量的范圍。
STACK_OVERFLOW 棧溢出。一般是由於無限遞歸或者在函數里使用了太大的數組變量的原因。
...... 其他錯誤,包括C++標准庫/STL運行時庫錯誤等,這里不再舉例。