【问题标题】:C Saving Data from a Text File into an Array of StructuresC 将文本文件中的数据保存到结构数组中
【发布时间】:2018-10-18 19:03:07
【问题描述】:

我想问一下C语言中的文件处理和结构。我被分配了一个任务,我需要一个 .txt 文件,其中包含:篮球队的名称、他们总共打过的比赛、他们赢得的比赛数量等。 这是任务:

  1. 从用户指定的.txt文件中获取数据(例如“data.txt”)
  2. 将数据存储在结构数组
  3. 让用户能够按名称或他们的获胜总数排序

这里是一个例子,“data.txt”文件:

结构:名称,参加的比赛,主场赢,主场输,客场赢,客场输

Fenerbahce-Dogus 25 12 0 10 3
Tofas 25 11 2 9 3
Anadolu-Efe 26 13 1 6 6
Banvit 26 9 4 8 5
Darussafaka 26 11 2 4 9

到目前为止,我一直在尝试分配一个动态数组(结构)并将 txt 文件中的数据保存到所述数组中。但是,每当我尝试输入上述“data.txt”时,程序就会立即停止响应。作为输入。谁能告诉我为什么会发生这种情况以及我应该怎么做才能克服这个错误?

代码如下:

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

typedef struct {
        char *name;
        int games;
        int winsHome, losesHome;
        int winsAway, losesAway;
        int winsTotal, losesTotal;
        int totalPoints;
} scoreboard;


void Load_Scoreboard_Table(char *, scoreboard *);

int main(){
    char fileName[40];
    FILE *inputFile;
    while (1){
        printf("Enter the file name> ");
        gets(fileName);
        inputFile = fopen(fileName,"r");
        if (inputFile != NULL){
            break;
        }
        printf("ERROR: The file %s could not be opened.\n",fileName);
        printf("Please verify that the file exists.\n");
    }
    int listLength=0;
    char curChar;
    while ((curChar=fgetc(inputFile))!=EOF){
        if (curChar=='\n'){
            listLength++;
        }
    }
    fclose(inputFile);
    scoreboard *scoreboard_table = (scoreboard *)malloc(sizeof(scoreboard) * listLength);
    Load_Scoreboard_Table(fileName,scoreboard_table);
    return 0;
}

void Load_Scoreboard_Table(char *fileName,scoreboard *scoreboard_table){
    FILE *inputFile;
    fopen(fileName,"r");
    int i=0;
    while (fscanf(inputFile, "%s %d %d %d %d %d\n", (scoreboard_table+i)->name,(scoreboard_table+i)->games,(scoreboard_table+i)->winsHome,(scoreboard_table+i)->losesHome,(scoreboard_table+i)->winsAway,(scoreboard_table+i)->losesAway)!=EOF){
        (scoreboard_table+i)->winsTotal = (scoreboard_table+i)->winsHome + (scoreboard_table+i)->winsAway;
        (scoreboard_table+i)->losesTotal = (scoreboard_table+i)->losesHome + (scoreboard_table+i)->losesAway;
        (scoreboard_table+i)->totalPoints = (((scoreboard_table+i)->winsTotal)*2) + (scoreboard_table+i)->losesTotal;
        i++;
    }
}

更新:

我已经设法从文件中读取并将其保存在结构数组中。(还添加了一个打印功能)。但是,一旦它完成打印功能,我仍然无法让它停止冻结(它会在将数据保存到数组之前冻结)。 注意:我知道很多人警告我不要使用gets;但是,我的老师告诉我暂时使用它。 注2:我决定在结构中使用静态字符名称 注3:我今天才学习数据结构,所以我对这个话题很陌生;因此,请不要过多详细地解释事情。 什么可能导致下面的代码冻结?

代码:

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

