2017-05-04 144 views
2

檢查字符串文件,所以我給用戶推出一個代碼像這樣的車的選項:C來自scanf函數

typedef struct 
{ 
    char name[50]; 
    char category[50]; 
    int code; 
    int price; 
} car; 
car c; 
    FILE *f; 
    f = fopen("Cars.txt", "r+"); 
    printf("Enter the code of the car:"); 
    if (f != NULL) { 
     scanf("%d", &c.code); 
     char *code; 
     code = (char *)malloc(sizeof(c.code) +1); 
     sprintf(code, "%d", &c.code); 
     while (checkCode(code, f) == 0) 
     { 
      printf("The code for this car already exists, try again:"); 
      scanf("%d", &c.code); 
      char *code; 
      code = (char *)malloc(sizeof(c.code) + 1); 
      sprintf(code, "%d", &c.code); 
     } 
    } 

這是我的註冊碼功能:

int checkCode(char *code, FILE *f) { 
    char line[1024]; 
    while (fgets(line, sizeof(line), f) != NULL) 
    { 
     if (strstr(line, code) != NULL) 
     { 
      return 0; 
     } 
    } 
    return 1; 
} 

一點也沒有沒有工作。儘管我介紹關於文件的線路之一已經進入了一個代碼函數返回1。我的猜測是問題就在這裏:

while (fgets(line, sizeof(line), f) != NULL) 

我是新來的C.任何人都可以請解釋我有什麼問題。謝謝大家的時間!

+2

我們應該知道「汽車」是什麼? –

+1

'scanf(「%d」,&c.code);' - >什麼是'c.code'? – Marievi

+0

對不起,這是一個結構我剛剛更新了我的代碼 – Alphonse

回答

3

有在你的代碼的幾個問題:

  • 你分配轉換的字符串空間不一致的大小:在數轉換的字符數不能被計算爲sizeof(c.code) + 1,你應該使用本地具有固定大小的陣列。
  • 您傳遞代碼的地址而不是其值。
  • 您不倒帶流指針以從頭開始掃描文件。
  • 你也應該尋求流的結尾寫入新條目。

這裏是一個修正版本:

FILE *f; 
f = fopen("Cars.txt", "r+"); 
if (f != NULL) { 
    char code[32]; 
    printf("Enter the code of the car:"); 
    scanf("%d", &c.code); 
    snprintf(code, sizeof code, "%d", c.code); 
    rewind(f); 
    while (checkCode(code, f) == 0) { 
     printf("The code for this car already exists, try again:"); 
     scanf("%d", &c.code); 
     snprintf(code, sizeof code, "%d", c.code); 
     rewind(f); 
    } 
    fseek(f, 0L, SEEK_END); 
} 

這實際上是更可靠的讀取響應作爲一個字符串,並與sscanf()轉換:

FILE *f = fopen("Cars.txt", "r+"); 
if (f != NULL) { 
    char code[32]; 
    printf("Enter the code of the car:"); 
    for (;;) { 
     if (fgets(code, sizeof code, stdin) == NULL) { 
      printf("unexpected end of file\n"); 
      return -1; 
     } 
     if (sscanf(code, "%d", &c.code) != 1) { 
      printf("invalid input, try again:"); 
      continue; 
     } 
     snprintf(code, sizeof code, "%d", c.code); 
     rewind(f); 
     if (checkCode(code, f) == 0) { 
      printf("The code %s is already used, try again:", code); 
      continue; 
     } 
     break; /* the code in c.code is OK */ 
    } 
    fseek(f, 0L, SEEK_END); 
} 
1

一個問題,我看到的是,該文件在while循環的一個集成之後不會倒回。

第二次檢查運行時,文件指針仍然在文件的末尾,所以它會像在文件中沒有代碼那樣工作。

另一個祕訣:

用做......而在這裏,因爲你要問的輸入至少一次。這將減少代碼重複。事情是這樣的:

char code[256]; 

do 
{ 
    scanf("%d", &c.code); 
    sprintf(code, "%d", &c.code); 
} while (checkCode(code, f) == 0); 

(請注意,錯誤輸入錯誤信息應該被移動到註冊碼()函數)

+0

這很奇怪,但chqrlie給出的解決方案沒有問題。即使輸入了多個錯誤代碼,它仍會給我提供錯誤信息,直到我輸入一個不在文件中的錯誤信息。你能否告訴我更多關於如何倒帶文件,爲什麼我應該使用do? – Alphonse

+1

C庫函數** void rewind(FILE * stream)將文件位置設置爲給定流文件的開始位置。 – slingeraap

1

我真的不喜歡的事實,你的代碼提示在代碼的兩個地方。如果你想在用戶給出不可接受的代碼時回到開頭,那就做那件事。這也可能避免在兩個地方進行內存分配,使得忘記釋放其中一個緩衝區的可能性減小。實物模型:

do { 
    int code = ask_for_code(); 
    if (look_for_code(code) == 0) { 
     printf("sorry, that code already exists");   
    } else { 
     do_something_with_the_code(); 
     break; 
    } 
} while(1); 

然後ask_for_code()將包含您的提示和scanflook_for_code大致匹配您的checkCode()

更改循環條件爲狀態標誌或類似的東西,如果你不喜歡看似無休止的循環。


同樣在此:

code = (char *)malloc(sizeof(c.code) +1); 
sprintf(code, "%d", &c.code); 

分配一個緩衝區的int(1)的大小,所以大概約5個字節。對於高達9999的數字來說,這足夠了,但任何過去的數據都會溢出緩衝區。 32位整數,應該適合在12個字節(與尾礦零),但在任何情況下,你可能想使用snprintf有:

char code[12]; 
snprintf(code, 12, "%d", c.code); 

那的printf也應該採取自身(c.code)的數量,而不是其地址(&c.code)。