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

时间:2016-01-14 22:05:16

标签: c arrays

我正在学习C并尝试编写程序来保存音乐信息。 我正在阅读包含以下内容的文件:

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

尝试进行相当基本的操作 - 查看每行直到EOF,抓取内容,使用','作为分隔符进行标记,将字符串的每个部分存储到3个变量中,将这3个变量存储到全局使用全局索引的数组,它在main中定义,如

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

我写的函数如下所示,其中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;
}

看起来它工作正常,但是,当我尝试在return语句之前进行简单的内容打印时,我得到了垃圾返回数据。

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

的产率:

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

当我尝试在另一个函数中使用几乎完全相同的while循环时,我得到更多的垃圾数据输出。

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

歌曲结构如下所示

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

我怀疑这个问题有一个简单的解决方案:与变量的类型定义有关,缺少* /&amp;或者不以&#39; \ 0&#39;结尾。 - 我不确定是什么导致了这一点。

2 个答案:

答案 0 :(得分:3)

而不是while (!feof(fp)) { if (fgets(fileOut, 1024, fp) != NULL) {只使用:

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

请注意,使用strtok进行解析是草率的:艺术家将以空格开头,年份将以空格开头并包含最终换行符。使用指针并手动解析会更精确。

您必须存储字符串的副本:

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

处理数据时,您可能需要free这些字符串,除非您退出程序,在这种情况下free不是必需的,但仍建议帮助跟踪潜在的内存泄漏。

在成功存储条目后,再增加newCount++;

根据您的说明,您还应将newCount存储到全局变量globalCounter

您的打印循环应使用counter而不是newCount

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

以下是更正后的版本:

#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;     
}

答案 1 :(得分:1)

您需要复制字符串。你不只是保持指向strtok返回的指针。 (并且您应该检查strtok和strdup的返回值是否有错误,并在完成Song记录时释放内存)。 您过早地迭代索引(跳过索引0) 您对返回值的测试是在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++;
    }

}

测试:

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