typedef struct {                 // defining a struct here
    char name[40];               // name of the sports club
    //clubs containing multiple words should be written in the following format: 'name-name-name'
    //ex : 'Anadolu Efe' should be written as 'Anadolu-Efe' in the text file
    //This is to avoid confusion when reading from .txt file
    int games;
    int winsHome, losesHome;
    int winsAway, losesAway;
    int winsTotal, losesTotal;
    int totalPoints;
} scoreboard;

void Load_Scoreboard_Table(char *, scoreboard *); // reads the .txt file and saves the contents into scoreboard_table
void Display_Scoreboard_Table(scoreboard *, int); // displays scoreboard_table, also takes it's size as input

int main(void){
    char fileName[40]; // the name of the file will be stored here (ex: data.txt)
    FILE *inputFile;   // creating a stream to read from .txt file
    while (1){         // Ask user for the name of the file until said file is opened for reading
            printf("Enter the file name> ");
            gets(fileName); // get string input from user that supports space characters (eg: "data.txt")
            inputFile = fopen(fileName,"r"); // try opening file in read mode
            if (inputFile != NULL){ //if the file has succesfully opened, then break from the loop
                    break;
            }
            printf("ERROR: The file %s could not be opened.\n",fileName); //if the file was not succesfully opened, then print appropriate error message
            printf("Please verify that the file exists.\n");
    }
    int listLength=0; //will be used to dynamically allocate memory for scoreboard_table array (array of structs)
    int curChar;   // I figured that fgetc returns an integer value
    while ((curChar=fgetc(inputFile))!=EOF){  //get a character until EOF
            if (curChar=='\n'){               //if it's a newline character then we need to allocate more memory for scoreboard_table array
                    listLength++;
            }
    }
    fclose(inputFile); // close the file as it's job is done
    scoreboard *scoreboard_table = malloc(sizeof(scoreboard) * listLength); // allocating enough memory to store the contents of .txt file
    Load_Scoreboard_Table(fileName,scoreboard_table); //save the contents of file on scoreboard_table 
    while (1){
        Display_Scoreboard_Table(scoreboard_table,listLength);
        break;
    }
    free(scoreboard_table); //freeing memory allocated for scoreboard_table
    return 0;
}

void Load_Scoreboard_Table(char *fileName,scoreboard *scoreboard_table){
    FILE *inputFile = fopen(fileName,"r"); // creating stream to read from file
    if(inputFile == NULL ) {               //checking again just in case there is a problem opening the file
        printf("ERROR: The file %s could not be opened.\n",fileName);
        exit(1);
    }
    int i=0,j,k;
    //the loop below gets data from .txt file line by line until EOF and stores it in scoreboard_table array
    while (fscanf(inputFile,"%s %d %d %d %d %d", (scoreboard_table+i)->name,&(scoreboard_table+i)->games,&(scoreboard_table+i)->winsHome,&(scoreboard_table+i)->losesHome,&(scoreboard_table+i)->winsAway,&(scoreboard_table+i)->losesAway) != EOF){
            (scoreboard_table+i)->winsTotal = (scoreboard_table+i)->winsHome + (scoreboard_table+i)->winsAway;
            (scoreboard_table+i)->losesTotal = (scoreboard_table+i)->losesHome + (scoreboard_table+i)->losesAway;
            (scoreboard_table+i)->totalPoints = (((scoreboard_table+i)->winsTotal)*2) + (scoreboard_table+i)->losesTotal;
            i++;
    }
    //the loop below replaces the '-' characters with ' ' in the name of every scoreboard_table array
    for (j=0;j<i;j++){
        for (k=0;k<40;k++){
            if ((scoreboard_table+i)->name[k] == '-'){
                (scoreboard_table+i)->name[k] = ' ';
            }
        }
    }
    printf("Score records file has been successfully loaded!\n");
}

void Display_Scoreboard_Table(scoreboard *scoreboard_table,int size){
    printf("Team                                        G     WH     LH     WA     LA     Won     Lost     Points\n");
    int i;
    for (i=0;i<=size;i++){
        printf("%-40s%5d  %5d  %5d  %5d  %5d   %5d    %5d      %5d\n",(scoreboard_table+i)->name,(scoreboard_table+i)->games,(scoreboard_table+i)->winsHome,(scoreboard_table+i)->losesHome,(scoreboard_table+i)->winsAway,(scoreboard_table+i)->losesAway,(scoreboard_table+i)->winsTotal,(scoreboard_table+i)->losesTotal,(scoreboard_table+i)->totalPoints);
    }
}

谢谢。

更新 2(使用工作代码):

问题是由于我为名为@9​​87654325@ 的结构数组分配了错误的内存量。更具体地说,我为数组分配的内存可以比文件少 1 行。 我再次更新了代码。它现在正在工作......(在大多数情况下,除非输入了意外的输入(例如输入一个空文件,或者用户在获取中输入更多字符)。) 这段代码对我的作业来说绰绰有余,因为我的老师没有要求更详细的程序(事实上,如果我们提交更复杂的程序,他们会生气,因为我们还没有在课堂上了解它们 - 这就是为什么我例如使用gets() 而不是fgets())。 不过,我很想听听您对此事的看法。你认为我应该做些什么来改善这一点? 顺便说一句,我知道代码中的语法拼写错误。这只是因为我们需要在作业中严格遵守输入输出格式,并且输入不同的内容意味着失分。 代码:

/* -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
                                          ~ ~ ~ ~ VERY IMPORTANT ~ ~ ~ ~
        The text file containing the data should be written in the following format:
        "%s %d %d %d %d %d\n" where
        %s is the name of the club
        If the name of the club contains more than one word, it should be written without any space characters ' '; instead place dash characters '-'
        Example: 'Anadolu Efe' should be written as 'Anadolu-Efe' in the text file
        complete line example:
        "Anadolu-Efe 26 13 1 6 6"

   -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-        */

//including required libraries
#include <stdio.h>  
#include <stdlib.h> //used to dynamically allocate memory
#include <string.h> //used for some string manipulation functions

typedef struct {                 // defining a struct here
    char name[40];               // name of the sports club
    //clubs containing multiple words should be written in the following format: 'name-name-name'
    //ex : 'Anadolu Efe' should be written as 'Anadolu-Efe' in the text file
    //This is to avoid confusion when reading from .txt file
    int games;
    int winsHome, losesHome;
    int winsAway, losesAway;
    int winsTotal, losesTotal;
    int totalPoints;
} scoreboard;

void Load_Scoreboard_Table(char *, scoreboard *); // reads the .txt file and saves the contents into scoreboard_table
void Display_Scoreboard_Table(scoreboard *, int); // displays scoreboard_table, also takes it's size as input
void Search(scoreboard *, int, char *);           // searches if a team exists in the scoreboard array and if there is; it prints the stats of the team
void interactive_board(scoreboard *, int, int);   // sorts the scoreboard array depending on user input, (sort by: games, points)

/*
This program reads data from a txt data, stores it in an array of structs
The program has the ability to sort the array based on either points or games
It also can search for the name inside said array of structs
*/

int main(){
    char fileName[40];   // the name of the file will be stored here (ex: data.txt)
    char searchTerm[40]; // search term will be stored here
    FILE *inputFile;     // creating a stream to read from .txt file
    int i;               // will be used later in a loop
    while (1){           // Ask user for the name of the file until said file is opened for reading
            printf("Enter the file name: ");
            gets(fileName); // get string input from user that supports space characters (eg: "data.txt")
            inputFile = fopen(fileName,"r"); // try opening file in read mode
            if (inputFile != NULL){ //if the file has succesfully opened, then break from the loop
                    break;
            }
            printf("ERROR: The file %s could not be opened.\n",fileName); //if the file was not succesfully opened, then print appropriate error message
            printf("Please verify that the file exists.\n");
    }
    int listLength=1; //will be used to dynamically allocate memory for scoreboard_table array (array of structs)
    int curChar;   // I figured that fgetc returns an integer value
    while ((curChar=fgetc(inputFile))!=EOF){  //get a character until EOF
            if (curChar=='\n'){               //if it's a newline character then we need to allocate more memory for scoreboard_table array
                    listLength++;
            }
    }
    fclose(inputFile); // close the file as it's job is done
    scoreboard *scoreboard_table = malloc(sizeof(scoreboard) * (listLength)); // allocating enough memory to store the contents of .txt file
    if (scoreboard_table == NULL){
        printf("ERROR: There has been an error allocating memory for scoreboard table array.\n");
        exit(1);
    }
    Load_Scoreboard_Table(fileName,scoreboard_table); //save the contents of file on scoreboard_table 
    Display_Scoreboard_Table(scoreboard_table,listLength);
    while (1){
        printf("Enter the name of the team (Exit - X, Sort -S): ");
        gets(searchTerm);
        i=0;
        while (searchTerm[i]!='\0'){
            searchTerm[i]=toupper(searchTerm[i]);
            i++;
        }
        if (strcmp(searchTerm,"X")==0){
            printf("Bye!\n");
            free(scoreboard_table); //freeing memory allocated for scoreboard_table
            return 0;
        }
        else if (strcmp(searchTerm,"S")==0){
            printf("Sort by (G: games, P: points): ");
            gets(searchTerm);
            i=0;
            while (searchTerm[i]!='\0'){
                searchTerm[i]=toupper(searchTerm[i]);
                i++;
            }
            if (strcmp(searchTerm,"G")==0){
                interactive_board(scoreboard_table,listLength,1);
                Display_Scoreboard_Table(scoreboard_table,listLength);
            }
            else if (strcmp(searchTerm,"P")==0){
                interactive_board(scoreboard_table,listLength,2);
                Display_Scoreboard_Table(scoreboard_table,listLength);
            }
            else{
                printf("ERROR: Invalid input. There is no sort term for '%s'\n",searchTerm);
            }
        }
        else{
            Search(scoreboard_table,listLength,searchTerm);
        }
    }
}

void Load_Scoreboard_Table(char *fileName,scoreboard *scoreboard_table){
    FILE *inputFile = fopen(fileName,"r"); // creating stream to read from file
    if(inputFile == NULL ) {               //checking again just in case there is a problem opening the file
        printf("ERROR: The file %s could not be opened.\n",fileName);
        exit(1);
    }
    int i=0,j,k;
    //the loop below gets data from .txt file line by line until EOF and stores it in scoreboard_table array
    while (fscanf(inputFile,"%s %d %d %d %d %d", (scoreboard_table+i)->name,&(scoreboard_table+i)->games,&(scoreboard_table+i)->winsHome,&(scoreboard_table+i)->losesHome,&(scoreboard_table+i)->winsAway,&(scoreboard_table+i)->losesAway) != EOF){
            (scoreboard_table+i)->winsTotal = (scoreboard_table+i)->winsHome + (scoreboard_table+i)->winsAway;
            (scoreboard_table+i)->losesTotal = (scoreboard_table+i)->losesHome + (scoreboard_table+i)->losesAway;
            (scoreboard_table+i)->totalPoints = (((scoreboard_table+i)->winsTotal)*2) + (scoreboard_table+i)->losesTotal;
            i++;
    }
    //the loop below replaces the '-' characters with ' ' in the name of every scoreboard_table array
    for (j=0;j<i;j++){
        for (k=0;k<40;k++){
            if (*(((*(scoreboard_table+j)).name)+k) == '-' ){  //if the value of name[k] inside scoreboard_table[j] is equal to '-' character
                *(((*(scoreboard_table+j)).name)+k) = ' ';     //replace the value of scoreboard_table[j].name[k] to ' ' character
            }
        }
    }
    fclose(inputFile); // close the file as it's job is done
    printf("Score records file has been successfully loaded!\n"); // notify the user that reading from the file has been successful
}

