0

私はコーディングにかなり慣れていないので、リンクリストと構造を使用して難しい割り当てを与えられました。課題は、アーティストのアルバムやトラックを読み取ってノードに保存できるように、音楽データベースを作成することです。

現在、プログラムを実行すると、.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:

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';
}    
4

2 に答える 2

1

-Wall(@ user120115 で提案されているように)で溢れ出る型エラーがたくさんあります。

すぐに飛び出すいくつかのこと:

  • キャストしないでください (C では。回避する正当な理由がない限り、C++mallocでも使用 しないでください)mallocnew
  • は将来の EOF を予測せず、以前の読み取り試行が失敗した理由 (たとえば、なぜ返されたのか) のみを通知するため、フォームのループwhile (!feof(stream))はおそらく間違っています。のポイントは、ファイルの終わりによる「通常の」読み取り失敗と、ディスク ドライブの火災などによる「異常な」( ) 読み取り失敗を区別することです。feofgetcharEOFfeofferror
  • InsertArtistリストを変更する必要があるため、新しいリストを返すか、古いリストへのポインターへのポインターを取得する必要がありますが、どちらも行いません。(しかし、さまざまなfindOrInsert機能はそうです!)

これは確かに好みの問題ですが、私は @sarnold と一緒に の使用を制限していますtypedef

于 2012-04-12T02:41:41.410 に答える
1

GCCを使用している場合は、最初にコンパイルします。

gcc -Wall -Wextra -pedantic -o myprog myprog.c

私のシステムでは、次のようになります。

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て、1 行ずつ進めます。

  4. ... (基本的なキーは「デバッグ」メニューにあります。)

実行中に、変数を右クリックしてWatch、つまり"watch 'discTemp'"を選択することもできます。存在しない場合は、[デバッグ] > [ウィンドウのデバッグ] > [ウォッチ] を選択します。

コードをステップ実行すると、変数の値などが表示されます。

gdbコマンドラインでも使用できます。$ gdb -args ./my_prog arg arg

前述のように、Valgrind も非常に便利なツールです。プロセスの悪い動作に関する情報が得られます。コードがエラーや警告なしでコンパイルされたとしても、プログラムが正常であるとは言えません。

Valgrind は Code::Blocks にも実装されています。

$ valgrind ./my_prog arg arg ...

最後に、常にコンパイルしてください。数行書きます。コンパイル。1 つの変更をコンパイルします。...


これらは、コーディングの苦痛を軽減する方法に関するいくつかのヒントです。それが役に立てば幸い。


ここで他の人が言及したメモに加えて、次のことも追加したいと思います。

  • menuループでは、 1 を返すかどうか確認する必要がありますscanf()(1 は要素を正常に読み取った場合、この場合は "%d")。そうでない場合は、バッファーを空にします。現在、整数以外のものであるため、無限ループが発生します。

  • 最後に、ファイルが改行で終わらない場合、これは別の無限ループであるというループがありgetNextLine()ます。この関数に関する @sarnold と @torek のコメントもお読みください。while()get character from file while character is not newline.


Ps: Code::Blocks にコマンド ライン引数を追加するには、次を使用する必要があります。

「プロジェクト」 > 「プログラムの引数を設定」

于 2012-04-12T02:41:49.753 に答える