2010-10-09 42 views
3

我試圖編寫一個程序,它接受一個純文本文件作爲它的參數並解析它,將所有數字加在一起,然後打印出總和。下面是我的代碼:爲什麼我會收到分段錯誤?

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

static int sumNumbers(char filename[]) 
{ 
    int sum = 0; 
    FILE *file = fopen(filename, "r"); 
    char *str; 

    while (fgets(str, sizeof BUFSIZ, file)) 
    { 
     while (*str != '\0') 
     { 
      if (isdigit(*str)) 
      { 
       sum += atoi(str); 
       str++; 
       while (isdigit(*str)) 
        str++; 
       continue; 
      } 
      str++; 
     } 
    } 

    fclose(file); 

    return sum; 
} 

int main(int argc, char *argv[]) 
{ 
    if (argc != 2) 
    { 
     fprintf(stderr, "Please enter the filename as the argument.\n"); 
     exit(EXIT_FAILURE); 
    } 
    else 
    { 
     printf("The sum of all the numbers in the file is : %d\n", sumNumbers(argv[1])); 
     exit(EXIT_SUCCESS); 
    } 

    return 0; 
} 

而且我使用的文本文件是:

這是一個很無聊的文本文件 一些隨機數在整個它散 。

這裏是一個:87,這裏是另一個:3

最後的最後兩個數字:12 19381.完成。唷。

當我編譯並嘗試運行它時,出現分段錯誤。

回答

14

您尚未爲緩衝區分配空間。
指針str只是一個懸掛指針。因此,您的程序將從文件中讀取的數據有效地轉儲到您不擁有的內存位置,從而導致分段錯誤。

您需要:

char *str; 
str = malloc(BUFSIZ); // this is missing..also free() the mem once done using it. 

或者只是:

char str[BUFSIZ]; // but then you can't do str++, you'll have to use another 
        // pointer say char *ptr = str; and use it in place of str. 

編輯:

有一個在另一個bug:

while (fgets(str, sizeof BUFSIZ, file)) 

第二個參數應該是BUFSIZ而不是sizeof BUFSIZ

爲什麼?

因爲第二個參數是要讀入包含空字符的緩衝區的最大字符數。由於sizeof BUFSIZ4,所以您可以讀取最多達到3 char的緩衝區。這就是爲什麼19381被讀作193,然後是81<space>的原因。

+0

嘿感謝現在的工作。但如果你不介意再忍受一段時間。如果在修復程序後嘗試運行程序,出於某種原因'atoi()'將數字'19381'分別解析爲'193'和'81'。任何想法爲什麼發生這種情況 – jon2512chua 2010-10-09 15:41:20

+0

@Jon:更新了答案:) – codaddict 2010-10-09 15:57:22

+0

Owh我現在看到了,謝謝! :) – jon2512chua 2010-10-09 16:12:23

2

因爲您尚未爲緩衝區分配空間。

3

您尚未分配任何內存來填充strfgets將緩衝區作爲其第一個參數,而不是未分配的指針。

而不是你需要定義一個合理大小的緩衝區,比方說char *str;char str[BUFSIZ];

1

您已經聲明的char *海峽,但你沒有留出它的內存,只是還沒有。你將需要爲它的malloc內存。

許多內存相關的錯誤,如這個可以很容易地找到valgrind。我強烈建議使用它作爲調試工具。

1
char *str; 

str沒有爲其分配內存。使用malloc()爲它分配一些內存,或者用一個預定義的大小聲明它。

char str[MAX_SIZE]; 
2

許多人已經解決了您詢問的問題,但我有一個問題作爲回報。究竟你認爲這完成:

 if (isdigit(*str)) 
     { 
      if (isdigit(*str)) 
      { 
       sum += atoi(str); 
       str++; 
       while (isdigit(*str)) 
        str++; 
       continue; 
      } 
     } 

什麼應該是兩個連續if語句完全相同的條件呢? (注意備案:任何一個都沒有else條款)。

+0

不錯的捕獲... + 1超越明顯= + – 2010-10-09 15:35:05

+0

對不起,這是一個錯字。一定是太累了。 – jon2512chua 2010-10-09 15:42:10

1

你的程序有幾個錯誤:

  • 它不能正確處理長行。當您讀取某個大小的緩衝區時,可能會發生某些編號從緩衝區的末尾開始並在下一個緩衝區的開始處繼續。例如,如果您的緩衝區大小爲4,則可能會有輸入The |numb|er 1|2345| is |larg|e.,其中垂直線指示緩衝區的內容。然後你會分別計算1和2345。
  • 它以char作爲參數調用isdigit。只要您閱讀任何「大」字符(大於SCHAR_MAX行爲未定義。你的程序可能會崩潰或產生不正確的結果或做任何想做的事情。要解決這個問題,您必須首先將該值轉換爲unsigned char,例如isdigit((unsigned char) *str)。或者,如在我的代碼中,您可以將fgetc函數的值作爲isdigit保證爲有效參數。
  • 您可以使用需要緩衝區的功能(fgets),但無法分配緩衝區。正如其他人指出的那樣,獲取緩衝區的最簡單方法是聲明本地變量char buffer[BUFSIZ]
  • 您使用str變量有兩個目的:保存緩衝區的地址(在整個執行時間內應保持不變)和用於分析文本(在執行過程中會更改)的指針。做出這兩個變量。我會稱它們爲bufferp指針的縮寫)。

這裏是我的代碼:

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

static int sumNumbers(const char *filename) 
{ 
    int sum, num, c; 
    FILE *f; 

    if ((f = fopen(filename, "r")) == NULL) { 
     /* TODO: insert error handling here. */ 
    } 

    sum = 0; 
    num = 0; 
    while ((c = fgetc(f)) != EOF) { 
     if (isdigit(c)) { 
      num = 10 * num + (c - '0'); 
     } else if (num != 0) { 
      sum += num; 
      num = 0; 
     } 
    } 

    if (fclose(f) != 0) { 
     /* TODO: insert error handling here. */ 
    } 

    return sum; 
} 

int main(int argc, char **argv) { 
    int i; 

    for (i = 1; i < argc; i++) 
     printf("%d\t%s\n", sumNumbers(argv[i]), argv[i]); 
    return 0; 
} 
+0

感謝您的好評!欣賞它! :) – jon2512chua 2010-10-09 16:23:05

0

這裏是一個功能,那你的工作:

static int sumNumbers(char* filename) { 
    int sum = 0; 
    FILE *file = fopen(filename, "r"); 
    char buf[BUFSIZ], *str; 

    while (fgets(buf, BUFSIZ, file)) 
    { 
      str=buf; 
      while (*str) 
      { 
        if (isdigit(*str)) 
        { 
          sum += strtol(str, &str, 10); 
        } 
        str++; 
      } 
    } 
    fclose(file); 
    return sum; 
} 

這並不包括錯誤處理,但工作得很好。爲您的文件,輸出將是

文件中的所有數字的總和是:19483

相關問題