void Display_Scoreboard_Table(scoreboard *scoreboard_table,int size){
    printf("\nTeam                                        G     WH     LH     WA     LA     Won     Lost     Points\n\n"); // the variables to be shown in table
    int i;
    for (i=0;i<size;i++){//for every element in scoreboard_table, print the variables stored
        printf("%-40s%5d  %5d  %5d  %5d  %5d   %5d    %5d      %5d\n",(scoreboard_table+i)->name,(scoreboard_table+i)->games,(scoreboard_table+i)->winsHome,(scoreboard_table+i)->losesHome,(scoreboard_table+i)->winsAway,(scoreboard_table+i)->losesAway,(scoreboard_table+i)->winsTotal,(scoreboard_table+i)->losesTotal,(scoreboard_table+i)->totalPoints);
    }
}

void Search(scoreboard *scoreboard_table, int size, char *searchTerm){ //search for name of team in scoreboard_table
    int i,j; //i = index of scoreboard_table array, j = index of name array inside scoreboard_table array
    char table_name[40]; //  will be used to convert scoreboard_table->name to uppercase and store it
    for (i=0;i<size;i++){  // for every element in scoreboard_table
        for (j=0;j<40;j++){  // for every character in the name of scoreboard_table[i]->name
            table_name[j]=toupper(*(((*(scoreboard_table+i)).name)+j)); //store the upper-case letter of scoreboard_table[i]->name[j] in table_name[j]
        }
        if (strcmp(table_name,searchTerm)==0){ 
        //if the search term is equal to table_name (which is uppercase version of scoreboard_table[i]->name), then print the statistics and break from the loop.
            printf("%s has %d win, %d lost and a total of %d points!\n",(scoreboard_table+i)->name,(scoreboard_table+i)->winsTotal,(scoreboard_table+i)->losesTotal,(scoreboard_table+i)->totalPoints);
            break;
        }
        else if(i==(size-1)){ 
        //   if it's the last element of scoreboard_table array and the search term is not equal to scoreboard_table[i]->name
        //   notify the user that their search term is not found in the scoreboard_table array
            printf("That team is unknown! Please try again!\n");
        }
    }
}

