2014-12-02 109 views
4

我試圖在C中製作一個程序,用於跟蹤學生借閱的書籍。我很難在訪問文件指針。當我使用文件時,我通常不會使用fscanf(),而是使用通常的scanf。我有這樣的數據結構:C中的文件,訪問指針,讀取和寫入文件

typedef struct{ 
    char fName[24], mInitial, lName[16]; 
}nameType; 

typedef struct{ 
    unsigned long idNo; 
    nameType studName; 
    char course[8]; 
    int yrLevel; 
    books borrowedBooks; 
    int bksCtr; 
}student; 

typedef struct{ 
    student *studs; 
    int studCtr; 
}studList; 

我已經創建了兩個功能,截至目前,這是addStudToFile(無效),增加了學生的文件,displayStudsFromFile(無效),基本打印出在文件中添加的學生。這是我的新手功能代碼:

void addStudToFile(void) 
{ 

    FILE *fp; 
    studList myStud; 


    fp = fopen("students.db", "w"); 
    if(fp!=NULL){ 
     /* ask for student details and adds these to the file */ 
     printf("Enter ID number: "); 
     fflush(stdin); 
     scanf(,"%lu", &myStud.studs->idNo); 
     printf("Enter First Name: "); 
     fflush(stdin); 
     gets(myStud.studs->studName.fName); 
     printf("Enter Last Name: "); 
     fflush(stdin); 
     gets(myStud.studs->studName.lName); 
     printf("Enter Middle Initial: "); 
     fflush(stdin); 
     scanf("%c", &(myStud.studs->studName.mInitial)); 
     printf("Enter Course: "); 
     fflush(stdin); 
     gets(myStud.studs->course); 
     printf("Enter Year: "); 
     fflush(stdin); 
     scanf("%d", &(myStud.studs->yrLevel)); 
     fwrite(&myStud, sizeof(studList),1,fp); 
     fclose(fp); 
    } 
} 

void displayStudsFromFile(void) 
{ 

    FILE *fp; 
    studList myStud; 

    fp = fopen("students.db", "r"); 
    if(fp!=NULL){ 
     while (fread(&myStud, sizeof(studList), 1, fp)){ 
      printf("%lu\t %s, %s %s\t %s-%d", myStud.studs->idNo, myStud.studs->studName.lName, 
              myStud.studs->studName.fName, myStud.studs->studName.mInitial, 
              myStud.studs->course, myStud.studs->yrLevel); 
      printf("borrowed %d books", myStud.studs->bksCtr); 
     } 
     fclose(fp); 
    } 
} 

現在,我在這裏的問題是,在我的訪問列表是myStud。在我的addStudToFile()函數,每次我輸入我的ID號,我的程序停止工作。爲什麼它停止工作?我需要malloc嗎?或者是我在訪問scanf()錯?我遇到我的程序停止再次工作的另一種情況是當我打電話給我的顯示功能時。它顯示的東西,但外星人/垃圾值。

這是在哪裏我在掃描功能遇到我的問題的屏幕截圖:

enter image description here

這裏是我的顯示功能:

enter image description here

我希望有人能夠幫助我與此。謝謝!

+0

不要對發佈圖片感覺不好 - 這是一個純文本程序,對吧?圖像會添加什麼? – usr2564301 2014-12-02 22:02:26

+0

寧可截圖。我很抱歉,我已經編輯過了。謝謝! @Jongware – 2014-12-02 22:04:24

+0

這一行:while(fread(&myStud,sizeof(studList),1,fp)){在到達文件結束時不一定會停止。因爲它可以返回除'1'之外的其他數字,例如在某些錯誤情況下不爲0。建議:while(1 == fread(&myStud,sizeof(studList),1,fp))){ – user3629249 2014-12-03 04:09:42

回答

3

你的預感是正確的,你需要的malloc的東西:)

typedef struct{ 
    student *studs; 
    int studCtr; 
}studList; 

這是你的問題。您將螺柱定義爲指向學生結構的指針,但實際上並未爲其分配任何內存,因此您可以稍後使用運算符來引用它。

您可以允許項目的預設號碼,這樣的話你可以定義一樣,

student studs[10]; 

允許10個條目,或在addStudToFile()你可以要求用戶輸入他想要輸入的條目數量。在這種情況下,你會離開的定義,因爲它是,一旦你有用戶輸入做:

myStud.studs = (student *) malloc(sizeof(student) * how_many); 

有可能是沿着你已經發布的代碼更多的錯誤,但暫時上面是什麼讓你回來。

編輯:如果你遵循的malloc()的路線,從返回addStudToFile()無論出於何種原因之前,你應該確保你叫

free(myStud.studs); 

,或者你得到一個內存泄漏...

更新

好吧,去進一步下降,當你使用fwrite()的一切,記住,你的malloc()的雙頭螺栓的內存。 sizeof(studlist)在編譯時計算,不可能知道運行時使用的額外內存。另外,這兩個內存區域不保證連續,所以仍然有一個fwrite不會削減它。如果你的代碼是按照它的結構構建的,那麼你最好先fwrite()首先使用studCtr,然後再使用你爲鼠標設計的內存。

對於displayStudsFromFile()因爲僅僅是一個循環那裏並沒有什麼真正的存儲,用於以後,我只用

student myStud; 

即使用學生結構只是一個實例,而不是studlist。在這種情況下,你需要做一個fread()讀取磁盤文件中的studCtr,然後使用它來一次循環fread()一個學生對象到myStud。在這一循環中,您打印感興趣的領域,像這樣:

printf("borrowed %d books", myStud.bksCtr); 

希望這將讓你去...用C第一步是有點困難:d

+0

我試過使用malloc,但是當我嘗試編譯我的程序時發生錯誤。它說:「從'空'無效轉換爲'學生',我甚至沒有得到這個錯誤。 – 2014-12-02 22:26:46

+0

無效*給學生*可能嗎?你是否在malloc()之前添加了演員給(student *)? 。 – kostas 2014-12-02 22:32:58

+0

我的malloc工作過,哈!謝謝!你能告訴我關於我的顯示功能嗎?這就是我被卡住的原因。每當我打電話給我的顯示功能時,它就會停止我的程序 – 2014-12-02 22:34:38

1

myStud.studs是一個指向學生的指針,但我沒有看到你實際分配給那個學生的位置。你需要malloc一個學生之前,你可以做一些事情,如&myStud.studs->idNo

+0

我的malloc應該如何處理這個? myStud =(studList)malloc(sizeof(?)) – 2014-12-02 22:16:16

+1

在C中,有幾個原因不能從任何malloc系列函數中強制返回值。所以建議刪除它。 – user3629249 2014-12-03 04:46:20

0

總之,不要寫指向文件的指針,它們以後會變得毫無意義。

典型的方法是首先寫出物品的數量,然後遍歷列表中的每個物品並單獨寫出它們。

在讀者結尾:

  1. 讀項目的數量。
  2. 分配足夠的內存來保存所有項目。
  3. 閱讀每個項目。
+0

我明白了,但我們的老師告訴我們現在使用這種方法來使用文件。 – 2014-12-02 22:22:43

0
along with the problems mentioned already, 
this function has its' own set of troubles. 
I have inserted '<--' and a comment at each problem 

fflush(stdin) though works on some implementations, it's still undefined behaviour. 
According to the standard, fflush only works with output/update streams 
(for your code, since the printf format strings do not end in '\n' 
( which would have forced the actual output to occur 
( change these lines to 'fflush(stdout)' 

A ' ' in a scanf() format string will consume any white space found at that 
point in the input. Therefore, for almost all cases, the first char in 
the format string should be: ' '. Then newlines, spaces, etc 
will be consumed, as if they were never there. It is even correct to 
use the leading ' ' when there is no white space to consume. 

gets() is depreciated and will corrupt/overrun a input buffer, so NEVER 
use gets, rather, use fgets(), where the amount of input can be limited 
and similar good things. 

void addStudToFile(void) 
{ 

    FILE *fp; 
    studList myStud; 


    fp = fopen("students.db", "w"); 
    if(fp!=NULL) 
    { 
     /* ask for student details and adds these to the file */ 

     printf("Enter ID number: "); 
     fflush(stdin); <-- change to stdout 
     scanf(,"%lu", &myStud.studs->idNo); 
     <-- change format string to: " %lu" 
     <-- add check of returned value to assure operation successful 

     printf("Enter First Name: "); 
     fflush(stdin); <-- change to stdout 
     gets(myStud.studs->studName.fName); 
     <-- replace gets with fgets() +appropriate parms) 
     <-- add check of returned value to assure operation successful 

     printf("Enter Last Name: "); 
     fflush(stdin); <-- change to stdout 
     gets(myStud.studs->studName.lName); 
     <-- replace gets with fgets() +appropriate parms) 
     <-- add check of returned value to assure operation successful 

     printf("Enter Middle Initial: "); 
     fflush(stdin); <-- change to stdout 
     scanf("%c", &(myStud.studs->studName.mInitial)); 
     <-- replace format string with " %c" 
     <-- add check of returned value to assure operation successful 

     printf("Enter Course: "); 
     fflush(stdin); <-- change to stdout 
     gets(myStud.studs->course); 
     <-- replace gets with fgets() +appropriate parms 
     <-- add check of returned value to assure operation successful 

     printf("Enter Year: "); 
     fflush(stdin); <-- change to stdout 
     scanf("%d", &(myStud.studs->yrLevel)); 
     <-- change format string to: " %d" 
     <-- add check of returned value to assure operation successful 

     fwrite(&myStud, sizeof(studList),1,fp); 
     <-- add check of returned value to assure operation successful 

     fclose(fp); 
    <-- add else clause so use knows what happened. I.E. 
     } else { perror("fopen failed for write"); exit(EXIT_FAILURE); 
    } // end if 
} // end function: addStudToFile 
0
Here are my comments, prefixed by '<--' 



void displayStudsFromFile(void) 
{ 

    FILE *fp; 
    studList myStud; 

    fp = fopen("students.db", "r"); 
    if(fp!=NULL) 
    { 
     while (fread(&myStud, sizeof(studList), 1, fp)) 
     <-- add check of returned value to assure operation successful 

     { 
      printf("%lu\t %s, %s %s\t %s-%d", 
        myStud.studs->idNo, 
        myStud.studs->studName.lName, 
        myStud.studs->studName.fName, 
        myStud.studs->studName.mInitial, 
        myStud.studs->course, 
        myStud.studs->yrLevel); 
      printf("borrowed %d books", myStud.studs->bksCtr); 
     } 
     fclose(fp); 
    <-- to let user know about error 
    <-- insert: }else{ perror("fopen failed for read"); exit(EXIT_FAILURE); 
    } // end if 
} // end function: displayStudsFromFile