简体   繁体   English

尝试将文件中的值存储到C中的数组中

[英]Trying to store values from file into array in C

I'm learning C and trying to write a program to hold music information. 我正在学习C,并试图编写一个程序来保存音乐信息。 I'm reading from a file with the following contents: 我正在读取具有以下内容的文件:

Hello,Adele,2015
Sorry,Justin Bieber,2015
X Gon Give It To Ya,DMX,2002

And trying to do a fairly basic operation - look at each line until EOF, grab the content, tokenize using ',' as delimiter, store each part of the string into 3 variables, store those 3 variables into the global array using the global index, which is defined in main like this 并尝试执行一个相当基本的操作-查看每行直到EOF,抓取内容,使用','作为定界符标记化,将字符串的每个部分存储到3个变量中,使用全局索引将这3个变量存储到全局数组中,在main中这样定义

Song SongList[1024];
int globalCounter;
globalCounter = 0;

The function I wrote looks like this, where fp is a successfully opened file, SongList is an array of Song structures and globalCounter is the global index of current position in array. 我编写的函数如下所示,其中fp是一个成功打开的文件, SongListSong结构的数组,而globalCounter是该数组中当前位置的全局索引。

int getFileData(FILE *fp, Song *SongList, int globalCounter) {
    int newCount = globalCounter;
    char fileOut[1024];
    int lineno = 0;

    while (!feof(fp)) {
        if (fgets(fileOut, 1024, fp) != NULL) {
            newCount++;
            char *tokenizer;
            char *fileTitle;
            char *fileArtist;
            char *fileYear;

            tokenizer = strtok(fileOut, ",");
            int counter = 0;
            fileTitle = tokenizer;
            counter++;
            while (tokenizer != NULL) {
                tokenizer = strtok(NULL, ",");
                if (counter == 1)
                    fileArtist = tokenizer;
                if (counter == 2)
                    fileYear = tokenizer;
                counter++; 
            }

            SongList[newCount].title = fileTitle;
            SongList[newCount].artist = fileArtist;
            SongList[newCount].year = fileYear;
            // prints the right values
            printf("%i\n", newCount);
            printf("TITLE: %s\n", SongList[newCount].title); 
            printf("ARTIST: %s\n", SongList[newCount].artist);
            printf("YEAR: %s\n", SongList[newCount].year);
        }
    }
    return newCount;
}

It looks like it works fine, however, when I try to do a simple print of contents before the return statement, I get garbage return data. 看起来工作正常,但是,当我尝试在return语句之前简单地打印内容时,我得到了垃圾返回数据。

int counter = 0;
while (counter < newCount) {
    printf("%s, %s, %s", SongList[newCount].title, SongList[newCount].artist, SongList[newCount].year);
    counter++;
}

yields: 收益率:

X Gon Give It To Ya, DMX, 2002X Gon Give It To Ya, DMX, 2002X Gon Give It To Ya, DMX, 2002

When I try to use pretty much the exact same while loop in another function, I get even more garbage data output. 当我尝试在另一个函数中使用几乎完全相同的while循环时,我得到了更多的垃圾数据输出。

(null), (null), (null), , ╨╦a, , DMXm

The song structure looks like this 歌曲的结构看起来像这样

typedef struct Song {
    char *title;
    char *artist;
    char *year; 
} Song;

I suspect the problem has a simple solution: something to do with type definitions of variables, missing */&, or not ending with '\\0' - I'm not sure what is causing this though. 我怀疑问题有一个简单的解决方案:与变量的类型定义有关,缺少* /&,或者不以'\\ 0'结尾-我不确定是什么原因造成的。

