Damien Borowski
Damien Borowski

Reputation: 37

How to coordinate lines of input into related arrays

so i have this program which asks the user to provide as input from the command line an artist name. At most 4 artists can be provided as input. For each artist, at least 1 and at most 3 songs could be provided. the issue i have is when i print the artists and playlist out, i keep getting some random symbols as output and no words. im not sure whats the mistake here. can someone help or direct me in some direction? (i know the program isnt done, i just wanted to get this working first)

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


int main(void)
{
    //The array containing artists names
    char artists[4][80];
    //The array containing the sorted artists
    char sortedArtists[4][80];
    //Songs for Artist 1
    char songsArtist1[3][80];
    //Songs for Artist 2
    char songsArtist2[3][80];
    //Songs for Artist 3
    char songsArtist3[3][80];
    //Songs for Artist 4
    char songsArtist4[3][80];
    //The total number of artists (Note it can be less than 4)
    int numOfArtists =0;
    //The total number of songs for each artist (Note that less than 3 songs can 
    be provided for each artist)
    int numSongsPerArtist[4];

    int i,j;

    /*
    * Use here functions that you should implement to insert artists and songs 
    from the standard input.
    * Note that you also need to track the number of artists and the number of 
    songs for each artist.
    */
    for(i=1; i<=1; i++) {
        printf("Insert artist/group name");
        fgets(artists[i], 80, stdin);

        for(j=1; j<=3; j++) {
            if(i==1) {
                printf("Insert song %d for %s",j,artists[i]);
                fgets(songsArtist1,80,stdin);
            }
            if(i==2) {
                printf("Insert song %d for %s",j,artists[i]);
                fgets(songsArtist2,80,stdin);
            }
            if(i==3) {
                printf("Insert song %d for %s",j,artists[i]);
                fgets(songsArtist3,80,stdin);
            }
            if(i==4) {
                printf("Insert song %d for %s",j,artists[i]);
                fgets(songsArtist4,80,stdin);
            }

        }
        if(artists[i][0] !=' ' && artists[i][1] !=' ') {
            numOfArtists
        }
    }

    for(i=1; i<=4; i++) {
        printf("%s\n", artists[i]);
        for(j=1; j <=3; j++) {
            if(i==1) {
                printf("%s",songsArtist1[j]);
            }
            if(i==2) {
                printf("%s",songsArtist2[j]);
            }
            if(i==3) {
                printf("%s",songsArtist3[j]);
            }
            if(i==4) {
                printf("%s",songsArtist4[j]);
            }
        }
    }

    /*
    * Use here the function sortArtists to sort the array of the artists and sortSongs to sort the songs of each artist
    * Print each artist (alphabetically) and for each of them print the list of songs sorted alphabetically
    */

    /*
    * Use here the function shuffleSongs to shuffle all the songs
    * Print the list of shuffled songs
    */
    return 0;
}

Upvotes: 0

Views: 96

Answers (1)

David C. Rankin
David C. Rankin

Reputation: 84579

Damien, if you are still stuck on your problem reading the artist/group and songs, the two biggest parts of your problem (other than your zero indexing misunderstanding) are handling the input you take from the user, properly trimming the '\n' characters included by fgets, and then properly coordinating the relationship between the artist/group and songs. Your problems have little or nothing to do with Printing a 2D Array.

C provides a struct that is tailor made to allow you to coordinate related information of differing types. This is what you are attempting to accomplish. When you individually declare array1, array2, etc.. to hold artist/group and then independently declare arraysong1, arraysong2, etc.. there is no relationship between the artist/group and the songs other than the array names (which is no way to manage the relationship). Instead, you could declare a struct to provide that relationship (and the constants to prevent magic numbers in your code), e.g.

#define NSONGS 3
#define NARTISTS 4
#define MAXC  80

typedef struct {
    char name[MAXC],            /* storage for name/group */
        songs[NSONGS][MAXC];    /* storage for songs */
    int nsaved;                 /* number songs currently saved */
} artists;

Now you simply declare an array of artists (initialized to all zero), e.g.

    artists a[NARTISTS] = {{ .name = "" }};

and you have an array of structs you can fill with artist/group and up to NSONGS songs each while preserving the proper relationship as to which artist/group sings what songs.

Now for what goes in the artist/group name and what goes into songs, you have done a good job by choosing fgets for user input. That avoids many of the pitfalls associated with taking input with scanf. However, there are a couple additional steps you must take to prevent storing the trailing '\n' that fgets (and POSIX getline) includes in the buffer it fills. It is a simple process of getting the length of the string stored by fgets and then checking and overwriting the '\n' at the end of the buffer with a nul-terminating character (e.g. 0 or '\0')

