erykkk
erykkk

Reputation: 119

C - easiest way to combine and alter 2 2D arrays of strings into larger 2D array

I would like to create a function for my program which takes 2 2D arrays, the first containing the name of an artist and the second containing the songs of said artists, place the artist name at the start of the array, followed by a " - ", then followed by the song name as such:

Artist1 - Song 1.

Artist1 - Song 2.

..

..

Artist4 - Song 3.

I have created the prototype for such function:

int amalgamateArtistsAndSongs (char amalgamatedSongs[][163],char artists[][80],
        char songsOfAnArtists[][80],int numOfSongs[],int pos);

Declarations of arrays:

    //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];
    //Array which holds amalgamated artist and song names -> (Artists - Song Name).
    char amalgamatedSongs[12][163];
    //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] = {0,0,0,0};

I have included int numSongsPerArtist; because it can occur that an artist has less than 3 songs, as to avoid Artistx - "blank" appearing in amalgamatedSongs[][]

I have attempted to create this function using strcpy() and strcat(), but it doesn't seem to work the way I would like it to:

int amalgamateArtistsAndSongs (char amalgamatedSongs[][163],char artists[][80],char songsOfAnArtists[][80],int numOfSongs[],int pos)
{
    int i;

    for (i=0;i<numOfSongs;i++)
    {
       strcpy(amalgamatedSongs[pos],artists[]);
       strcat(amalgamatedSongs[pos]," - ");
       strcat(amalgamatedSongs[pos],songsOfAnArtists[i]);
       strcat(amalgamatedSongs[pos],"\0");
       pos++;
    }

    return pos;
}

I am using int pos; to indicate to the next call of the function where the in amalgamatedSongs[][] the previous call of the function left off (where the last artist - song was placed).

This is how the function is called

amalgamateArtistsAndSongs(amalgamatedSongs,artists[1],
        songsArtist2,numSongsPerArtist[1],pos);

To clarify:

If

artists[][80] = {"artist1","artist2","artist3","artist4"};
songsArtist1[][80] = {"a","b","c"};
songsArtist2[][80] = {"aa","bb","cc"};
songsArtist3[][80] = {"aaa","bbb"};
songsArtist4[][80] = {"aaaa"};

Then (after using the amalgamateArtistsAndSongs() function)

amalgamatedSongs[][163] = {"artist1 - a","artist1 - b","artist1 - c",
"artist2 - aa","artist2 - bb","artist2 - cc","artist3 - aaa","artist3 - bbb",
"artist4 - aaaa"};

Upvotes: 0

Views: 83

Answers (2)

Pablo
Pablo

Reputation: 13580

This function

int amalgamateArtistsAndSongs (char amalgamatedSongs[][163],
    char artists[][80],char songsOfAnArtists[][80],
    int numOfSongs[],int pos)
{
    int i;

    for (i=0;i<numOfSongs;i++)
    {
       strcpy(amalgamatedSongs[pos],artists[]);
       strcat(amalgamatedSongs[pos]," - ");
       strcat(amalgamatedSongs[pos],songsOfAnArtists[i]);
       strcat(amalgamatedSongs[pos],"\0");
       pos++;
    }

    return pos;
}

is incorrect: numOfSongs is a pointer to an array, the for loop will continue to loop until i gets to the integer value of the addresses where numOfSongs is pointing to and you definitely will overflow amalgamatedSongs. The compiler must have given a warning for this. The correct condition should be i < numOfSongs[pos].

Also

 strcpy(amalgamatedSongs[pos],artists[]);

is a syntax error, you should get sometging like this:

error: expected expression before ‘]’ token
  strcpy(amalgamatedSongs[pos],artists[]);
                                       ^

You probably want

 strcpy(amalgamatedSongs[pos], artists[pos]);

This

   strcat(amalgamatedSongs[pos],"\0");

is not needed, because strcat writes the '\0'-terminating byte.

A problem with this series of strcat is that you don't know if the whole strings fits in amalgamatedSongs[pos], you may overflow the buffer. You would have to use strncpy and strncat and manually set the '\0'-terminating between each call. It's a lot of work, I'd concatenate the strings using snprintf:

int amalgamateArtistsAndSongs (char amalgamatedSongs[][163],
    char artists[][80],char songsOfAnArtists[][80],
    int numOfSongs[],int pos)
{
    int i;

    for (i=0;i<numOfSongs;i++)
    {
        snprintf(amalgamatedSongs[pos], 163, "%s - %s",
            artists[pos], songsOfAnArtists[i]);

       pos++;
    }

    return pos;
}

snprintf will write at most 163 characters including the '\0'-terminating byte. If the combination artist - song is to long for 162 characters, snprintf will only write 162 characters and set the '\0'-terminating byte, thus you don't overflow the buffer.

man printf

#include <stdio.h>
int snprintf(char *str, size_t size, const char *format, ...);
int vsnprintf(char *str, size_t size, const char *format, va_list ap);

The functions snprintf() and vsnprintf() write at most size bytes (including the terminating null byte ('\0')) to str.

Upvotes: 1

D&#250;thomhas
D&#250;thomhas

Reputation: 10073

Your title is misleading. While true you are in fact messing with 2D arrays, it is more idiomatic and better understood to say you are messing with arrays of strings.

To combine strings, use strcpy() and strcat().

To do it for an array of things, use a loop.

for (int n = 0; n < num_items; n++)
{
  strcpy( amalgamatedSongs[ n ], artists[ n ] );
  strcat( amalgamatedSongs[ n ], " - " );
  strcat( amalgamatedSongs[ n ], ... );
}

When in doubt, learn to read the docs. cppreference.com has a very good reference.

Upvotes: 0

Related Questions