Instead of while (!feof(fp)) { if (fgets(fileOut, 1024, fp) != NULL) { just use: 而不是while (!feof(fp)) { if (fgets(fileOut, 1024, fp) != NULL) {

   while (fgets(fileOut, 1024, fp) != NULL) {

Note that your parsing with strtok is sloppy: the artist will start with a space, the year will start with a space and include the final line feed. 请注意,您使用strtok的解析是草率的:艺术家将以空格开头,年份将以空格开头并包含最后的换行符。 Using a pointer and parsing by hand would be more precise. 使用指针并手动解析会更精确。

You must store copies of the strings: 您必须存储字符串的副本:

       SongList[newCount].title = strdup(fileTitle);
       SongList[newCount].artist = strdup(fileArtist);
       SongList[newCount].year = strdup(fileYear);

You may want to free these strings when you are done processing the data, unless you exit the program, in which case free is not necessary, but still recommended to help track potential memory leaks. 您可能需要在处理完数据后free这些字符串,除非退出程序,在这种情况下,不需要free ,但仍建议使用它来帮助跟踪潜在的内存泄漏。

Also increment newCount++; 还增加newCount++; after successfully storing the entry. 成功存储的条目。

According to your description, you should also store newCount to the global variable globalCounter . 根据你的描述,你也应该存储newCount全局变量globalCounter

Your printing loop should use counter instead of newCount : 您的打印循环应使用counter而不是newCount

    int counter = 0;
    while (counter < newCount) {
        printf("%s, %s, %s\n",
               SongList[counter].title, 
               SongList[counter].artist, 
               SongList[counter].year);
        counter++;
    }

Here is a corrected version: 这是更正的版本:

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

typedef struct Song {
    char *title;
    char *artist;
    char *year; 
} Song;

Song SongList[1024];
int globalCounter = 0;

int getFileData(FILE *fp, Song *SongList, int *globalCounter) {
    int newCount = *globalCounter;
    char fileOut[1024];

    while (newCount < 1024 && fgets(fileOut, 1024, fp) != NULL) {
        char *p = fileOut;
        char *fileTitle;
        char *fileArtist;
        char *fileYear;

        fileTitle = p;
        if ((p = strchr(p, ',')) == NULL)
            continue;
        *p++ = '\0';
        p += strspn(p, " \t");  /* skip blank characters */
        fileArtist = p;
        if ((p = strchr(p, ',')) == NULL)
            continue;
        *p++ = '\0';
        p += strspn(p, " \t");  /* skip blank characters */
        fileYear = p;
        p += strcspn(p, ",\n");  /* skip to ',' or '\n' or end of string */
        *p = '\0';

        SongList[newCount].title = strdup(fileTitle);
        SongList[newCount].artist = strdup(fileArtist);
        SongList[newCount].year = strdup(fileYear);

        // prints the right values
        printf("%i\n", newCount);
        printf("TITLE: %s\n", SongList[newCount].title); 
        printf("ARTIST: %s\n", SongList[newCount].artist);
        printf("YEAR: %s\n\n", SongList[newCount].year);
        newCount++;
    }
    return *globalCounter = newCount;
}

int main() {
    FILE *fin;

    if ((fin = fopen("test.txt", "r")) != NULL) {
        getFileData(fin, SongList, &globalCounter);
        fclose(fin);
    }
    for (int counter = 0; counter < globalCounter; counter++) {
        printf("%s, %s, %s\n",
            SongList[counter].title,
            SongList[counter].artist,
            SongList[counter].year);
        counter++;
    }
    return 0;     
}

You need to duplicate the string. 您需要复制字符串。 You do not just keep a pointer to the strtok return. 您不仅要保留指向strtok返回的指针。 (And you should check the return value of strtok and strdup for errors and deallocate the memory when done with a Song record). (并且您应该检查strtok和strdup的返回值是否有错误,并在完成Song记录后释放内存)。 You are iterating the index too soon (skipping index 0). 您太早迭代索引了(跳过索引0)。
And your testing of the return value is indexing the same last position in the for loop. 您对返回值的测试将索引for循环中的相同最后位置。

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

typedef struct Song 
{
    char* title;
    char* artist;
    char* year; 
} Song;

Song SongList[1024];
int globalCounter = 0;


int getFileData(FILE* fp, Song* SongList, int globalCounter)
{
    int newCount = globalCounter;
        char fileOut[1024];
        int lineno = 0;
        while (!feof(fp))
        {
            if (fgets(fileOut,1024,fp) != NULL)
            {
                char *tokenizer;
                //char* fileTitle;
                //char* fileArtist;
                //char* fileYear;

                tokenizer = strtok(fileOut, ",");
                int counter = 0;
                SongList[newCount].title = strdup( tokenizer );
                //fileTitle = tokenizer;
                counter++;
                while(tokenizer != NULL)
                {
                    tokenizer = strtok(NULL, ",");
                    if(counter == 1)
                        SongList[newCount].artist = strdup( tokenizer );
                    //    fileArtist = tokenizer;
                    if(counter == 2)
                        SongList[newCount].year = strdup( tokenizer );
                    //    fileYear = tokenizer;
                    counter++; 
                }

                //SongList[newCount].title = fileTitle;
                //SongList[newCount].artist = fileArtist;
                //SongList[newCount].year = fileYear;
                // prints the right values
                printf("%i\n",newCount);
                printf("TITLE: %s\n", SongList[newCount].title); 
                printf("ARTIST: %s\n", SongList[newCount].artist);
                printf("YEAR: %s\n", SongList[newCount].year);
                newCount++;
            }
        }
    return newCount;
}

int main()
{
    FILE * fin = fopen( "test.txt", "rt" );
    int newCount = getFileData( fin, SongList, globalCounter );
    int counter = 0;
    while(counter < newCount){
        printf("%s, %s, %s",SongList[counter].title,SongList[counter].artist,SongList[counter].year);
        counter++;
    }

}

Test: 测试:

1212:/tmp$ g++ test.cpp  && ./a.out 
0
TITLE: Hello
ARTIST: Adele
YEAR: 2015

1
TITLE: Sorry
ARTIST: Justin Bieber
YEAR: 2015

2
TITLE: X Gon Give It To Ya
ARTIST: DMX
YEAR: 2002

Hello, Adele, 2015
Sorry, Justin Bieber, 2015
X Gon Give It To Ya, DMX, 2002

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM