2012-04-12 41 views
0

我在编码方面颇为新颖,并且使用链接列表和结构进行了艰难的分配。这个任务是制作一个音乐数据库,以便您可以读取艺术家专辑和曲目,并将它们存储在节点中。链接列表:读入txt文件,节点不保存

当前,当我运行程序时,从.txt文件中读取数据时没有存储节点。最终,我开始怀疑我使用某些指针是正确的,因为我正在分段错误。我做错了什么,是否有修复,我可以做到这一点将使其功能?

我的代码(需要的库已列入):

结构和宏定义:

#define LINEBUFFERSIZE 256 

struct song 
{ 
    char *songName_p; 
    int trackNumber; 
    struct song *nextSong_p; 
}; 

struct disc 
{ 
    char *discName_p; 
    int year; 
    struct song *song_p; 
    struct disc *nextDisc_p; 

}; 

struct artist 
{ 
    char name[20]; 
    char *artistName_p; 
    struct disc *disc_p; 
    struct artist *nextArtist_p; 
}; 
struct artist *end = (struct artist *) NULL; //NEW 
struct artist *startPtr = (struct artist *) NULL; //NEW 
struct artist *find(struct artist *, char *);//NEW 
//NEW 

类型定义:

typedef struct artist artist_t; 
typedef struct disc disc_t; 
typedef struct song song_t; 

typedef struct artist *artistNodePtr; 
typedef struct disc *discNodePtr; 
typedef struct song *songNodePtr; 

函数定义:

void InsertArtist(struct artist *New); 
artistNodePtr initializenode(char *name); 
artistNodePtr findOrInsertArtist(artistNodePtr *sPtr, char *name); 
discNodePtr findOrInsertDisc(discNodePtr *sPtr, char *discID, int releaseYear); 
void findOrInsertSong(songNodePtr *sPtr, char *songID, int trackID); 
void getNextLine(char buffer[], int bufferSize, FILE *fptr); 
void printlist(struct artist *ptr); 
void printnode(struct artist *ptr); 

主要方法:

int main(int argc, char *argv[]) 
{ 
    char name[20]; 
    struct artist *newNodePointer; 
    char lineBuffer[LINEBUFFERSIZE]; 
    artistNodePtr startPtr = NULL; /* initially the artist list is empty */ 
    FILE *musicFile; 
    char *artistTemp, *discTemp, *yearTemp, *trackTemp, *songTemp; 
    int year, track, menu = 1; 
    artistNodePtr theArtist; 
    // discNodePtr theDisc; 

    if (argc==1) 
    { 
     printf(" Must supply a file name as command line argument/n"); 
     return 0; 
    } 

    if ((musicFile = fopen(argv[1], "r")) == NULL) 
    { 
     printf ("Error opening music file. Program terminated/n"); 
     return 0; 
    } 

    getNextLine(lineBuffer, LINEBUFFERSIZE, musicFile); 
    while (!feof(musicFile)) 
    { 
     artistTemp = strtok(lineBuffer,";"); 
     if (artistTemp == NULL) 
     { 
      printf("Error parsing input file; Program is terminated\n"); 
      return 0; 
     } 
     discTemp = strtok(NULL ,";"); 
     if (discTemp == NULL) 
     { 
      printf("Error parsing input file; Program is terminated\n"); 
      return 0; 
     } 
     yearTemp = strtok(NULL ,";"); 
     if (yearTemp == NULL) 
     { 
      printf("Error parsing input file; Program is terminated\n"); 
      return 0; 
     } 
     trackTemp = strtok(NULL ,";"); 
     if (trackTemp == NULL) 
     { 
      printf("Error parsing input file; Program is terminated\n"); 
      return 0; 
     } 
     songTemp = strtok(NULL ,"\n"); 
     if (songTemp == NULL) 
     { 
      printf("Error parsing input file; Program is terminated\n"); 
      return 0; 
     } 
     year = atoi(yearTemp); 
     track = atoi(trackTemp); 
     theArtist = findOrInsertArtist(&startPtr, artistTemp); 
    // theDisc = findOrInsertDisc(&(theArtist->disc_p), discTemp, year); 
     //findOrInsertSong(&(theDisc->song_p), songTemp, track); 
     getNextLine(lineBuffer, LINEBUFFERSIZE, musicFile); 
    } /* end of while loop */ 

    while (menu != 0) 
    { 
     printf("1 to display entire catalog \n"); 
     printf("2 to display alls songs by a given artist\n"); 
     printf("3 to display all songs on a given disc\n"); 
     printf("0 to exit the library\n "); 
     scanf("%d", &menu); 
     switch (menu){ 
     case 1: printlist(startPtr); 
      break; 

     case 2: 
      printf("enter an artist name"); 
      scanf("%s", name); 
      newNodePointer = find(startPtr, name); 
      if (newNodePointer==NULL) 
      { 
       newNodePointer = initializenode(name); 
       InsertArtist(newNodePointer); 
      } 

     } 
    } /* end main */ 
} 

功能定义:

artistNodePtr findOrInsertArtist(artistNodePtr *sPtr, char *name) 
    { 

sPtr = initializenode(name); 
    InsertArtist(sPtr); 

    if(!sPtr) 
     sPtr = find(startPtr, name); 
    return sPtr; 
} 
void printlist(struct artist *ptr){ 
    while(ptr!= NULL){ 
    printnode(ptr); 
    ptr = ptr->nextArtist_p; 
    } 
    } 
void printnode(struct artist *ptr) 
{ 
    printf("Name %s\n", ptr->name); 

} 

artistNodePtr initializenode(char *name) 
{ 

    struct artist *newNodePtr = (artistNodePtr)malloc(sizeof(artist_t)); 
    if (newNodePtr != NULL) 
    { 
     newNodePtr->artistName_p = (char*)malloc((strlen(name)+1)*sizeof(char)); 
     if (newNodePtr->artistName_p != NULL) 
     { 
      strcpy(newNodePtr->artistName_p, name); 
      newNodePtr->nextArtist_p = NULL; 
      newNodePtr->disc_p = NULL; 

      return newNodePtr; 
     } 
    } 
} 

void InsertArtist(struct artist *New) 
    { 
    //NEW 
    struct artist *temp, *prev; 

    if(startPtr == NULL) 
    { 
     startPtr = New; 
     end = New; 
     startPtr->nextArtist_p = NULL; 
     return; 
    } 
    temp = startPtr; 

    while(strcmp(temp->name, New->name) < 0) 
    { 
     temp = temp->nextArtist_p; 
     if(temp == NULL) 
      break; 
    } 
    if(temp == startPtr) 
    { 
     New->nextArtist_p = startPtr; 
     startPtr = New; 
    } 
    else 
    { 
     prev = startPtr; 
     while(prev->nextArtist_p != temp) 
     { 
      prev = prev->nextArtist_p; 
     } 
     prev->nextArtist_p = New; 
     New-> nextArtist_p = temp; 
      if(end == prev) 
      end = New; 
    } 
} 

struct artist *find(struct artist *newNodePointer, char *name) 
{ 
    //NEW 
    while (strcmp(name, newNodePointer->name)!=0) 
    { 
     newNodePointer = newNodePointer->nextArtist_p; 
     if (newNodePointer == NULL) 
      break; 
    } 
    return newNodePointer; 
} 


void getNextLine(char buffer[], int bufferSize, FILE *fptr) 
{ 
    char temp; 
    int i = 0; 

    buffer[0] = fgetc(fptr); 
    while ((!feof(fptr)) && (buffer[i] != '\n') && i<(bufferSize-1)) 
    { 
     i = i +1; 
     buffer[i]=fgetc(fptr); 
    } 

    if ((i == (bufferSize-1)) && (buffer[i] != '\n')) 
    { 
     temp = fgetc(fptr); 
     while (temp != '\n') 
     { 
      temp = fgetc(fptr); 
     } 
    } 

    buffer[i] = '\0'; 
}  
+3

作为一个开始如果你正在使用GCC,编译时,'gcc -Wall -Wextra -pedantic -o myprog myprog.c' – Morpfh 2012-04-12 02:34:01

+0

我强烈建议用'getline(3)'替换getNextLine',如果你在Linux系统上运行或另一个符合POSIX.1-2008标准的系统。我有一种感觉,你所有的'typedefs'都增加了比有用的快捷键更多的噪音 - 我更喜欢普通的'struct foo'名字,我和我_detest_“指针”typedefs--我宁愿知道我什么时候到达使用指针。你不应该从'malloc(3)'强制返回值;这样做可以隐藏非常有用的警告。在你的三个指针'songName_p','discName_p'和'artistName_p'中,只有后者分配了任何内存。错误? – sarnold 2012-04-12 02:38:15

+0

在使用歌曲和光盘之前,我将先测试出artistName_p。我怎么知道是否正在读取txt文件?在comman争论的一行中,我输入了文件.txt的名称:HW4Data.txt。是创建语法?我正在使用代码块 – user1325578 2012-04-12 03:00:43

