2016-09-19 27 views
0

這是給我的C語言編程課,我的老師正在使用scanf,我們不能使用任何其他東西。我通過在這個文本文件:https://gist.github.com/cjoshmartin/29bd3365a925ee295da21ae2e917c7e1 我使用的是表彰行的文件中通過這一稱道: 程序1 < lab4text.txt使用scanf讀取C程序中的文本

here is what I am trying to get for output: 

    | SSN | Average | 263? | 
    ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ 
1 | xxxx | xx.xxx% | Y | 
2 | xxxx | xx.xxx% | N | 
3 | xxxx | xx.xxx% | Y | 
4 | xxxx | xx.xxx% | Y | 



here is what is what I currently am getting: 
    | SSN | Average | 263 | 
------------------------- 
1 | 2381 | 67.454 % |  Y | 
2 | 0 | -167.040 % |  2 | 
3 | 0 | 3762321554297869312.000 % |  6 | 
4 | 1234 | 81.318 % |  Y | 

我覺得scanf函數是從的錯誤部分閱讀文本文件,但我不知道如何解決它。

這裏是我當前的代碼:

#include <stdio.h> 
void main(void){ 

//FILE *file; 
int i = 0; 
int SSN[4] = { 0 }, j; 
char isin263[4]; 
float quizavg[4]; 
float labavg[4]; 
float exam1[4]; 
float exam2[4]; 
float finalexam[4]; 
scanf("%*[^\n]\n"); 
scanf("%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s"); 
scanf("%*[^\n]\n"); 


for (i = 0;i < 4;i++) 
{ 
    scanf("%*s %*s %*s"); 
    scanf("%*d-%*d-%d", &SSN[i]); 
    scanf(" %*9s%*c%*c%*c%*c %c %f %f %f %f %f\n", &isin263[i], &quizavg[i], &labavg[i], &exam1[i], &exam2[i], &finalexam[i]); 
} 


    printf("|%5s | %5s | %4d |\n","SSN","Average", 263); 
    printf("-------------------------\n"); 
    for (j = 0;j < 4;j++) 
    { 
     //fixed this line 
     printf(" %i | %4d | %5.3f %% | %5c |\n",j+1,SSN[j], (quizavg[j]*0.07)+(labavg[j]*0.24)+((exam1[j]+exam2[j])*0.185)+(finalexam[j]*0.32), isin263[j]); 
    } 


    } 

任何幫助,將不勝感激!

+0

請張貼[MCVE] – purplepsycho

+1

