2015-11-21 79 views
1

所以我認爲問題在於獲取ref數組中的參考數字作爲字符串並將其轉換爲整數以轉換爲整數數組結果,並將其複製到頁面數組。由於我得到了分段錯誤11,我正在經歷一個數組的界限。不知道如何解決這個問題。C程序給我分段錯誤11

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <string.h> 
#include <ctype.h> 


int main() 
{ 

    char ref[30];// array that holds reference string 
    int frame_size;// maximum number of frames is 8 
    // a frame holds a number thats in the reference stream. 
    int optimal_fault =0; 
    int lru_fault =0;// least recently used faults 
    int mfu_fault =0;// most frequently used faults 
    int lfu_fault =0;// least frequently used faults  
    int pages = 0;//counts how many times you've looped 
    //int page=0;//this will be the pages array 
    printf(" Please enter reference string: "); 


    fgets(ref, 30, stdin); 
    int num; 

    //printf("reference: %c", &ref); 
    printf(" Please enter the number of frames(no more than 8 allowed)\n"); 

    scanf("%d",&frame_size); 

    int len = strlen(ref); 
    int results[len]; 
    int page[len]; 
    int k=0; 


    printf("len: %d:",len); 
    for(int i=0; ref[i]!= '\0'; i++) 
    { 
    if(isdigit(ref[i])) 
    { 
     num = sscanf(&ref[i], "%d", &results[i]); 
     printf("results: %d\n", results[i]); 
     page[k] = results[i]; 
     printf("page: %d\n", page[k]); 
     k++; 
     i++; 
    } 

    } 
    return 0; 
} 
+1

你正在循環體內再次增加'i ++'*兩次*,一次在'for'語句中。如果字符串長度是奇數,那麼你會錯過控制循環的''\ 0''終止符。 –

+0

沒有這不是問題的第二個i ++是那裏的參考字符串格式。因爲它可以是1 2 3 23,如果我把i ++取出來,它不會看到23它會看到1 2 3 2 3 @WeatherVane –

+0

如果你遇到了分段錯誤,用Valgrind或Dr. Memory運行它。這兩個程序都會告訴你哪行代碼非法訪問內存。 –

回答

1

我很高興通過你的程序有問題的工作,但你需要有一個開放的心態,願意嘗試修復我引起的問題。我會識別錯誤。你做出明顯的改變,並進行測試。我幾乎可以肯定你的錯誤會在這個過程中消失。如果他們不這樣做,發佈更新與您所做的並ping我的變化的問題,我們會從那裏工作......


首先,讓我們考慮這將如何執行時,提供了一個字符串,如"0"

預計i將這個字符串時就會增加,因爲只有一個在它的性格,因此,循環如下所示:for(int i=0; ref[i]!= '\0'; i++) ......我們沒有理由相信這個代碼將增加超過一次i更多的這一點,對嗎?

然而,你的代碼的增量再次在這裏:

if(isdigit(ref[i])) 
{ 
    /* SNIP */ 
    i++; // <--- ERROR HERE! 
} 

你的代碼,因爲它增加了太多次跳過字符串終止'\0'字節。它跳出數組的末尾,調用未定義的行爲。期望這可能導致段錯誤是現實的,但是因爲它是UB沒有要求。


isdigit預計其參數爲unsigned charEOF;任何負值不是EOFmight cause assertion errors。也許你的意思是寫:if(isdigit((unsigned char)ref[i]))


int len = strlen(ref); 
int results[len]; 
int page[len]; 

一開始,strlen返回size_t。如果源值位於目標類型範圍之外,則從無符號到有符號整數類型的轉換會導致實現定義的行爲。該實現定義的行爲可能(理論上)包括陷阱表示,這可能會引發陷阱(即段錯誤)。

此外,你是否認爲當len爲0(例如你有一個空字符串)時,你聲明的是0大小的數組?根據the C standard這是未定義的行爲。

...每次評估時,它的值應大於零。

也許你的意思是寫這樣的事:

size_t len = strlen(ref); 
if (len == 0) { 
    puts("ref is too small! This field must be at least one byte..."); 
    return 0; 
} 
int results[len]; 
int page[len]; 
printf("len: %zu:",len); // NOTE: %zu causes printf to print a size_t; don't use %d for that. 

考慮使用size_t爲表示尺寸的其他變量,如ik,爲int可以繞到負值(這是一個未定義行爲的後果,所以技術上可能會崩潰或更糟)。你不希望results[i]i是負面的,你會嗎? (不是ref可以有很多字節,在此代碼)


int main()不被認爲是標準C.一個有效的切入點,你應該使用int main(void),它指定的主入口點函數沒有參數,與您所使用的不同,它指定主入口點採用未指定類型的未指定數量的參數。這個錯誤有時會導致段錯誤,可以通過編譯這兩個方案來證明:

int main() { 
    main(42, "hello", -1.0); // WHAT?! main() can accept three arguments?! 
} 

 

int main(void) { 
    main(42, "hello", -1.0); // Note the compiler error... 
} 

再次,這是UB所以沒有要求。可惜我找不到任何鏈接在我花了十分鐘的時間搜索,但是我確定我已經看到了一個這樣的實例,在程序終止時引起段錯誤。


你應該(幾乎)經常檢查scanf返回值。scanf("%d",&frame_size);不保證成功,因此不能保證frame_size將包含一個理智的價值。話雖如此,frame_size似乎並沒有在這裏的任何邏輯中使用。如果您需要讀取並丟棄stdinint值,則可以使用scanf("%*d");來完成。這是您(很可能)不需要檢查返回值的唯一情況。

這也適用於sscanf我注意到你在這裏保存了sscanf的返回值:num = sscanf(&ref[i], "%d", &results[i]); ...但是,你沒有做任何事情!因此,您不能保證results[i]包含理智的價值。這樣的恥辱......

num = sscanf(&ref[i], "%d", &results[i]); 
if (num != 1) { 
    continue; 
}