Putting those pieces together, you could read your data into an array of stuct and then write a simple print function (or functions) to output your data (I used 4-songs per artist in the example below). You will then simply need to write a compare function for qsort to handle the sorting of your artists and song (there are plenty of examples on this site -- that is left for you)

A short example would be:

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

#define NSONGS 4
#define NARTISTS NSONGS
#define MAXC  80

typedef struct {
    char name[MAXC],            /* storage for name/group */
        songs[NSONGS][MAXC];    /* storage for songs */
    int nsaved;                 /* number songs currently saved */
} artists;

void prnsongs (artists *a);
void prncollection (artists *a, int n);

int main (void) {

    int n = 0;                  /* counter for artists */
    char buf[MAXC] = "";        /* buffer for input */
    /* array of struct initialized all zero */
    artists a[NARTISTS] = {{ .name = "" }};

    while (n < NARTISTS) {      /* loop until we fill all artists */
        size_t len = 0;         /* length of input to allow '\n' trim */

        printf ("\nenter artists/group name: ");    /* prompt */
        fflush (stdout);        /* precaution to insure prompt displayed */
        if (!fgets (buf, MAXC, stdin)) {    /* read artist/group name */
            fprintf (stderr, "user canceled input - artists.\n");
            break;
        }
        len = strlen (buf);     /* get length of artist/group */
        if (len && buf[len - 1] == '\n')    /* check last char '\n' */
            buf[--len] = 0;     /* overwrite with nul-terminating char */
        else if (len == MAXC - 1) { /* otherwise name too long - bail */
            fprintf (stderr, "error: name exceeds %d chars.\n", MAXC);
            exit (EXIT_FAILURE);
        }
        strcpy (a[n].name, buf);    /* copy buf to artist.name */

        while (a[n].nsaved < NSONGS) {    /* loop until songs filled */
            printf ("  %s - song[%d]: ", a[n].name, a[n].nsaved + 1);
            if (!fgets (buf, MAXC, stdin)) {
                fprintf (stderr, "user canceled input - songs.\n");
                break;
            }
            len = strlen (buf); /* same length & trim for each song */
            if (len && buf[len - 1] == '\n')
                buf[--len] = 0;
            else if (len == MAXC - 1) {
                fprintf (stderr, "error: name exceeds %d chars.\n", MAXC);
                exit (EXIT_FAILURE);
            }   /* copy song to a[n].songs[x], increment .nsaved */
            strcpy (a[n].songs[a[n].nsaved++], buf);
        }
        n++;    /* increment artist index */
    }

    printf ("\n=== Stored Collection of Artists & Songs ===\n");
    prncollection (a, n);   /* print all artists and songs */

    return 0;
}

/* simple function to print songs for artist */
void prnsongs (artists *a)
{
    int i;

    for (i = 0; i < a->nsaved; i++)
        printf ("  song[%d] - %s\n", i + 1, a->songs[i]);
}

/* simple function to print artists & songs */
void prncollection (artists *a, int n)
{
    int i;

    for (i = 0; i < n; i++) {
        printf ("\nartist/group: %s\n", a[i].name);
        prnsongs (&a[i]);   /* & - to pass pointer to struct */
    }
}

(note the print function was written in two logical pieces and you could have passed the structure to prnsongs itself, but passing a pointer is a bit more efficient)

Example Use/Output

$ ./bin/artist_songs

enter artists/group name: elvis
  elvis - song[1]: bs shoes
  elvis - song[2]: hh burning love
  elvis - song[3]: hound dog
  elvis - song[4]: lm tender

enter artists/group name: nirvana
  nirvana - song[1]: hs box
  nirvana - song[2]: bloom
  nirvana - song[3]: dumb
  nirvana - song[4]: as you are

enter artists/group name: peal jam
  peal jam - song[1]: alive
  peal jam - song[2]: daughter
  peal jam - song[3]: animal
  peal jam - song[4]: jeremy

enter artists/group name: buffet
  buffet - song[1]: changes in lattitude
  buffet - song[2]: fins
  buffet - song[3]: margaritaville
  buffet - song[4]: went to paris

=== Stored Collection of Artists & Songs ===

artist/group: elvis
  song[1] - bs shoes
  song[2] - hh burning love
  song[3] - hound dog
  song[4] - lm tender

artist/group: nirvana
  song[1] - hs box
  song[2] - bloom
  song[3] - dumb
  song[4] - as you are

artist/group: peal jam
  song[1] - alive
  song[2] - daughter
  song[3] - animal
  song[4] - jeremy

artist/group: buffet
  song[1] - changes in lattitude
  song[2] - fins
  song[3] - margaritaville
  song[4] - went to paris

So the bulk of your problem had nothing to do with printing 2D arrays, your problem was basic data handling and handling the user input provided by fgets. Look things over and let me know if you have further questions (and try to use a more descriptive and accurate title for your question next time)

Upvotes: 2

Related Questions