的'「%c」'格式(帶或不帶任何修飾符)不會跳過前導空格。嘗試在用於跳過管道字符的'「%* c」'之前在格式字符串中放置一個空格。同時檢查['scanf'](http://en.cppreference.com/w/c/io/fscanf)返回的結果。 –

+2

閱讀每行並不容易,然後解析它們? –

回答

1

也許this是你在找什麼。

Specifier: %*s%*[ \"]%[^,], %[^\"]\"%s%s%*[ ]%[YN]%lf%lf%lf%lf%lf 
    %*s  - Skips '*' characters at the beginning of each line 
    %*[ \"] - Skips spaces and the opening quote 
    %[^,]  - Gets the Last Name 
    ', '  - Ignores the comma and space 
    %[^\"] - Gets the First Name 
    '"'  - Ignores the closing quote 
    %s  - Gets the SSN 
    %s  - Gets the DOB 
    %*[ ]  - Ignores spaces 
    %[YN]  - Gets the value of the 263? column 
    %lf  - Gets the Quiz-avg 
    %lf  - Gets the Lab-avg 
    %lf  - Gets the Exam#1 
    %lf  - Gets the Exam#2 
    %lf  - Gets the Final Exam 
+1

split * last,first * on'','? (例如'%[^,]'最後) –

+0

已編輯,謝謝。 –

+0

謝謝!無論如何,我只能得到SSN的最後幾位數字? –

2

如果你要嘗試與fscanf讀取變化的數據,那麼格式字符串將是你成功的關鍵(或失敗)。如果您需要收集的每一行都具有相同的格式,那麼您可以嘗試使用fscanf來讀取數據(而您通過使用fgetssscanf將讀取與解析&驗證解耦來獲得靈活性)。但是,只要您有辦法保留所需的線路,並跳過那些不需要的線路,則fscanf即可用作工具。

在這種情況下,您的示例數據LYF_HKN在他的答案中做了很好的工作,以解決您需要的每一行中的所有信息。我想補充一個小的變體,並使用類似:

char *fmt = " %*[^\"]\"%[^,], %[^\"]\" %s %s %[YN] %lf %lf %lf %lf %lf"; 

其餘的是簡單的循環遍歷你的輸入文件中的行和索引你添加到您的結構中的學生。您需要捕獲returnfscanf,並將其與您需要的匹配計數10進行比較,以驗證您的每個值都已收到輸入。您還需要跳過標題行和其他不包含學生數據的行。只要fscanf不會遇到EOF設置流中的錯誤條件,您可以通過閱讀來完成此操作。然後,您只需檢查匹配計數return)與預期的10以指示它是否是有效的學生數據行。

把這個放在一起,你可以這樣做以下:

#include <stdio.h> 

/* constants for use in your code */ 
enum { YN = 2, DOB = 11, SS = 12, NM = 32 }; 

typedef struct { 
    char last[NM], first[NM], ss[SS], dob[DOB], yn[YN]; 
    double qavg, lavg, ex1, ex2, fex; 
} stnt; 

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

    stnt s[8] = {{ .first = "" }}; 
    int cnv = 0, n = 0; 
    char *fmt = " %*[^\"]\"%[^,], %[^\"]\" %s %s %[YN] %lf %lf %lf %lf %lf"; 
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin; 

    if (!fp) { /* validate file open for reading */ 
     fprintf (stderr, "error: file open failed '%s'.\n", argv[1]); 
     return 1; 
    } 

    /* read each line, if the match-count is 10 increment index */ 
    while ((cnv=fscanf (fp, fmt, s[n].last, s[n].first, s[n].ss, s[n].dob, s[n].yn, 
       &s[n].qavg, &s[n].lavg, &s[n].ex1, &s[n].ex2, &s[n].fex)) != EOF) 
     if (cnv == 10) n++; 

    if (fp != stdin) fclose (fp);  /* close file if not stdin */ 

    for (int i = 0; i < n; i++) /* output the student information */ 
     printf ("\n student : %s %s\n ss number : %s\n D.O.B. : %s\n" 
       " yes/no : %s\n quiz avg : %.2lf\n lab avg : %.2lf\n" 
       " exam 1 : %.2lf\n exam 2 : %.2lf\n final  : %.2lf\n", 
       s[i].first, s[i].last, s[i].ss, s[i].dob, s[i].yn, s[i].qavg, 
       s[i].lavg, s[i].ex1, s[i].ex2, s[i].fex); 

    return 0; 
} 

使用fgetssscanf

鑑於討論和關於使用fgetssscanf的意見,除了fscanf的例子之外,值得用一個簡短的例子來說明我使用的方法。該代碼大致相同,除了添加緩衝區buf來保存用戶輸入線和基於fgets返回的循環控制。除此之外,用sscanf代替fscanf只不過是代替sscanf調用中的文件流的緩衝區。無論fscanfsscanf返回匹配計數在於把基礎上,轉換指定地點成功轉換次數存在於格式字符串

#include <stdio.h> 

/* constants for use in your code */ 
enum { YN = 2, DOB = 11, SS = 12, NM = 32, MAXC = 256 }; 

typedef struct { 
    char last[NM], first[NM], ss[SS], dob[DOB], yn[YN]; 
    double qavg, lavg, ex1, ex2, fex; 
} stnt; 

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

    stnt s[8] = {{ .first = "" }}; 
    int n = 0; 
    char buf[MAXC] = "", 
     *fmt = " %*[^\"]\"%[^,], %[^\"]\" %s %s %[YN] %lf %lf %lf %lf %lf"; 
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin; 

    if (!fp) { /* validate file open for reading */ 
     fprintf (stderr, "error: file open failed '%s'.\n", argv[1]); 
     return 1; 
    } 

    /* read each line, if the match-count is 10 increment index */ 
    while (fgets (buf, MAXC, fp)) 
     if (sscanf (buf, fmt, s[n].last, s[n].first, s[n].ss, s[n].dob, s[n].yn, 
       &s[n].qavg, &s[n].lavg, &s[n].ex1, &s[n].ex2, &s[n].fex) == 10) 
      n++; 

    if (fp != stdin) fclose (fp);  /* close file if not stdin */ 

    for (int i = 0; i < n; i++) /* output the student information */ 
     printf ("\n student : %s %s\n ss number : %s\n D.O.B. : %s\n" 
       " yes/no : %s\n quiz avg : %.2lf\n lab avg : %.2lf\n" 
       " exam 1 : %.2lf\n exam 2 : %.2lf\n final  : %.2lf\n", 
       s[i].first, s[i].last, s[i].ss, s[i].dob, s[i].yn, s[i].qavg, 
       s[i].lavg, s[i].ex1, s[i].ex2, s[i].fex); 

    return 0; 
} 

示例使用/輸出

使用您的數據(帶有),你最終會得到類似以下的輸出:

$ ./bin/rdstudents <dat/lab4text.txt 

student : Christopher Jones 
ss number : 162-74-2381 
D.O.B. : 9/12/1995 
yes/no : Y 
quiz avg : 51.67 
lab avg : 72.50 
exam 1 : 77.00 
exam 2 : 68.50 
final  : 61.00 

student : Sarah Lee Abrahamson 
ss number : 127-49-0853 
D.O.B. : 11/5/1993 
yes/no : N 
quiz avg : 87.10 
lab avg : 79.33 
exam 1 : 64.25 
exam 2 : 84.00 
final  : 72.50 

student : Adreana Parker-Jones 
ss number : 230-38-1234 
D.O.B. : 3/1/1996 
yes/no : Y 
quiz avg : 75.23 
lab avg : 81.04 
exam 1 : 78.50 
exam 2 : 80.00 
final  : 85.25 

student : Joshua Ellis 
ss number : 186-27-1372 
D.O.B. : 7/31/1988 
yes/no : Y 
quiz avg : 85.23 
lab avg : 94.90 
exam 1 : 85.00 
exam 2 : 92.00 
final  : 94.25 
+0

好的工作。我打算回答它,格式是傷害了我的眼睛:)順便說一句,爲什麼你不提倡使用fgets(逐行閱讀)?這將很容易調試,維護。 – blackpen

+0

我在提及'fgets'和'sscanf'時都提到過, intro,但很可惜,有時當數據合法地允許使用'fscanf'本身時,這個例子是值得的。 –

+0

我沒注意你的評論,我剛纔看到它。Upvote +1。 – blackpen