void interactive_board(scoreboard *scoreboard_table, int size, int sort){
    //this function sorts the scoreboard_table array using selection sort algorithm
    /*
    selection sort algorithm sorts an array by repeatedly finding the maximum element from unsorted part and putting it at the beginning.
    */
    int i,j,index;
    /*
    i is used in a for loop to get ith element of scoreboard_table
    j is used to determine when the sorting is complete
    (ie: if you have a list containing 5 elements, you need to sort the array 4 times at most(in this case, which is selection sort algorithm); 
    therefore j is used in a for loop : for (j=0;j<(sizeofArray-1);j++)
    j is also used to write into jth element of scoreboard_table
    */
    int max; //store the max value here
    scoreboard temp; //declare a struct named temp, will store temporary data when swapping variables of scoreboard_table array
    if (sort==1){ // if sorting based on games
        for (j=0;j<size-1;j++){ // explained above, iterate the code below (array) size-1 times
            max=(scoreboard_table+size-1)->games; //set max to the last element of the array since this is the unsorted part of array...
            index=size-1;                         //set index to index of last element of the array...
            for (i=j;i<size;i++){                 //no need to search elements with index less than j since they are already sorted
                                                  //therefore start searching elements from j till the last element
                if (max<((scoreboard_table+i)->games)){ 
                //if the value of current element > max, then the max value becomes this value and the index of the new max value is stored in index
                    max=(scoreboard_table+i)->games;
                    index=i;
                }
                if (i==(size-1)){ // swap the variables of scoreboard_table[index] with the variables of scoreboard_table[j]
                    //where j stands for the next unsorted member and index stands for the index of the largest variable
                    //copy contents of scoreboard_table[j] into temp (BACKUP)
                    strcpy(temp.name,(scoreboard_table+j)->name);
                    temp.games=(scoreboard_table+j)->games;
                    temp.losesAway=(scoreboard_table+j)->losesAway;
                    temp.losesHome=(scoreboard_table+j)->losesHome;
                    temp.losesTotal=(scoreboard_table+j)->losesTotal;
                    temp.totalPoints=(scoreboard_table+j)->totalPoints;
                    temp.winsAway=(scoreboard_table+j)->winsAway;
                    temp.winsHome=(scoreboard_table+j)->winsHome;
                    temp.winsTotal=(scoreboard_table+j)->winsTotal;
                    //copy contents of scoreboard_table[index] into scoreboard_table[j]
                    strcpy((scoreboard_table+j)->name,(scoreboard_table+index)->name);
                    (scoreboard_table+j)->games=(scoreboard_table+index)->games;
                    (scoreboard_table+j)->losesAway=(scoreboard_table+index)->losesAway;
                    (scoreboard_table+j)->losesHome=(scoreboard_table+index)->losesHome;
                    (scoreboard_table+j)->losesTotal=(scoreboard_table+index)->losesTotal;
                    (scoreboard_table+j)->totalPoints=(scoreboard_table+index)->totalPoints;
                    (scoreboard_table+j)->winsAway=(scoreboard_table+index)->winsAway;
                    (scoreboard_table+j)->winsHome=(scoreboard_table+index)->winsHome;
                    (scoreboard_table+j)->winsTotal=(scoreboard_table+index)->winsTotal;
                    //copy contents of temp (BACKUP) into scoreboard_table[index]
                    strcpy((scoreboard_table+index)->name,temp.name);
                    (scoreboard_table+index)->games=temp.games;
                    (scoreboard_table+index)->losesAway=temp.losesAway;
                    (scoreboard_table+index)->losesHome=temp.losesHome;
                    (scoreboard_table+index)->losesTotal=temp.losesTotal;
                    (scoreboard_table+index)->totalPoints=temp.totalPoints;
                    (scoreboard_table+index)->winsAway=temp.winsAway;
                    (scoreboard_table+index)->winsHome=temp.winsHome;
                    (scoreboard_table+index)->winsTotal=temp.winsTotal;
                }
            }
        }
    }
    else{ // if sorting based on points
        for (j=0;j<size-1;j++){ // explained above, iterate the code below (array) size-1 times
            max=(scoreboard_table+size-1)->totalPoints; //set max to the last element of the array since this is the unsorted part of array...
            index=size-1;                         //set index to index of last element of the array...
            for (i=j;i<size;i++){                 //no need to search elements with index less than j since they are already sorted
                                                  //therefore start searching elements from j till the last element
                if (max<((scoreboard_table+i)->totalPoints)){ 
                //if the value of current element > max, then the max value becomes this value and the index of the new max value is stored in index
                    max=(scoreboard_table+i)->totalPoints;
                    index=i;
                }
                if (i==(size-1)){ // swap the variables of scoreboard_table[index] with the variables of scoreboard_table[j]
                    //where j stands for the next unsorted member and index stands for the index of the largest variable
                    //copy contents of scoreboard_table[j] into temp (BACKUP)
                    strcpy(temp.name,(scoreboard_table+j)->name);
                    temp.games=(scoreboard_table+j)->games;
                    temp.losesAway=(scoreboard_table+j)->losesAway;
                    temp.losesHome=(scoreboard_table+j)->losesHome;
                    temp.losesTotal=(scoreboard_table+j)->losesTotal;
                    temp.totalPoints=(scoreboard_table+j)->totalPoints;
                    temp.winsAway=(scoreboard_table+j)->winsAway;
                    temp.winsHome=(scoreboard_table+j)->winsHome;
                    temp.winsTotal=(scoreboard_table+j)->winsTotal;
                    //copy contents of scoreboard_table[index] into scoreboard_table[j]
                    strcpy((scoreboard_table+j)->name,(scoreboard_table+index)->name);
                    (scoreboard_table+j)->games=(scoreboard_table+index)->games;
                    (scoreboard_table+j)->losesAway=(scoreboard_table+index)->losesAway;
                    (scoreboard_table+j)->losesHome=(scoreboard_table+index)->losesHome;
                    (scoreboard_table+j)->losesTotal=(scoreboard_table+index)->losesTotal;
                    (scoreboard_table+j)->totalPoints=(scoreboard_table+index)->totalPoints;
                    (scoreboard_table+j)->winsAway=(scoreboard_table+index)->winsAway;
                    (scoreboard_table+j)->winsHome=(scoreboard_table+index)->winsHome;
                    (scoreboard_table+j)->winsTotal=(scoreboard_table+index)->winsTotal;
                    //copy contents of temp (BACKUP) into scoreboard_table[index]
                    strcpy((scoreboard_table+index)->name,temp.name);
                    (scoreboard_table+index)->games=temp.games;
                    (scoreboard_table+index)->losesAway=temp.losesAway;
                    (scoreboard_table+index)->losesHome=temp.losesHome;
                    (scoreboard_table+index)->losesTotal=temp.losesTotal;
                    (scoreboard_table+index)->totalPoints=temp.totalPoints;
                    (scoreboard_table+index)->winsAway=temp.winsAway;
                    (scoreboard_table+index)->winsHome=temp.winsHome;
                    (scoreboard_table+index)->winsTotal=temp.winsTotal;
                }
            }
        }
    }
}

【问题讨论】:

  • 因为我现在很懒(嘿,“懒惰”是好的工程的驱动力.. 呵呵)--您使用调试器怎么样,这样您就可以告诉我们在哪里查看? :)
  • gets 不好。不要使用它。 stackoverflow.com/questions/1694036/…
  • 哦,是的。以及一些 *scanf() 中的普通 %s -> 溢出任何缓冲区。 禁止 gets()(出于充分的理由从 C 中删除)完全支持 fgets()scanf(),使用 字段宽度
  • 写这些 cmets,我看到你的结构中有 char *name,永远不要把它分配给一些有意义的指针,仍然把它提供给 scanf("%s", ... -- 肯定这会崩溃,scanf() 会尝试写到某个不确定的位置。

标签: c arrays memory-management struct


【解决方案1】:

你的代码有很多问题,比如。

首先,使用fgets() 而不是gets()。例如

fgets(fileName,sizeof(fileName),stdin);

其次namescoreboard的指针成员,先为其分配内存。例如

scoreboard_table->name = malloc(SIZE); /* define SIZE */

第三fgetc()返回类型为int。查看fgetc() 的手册页。所以char curChar; 应该是int curChar;

最后,在fscanf() 中存储整数时,您需要为每个参数提供&amp; 地址。例如

fscanf(inputFile,"%d",&(scoreboard_table+i)->games)

我尝试在 cmets 中进行解释。这是示例代码

void Load_Scoreboard_Table(char *, scoreboard *);
int main(void){
        char fileName[40], *ret = NULL;
        FILE *inputFile;
        while (1){
                printf("Enter the file name> ");
                /* make sure fileName gets correctly stored in buffer as expected  */
                ret = fgets(fileName,sizeof(fileName),stdin); /* use fgets() instead of gets() */
                if(ret == NULL) { /* if failed, check again */
                        continue;
                }
                else {
                        printf("%s",ret); /* if fgets() result is as expected, control comes here */
                        fileName[strlen(fileName)-1] ='\0';
                }
                inputFile = fopen(fileName,"r");
                if (inputFile != NULL){
                        break;
                }
                printf("ERROR: The file %s could not be opened.\n",fileName);
                printf("Please verify that the file exists.\n");
        }
        int listLength=0;
        int curChar; /*return type of fgetc() is int */
        while ((curChar=fgetc(inputFile))!=EOF){
                if (curChar=='\n'){
                        listLength++;
                }
        }
        fclose(inputFile);
        scoreboard *scoreboard_table = malloc(sizeof(scoreboard) * listLength);/* no need to cast the result of malloc() */
        scoreboard_table->name = malloc(100);/*name is pointer member, allocate memory for it. must */
        Load_Scoreboard_Table(fileName,scoreboard_table);

        /* don't forget to free dynamically allocated memory here  @TODO */
        return 0;
}

void Load_Scoreboard_Table(char *fileName,scoreboard *scoreboard_table){
        FILE *inputFile = fopen(fileName,"r");
        if(inputFile == NULL ) {
                /* some mesage,, error handling  @TODO*/
        }
        int i=0;
        while (fscanf(inputFile,"%s %d %d %d %d %d", (scoreboard_table+i)->name,&(scoreboard_table+i)->games,&(scoreboard_table+i)->winsHome,&(scoreboard_table+i)->losesHome,&(scoreboard_table+i)->winsAway,&(scoreboard_table+i)->losesAway) > 0){
                (scoreboard_table+i)->winsTotal = (scoreboard_table+i)->winsHome + (scoreboard_table+i)->winsAway;
                (scoreboard_table+i)->losesTotal = (scoreboard_table+i)->losesHome + (scoreboard_table+i)->losesAway;
                (scoreboard_table+i)->totalPoints = (((scoreboard_table+i)->winsTotal)*2) + (scoreboard_table+i)->losesTotal;
                i++;
        }
        for(int j =0 ;j<i;j++) {
                printf("%d %d %d \n",(scoreboard_table+j)->winsTotal,(scoreboard_table+j)->losesTotal,(scoreboard_table+j)->totalPoints);
        }
}

来自man 3 gets 为什么不应该使用gets() 原因在这里。

永远不要使用gets()。因为不知道是不可能说出来的 数据提前获取()将读取多少个字符, 并且因为 gets() 将继续存储超过缓冲区末尾的字符,所以使用它是非常危险的。它有 被用来破坏计算机安全。请改用 fgets()。

【讨论】:

  • 不,还是错了,伙计。您需要在打开警告的情况下进行编译。您没有检查 fgets 的返回值,只是假设它成功了。如果失败 fileName[strlen(fileName)-1] ='\0'; 是未定义的行为。测试echo -n "" | ./a.out
  • 为 OP 保留一些东西?我给出了足够的提示。
  • 感谢您抽出宝贵时间。我相信我理解了你的代码;但是当我编译它时。我得到了非常相似的结果。当我尝试输入 data.txt 时,程序仍然冻结
  • 为什么要投反对票?请说明原因。 已经在我的 cmets 中提到了原因。 不使用 -Wall 编译或忽略输出 - 这会在精心制作的输入上将发布的代码打开到 UB。
  • 嗨@PlagueTR 我修改了。现在检查。它应该可以工作,它在我的系统中工作。
【解决方案2】:

请特别注意fscanf() 的内容。必须传递int 变量的地址,这是代码崩溃的原因之一。

 while (fscanf(inputFile, "%s %d %d %d %d %d\n", 
 (scoreboard_table+i)->name, &(scoreboard_table+i)->games,
 &(scoreboard_table+i)->winsHome, &(scoreboard_table+i)->losesHome,
 &(scoreboard_table+i)->winsAway,&(scoreboard_table+i)->losesAway)!=EOF){

此外,您应该注意其他 cmets,例如不要使用gets()

char fileName[40], *p;

fgets(fileName, sizeof fileName, stdin);
if ((p = strchr(fileName, '\n')) != NULL) { 
    *p = '\0'; /* remove newline */
}

顺便说一下,结构中的char *name需要分配内存,这是另一个崩溃的原因,别忘了free

【讨论】:

  • 谢谢。我意识到我忘记为 char *name 分配内存。你能告诉我为什么我不应该使用gets()though 吗? (我一周前刚刚了解了 C 中的字符串。)是不是因为 gets() 没有任何保护措施可以防止人们输入的字符数超过 char 数组可以存储的字符数?
猜你喜欢
  • 2021-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多