回答

1

还有一堆类型的错误,将溢出与-Wall(由@ user120115的建议)。

是跳出马上有几件事情:

  • 不投malloc(C语言,甚至不使用malloc在C++中,除非有一些很好的理由,以避免new
  • 任何形式为while (!feof(stream))的循环可能都是错误的,因为feof不能预测未来的EOF,它只会告诉您为什么之前的读取尝试失败(例如,为什么getchar返回EOF)。 feof这一点是为了区分由于文件结束导致的“正常”读取失败和由于磁盘驱动器被触发或其他原因导致的“异常”(ferror)读取失败。
  • InsertArtist需要修改一个列表,因此它要么必须返回新的列表,要么将指针指向旧的指向列表的指针,但它不会。 (但各种findOrInsert功能呢!)

我也是对限制使用typedef @sarnold,虽然这是无可否认的喜好问题。

1

作为开始进行编译,如果你使用的GCC,

的gcc -Wall -pedantic -Wextra -o MYPROG MYPROG。ç

在我的系统我得到:

song.c: In function ‘main’: 
song.c:75:16: warning: variable ‘theArtist’ set but not used [-Wunused-but-set-variable] 
song.c:74:12: warning: variable ‘track’ set but not used [-Wunused-but-set-variable] 
song.c:74:6 : warning: variable ‘year’ set but not used [-Wunused-but-set-variable] 

song.c: In function ‘findOrInsertArtist’: 
song.c:162:7: warning: assignment from incompatible pointer type [enabled by default] 
song.c:163:2: warning: passing argument 1 of ‘InsertArtist’ from incompatible pointer type [enabled by default] 
song.c:50:6 : note: expected ‘struct artist *’ but argument is of type ‘struct artist **’ 
song.c:166:8: warning: assignment from incompatible pointer type [enabled by default] 
song.c:167:2: warning: return from incompatible pointer type [enabled by default] 

song.c: In function ‘initializenode’: 
song.c:197:1: warning: control reaches end of non-void function [-Wreturn-type] 

song.c: In function ‘main’: 
song.c:158:1: warning: control reaches end of non-void function [-Wreturn-type] 

应特别谨慎,一切,但-Wunused,然后检查是否应该已经用于那些未使用的变量,有一些失败的代码逻辑。

然后,当你设法编译没有警告的valgrind与运行程序(如果在Windows上我不知道,也许你可以在这里找到一些有用的东西:is-there-a-good-valgrind-substitute-for-windows


编辑:
我注意你说你使用Code :: Blocks。我会推荐使用像Vim这样的编辑器+在命令行编译。特别是开始。

即便如此;如上面提到的评论,你可以将修改警告级别:

"Settings" > "Compiler and debugger ..." > [Compiler Flags]=>[Warnings] 

获得调试添加-ggdb[Other options]。如果你只是想改变这种对项目基地 - 你会发现在相同的选择:

"Project" > "Build options ..." 

当您与您可以运行在调试模式下的程序调试符号编译。

简单的过程:

  1. 右键点击你的代码,你希望停止执行地方。选择“切换断点”。

  2. F8以调试模式启动程序。

  3. 然后按F7逐行逐行。

  4. ...(基本按键在 “调试” 菜单)。

在运行时,你也可以右键单击一个变量,然后选择观看,即“看 'discTemp' “。如果不存在,请选择“调试”>“调试窗口”>“手表”。

现在您将看到变量的值等,当您通过代码时。

gdb也可以在命令行上使用。 $ gdb -args ./my_prog arg arg

Valgrind,如前所述,也是一个非常有用的工具。您将在您的过程中获得有关不良行为的信息。即使代码编译没有错误或警告,但并不是说该程序是理智的。

Valgrind是在代码::块还实施,更好的或许应该说:

$ valgrind ./my_prog arg arg ... 

而且作为最后一点:编译所有的时间。写几行。编译。进行一次更改编译。 ...


这些是关于如何使编码更不痛苦的一些提示。希望能帮助到你。


除了被其他人所提到的注意事项在这里我也想补充一下:

  • 在你menu循环,你不得不如果scanf()返回1,(1为成功检查阅读元素,在你的情况下“%d”) - 如果没有,则为空缓冲区。因为现在只有一个整数会导致无限循环。

  • getNextLine()你有一个while()循环结束,说get character from file while character is not newline.如果文件不以换行符结束这是另一个无限循环。还请阅读@sarnold和@torek关于此功能的评论。


PS:要添加命令行参数的代码::块,你必须使用:

“项目”> “设置程序的参数”