2013-04-28 88 views
0

我知道我只是想念一些愚蠢的東西,但我很沮喪,我只是看不到它。當我對下面的代碼運行3個字段的文件「field1; field2; field3」時,這些任務在retrieveTasks方法中正確輸出。當該方法返回到主輸出已損壞。我知道這很愚蠢,我只是想念它。我已經嘗試將CourseName,TaskDescription等改爲數組而不是char *。我曾嘗試傳遞fileString作爲char *,我已經嘗試過使用strcpy而不使用。任何人都可以指出我的方向嗎?方法返回後內存被破壞

const int MAX_STRING_LENGTH = 101; 
const int MAX_TASK_ITEMS = 255; 
const char NEWLINE = '\n'; 
const char DELIMETER[] = ";"; 
const char FILENAME[] = "tasks.txt"; 

struct Task { 
    char* CourseName; 
    char* TaskDescription; 
    char* DueDate; 
    char FileString[300]; 

    void printTask() { 
    cout << CourseName << DELIMETER << TaskDescription << DELIMETER << DueDate << endl; 
    } 

    void initializeFromFileString(char fileString[]) { 
    strcpy(FileString, fileString); 
    CourseName = strtok(FileString, DELIMETER); 
    TaskDescription = strtok(NULL, DELIMETER); 
    DueDate = strtok(NULL, DELIMETER); 
    } 
}; 

struct TaskList { 
    Task Tasks[MAX_TASK_ITEMS]; 
    int TaskCount; 

    void initialize() { 
    TaskCount = 0; 

    return; 
    } 

    void addTask(Task task) { 
    Tasks[TaskCount] = task; 
    TaskCount++; 

    return; 
    } 

    void printTasks() { 
    for(int TaskNum = 0; TaskNum < TaskCount; TaskNum++) { 
     cout << TaskNum + 1 << ".  "; 
     Tasks[TaskNum].printTask(); 
     cout << endl; 
    } 

    return; 
    } 

    // Load data from the file. Will return -1 if it fails for any reason. 
    // Otherwise it returns the number of records read. 
    int retrieveTasks(const char* fileName) { 
    int isSuccessfulOpen = 0; 
    int recordsRead = 0; 
    ifstream inFile; 

    isSuccessfulOpen = openFile(inFile, fileName); 

    if(!isSuccessfulOpen) { 
     return -1; 
    } 

    // Read input file and store in appropriate arrays 
    while(inFile.eof() == false) { 
     char fileLine[MAX_STRING_LENGTH * 3]; 
     Task task; 

     inFile.getline(fileLine, MAX_STRING_LENGTH * 3, NEWLINE); 
     inFile.ignore(UINT_MAX, NEWLINE); 
     task.initializeFromFileString(fileLine); 
     addTask(task); 
     recordsRead++; 
    } 
    inFile.close(); 

    return recordsRead; 
    } 
}; 

int main() { 
    bool isFinished = false; 
    TaskList taskList; 

    taskList.initialize(); 
    taskList.retrieveTasks(FILENAME); 
    taskList.printTasks(); 

    return 0; 
} 



int openFile(ifstream& inFile, const char* fileName) { 
    inFile.open(fileName); 

    // Veryify that the file is valid. If not print error message. 
    if(inFile.is_open() == false) { 
    cout << "File " << fileName << " does not exist. Please provide a valid file path." << endl; 
    return 0; 
    } 

    return 1; 
} 

// Open file for writing 
int openFile(ofstream& outFile, const char* fileName) { 
    outFile.open(fileName); 

    // Veryify that the file is valid. If not print error message and exit. 
    if(outFile.is_open() == false) 
    { 
    cout << "File " << fileName << " does not exist. Please provide a valid file path." << endl; 
    return 0; 
    } 

    return 1; 
} 
+0

爲什麼你使用C字符串和庫? – 2013-04-28 06:20:37

+0

確實。使用C++技術可以幫助您避免出現三條/五條規則的問題,更不用說使代碼更清晰,更易於遵循。 – chris 2013-04-28 06:23:34

+0

我同意。你的本地緩衝區使得copy-ctor和賦值運算符相當平凡,但老實說,這應該使用'std :: string'對象和標準集合類(比如'std :: vector <>')來完成你的任務列表。它會使代碼更清潔。 – WhozCraig 2013-04-28 06:31:50

回答

4

CourseNameTaskDescriptionDueDate都指向存儲器存在於while循環中創建的對象task在數組中。由於這個task對象是本地作用域,因此一旦retrieveTasks已經完成執行,它們就會包含垃圾。

變化需要

  1. 你TaskCount始終保持比數多一個 - 因此這需要由1

    for(int TaskNum = 0; TaskNum < TaskCount; TaskNum++) { 
    

    減少改爲

    for(int TaskNum = 0; TaskNum < TaskCount -1 ; TaskNum++) { 
    
  2. 刪除while循環中的任務對象。

  3. AddTask需要一個char *而不是Task。 AddTask調用initializeFromFileString以便strcpy完成對數組的Task對象中的字符串。而strtok也叫這個字符串

  4. 變化

    while(inFile.eof() == false) { 
    

    while(inFile) { 
    
  5. 刪除

    inFile.ignore(UINT_MAX, NEWLINE); 
    

固定碼

struct Task { 
    char* CourseName; 
    char* TaskDescription; 
    char* DueDate; 
    char FileString[300]; 

    void printTask() { 
    cout << CourseName << DELIMETER << TaskDescription << DELIMETER << DueDate << endl; 
    } 

    void initializeFromFileString(char fileString[]) { 
    strcpy(FileString, fileString); 
    CourseName = strtok(FileString, DELIMETER); 
    TaskDescription = strtok(NULL, DELIMETER); 
    DueDate = strtok(NULL, DELIMETER); 
    } 

}; 



int openFile(ifstream& inFile, const char* fileName) { 
    inFile.open(fileName); 

    // Veryify that the file is valid. If not print error message. 
    if(inFile.is_open() == false) { 
    cout << "File " << fileName << " does not exist. Please provide a valid file path." << endl; 
    return 0; 
    } 

    return 1; 
} 

// Open file for writing 
int openFile(ofstream& outFile, const char* fileName) { 
    outFile.open(fileName); 

    // Veryify that the file is valid. If not print error message and exit. 
    if(outFile.is_open() == false) 
    { 
    cout << "File " << fileName << " does not exist. Please provide a valid file path." << endl; 
    return 0; 
    } 

    return 1; 
} 

struct TaskList { 
    Task Tasks[MAX_TASK_ITEMS]; 
    int TaskCount; 

    void initialize() { 
    TaskCount = 0; 

    return; 
    } 

    void addTask(char * t) { 
    Tasks[TaskCount].initializeFromFileString(t); 
    TaskCount++; 

    return; 
    } 

    void printTasks() { 
    for(int TaskNum = 0; TaskNum < TaskCount - 1; TaskNum++) { 
     cout << TaskNum + 1 << ".  "; 
     Tasks[TaskNum].printTask(); 
     cout << endl; 
    } 

    return; 
    } 

    // Load data from the file. Will return -1 if it fails for any reason. 
    // Otherwise it returns the number of records read. 
    int retrieveTasks(const char* fileName) { 
    int isSuccessfulOpen = 0; 
    int recordsRead = 0; 
    ifstream inFile; 

    isSuccessfulOpen = openFile(inFile, fileName); 

    if(!isSuccessfulOpen) { 
     return -1; 
    } 

    // Read input file and store in appropriate arrays 
    while(inFile) { 
     char fileLine[MAX_STRING_LENGTH * 3]; 

     inFile.getline(fileLine, MAX_STRING_LENGTH * 3, NEWLINE); 

     addTask(fileLine); 
     printTasks(); 

     recordsRead++; 
    } 
    inFile.close(); 

    return recordsRead; 
    } 
}; 

很明顯,如果你在C++寫的,而不是在C inside classes寫它的這整個程序將更簡單且不易出錯。

+0

非常感謝。這是一個巨大的幫助。如果我可以使用C++類,那麼上一學期我們就可以,但這個術語的要求只允許cstrings。再次感謝你的幫助。 – user2328414 2013-04-28 07:01:23