简体   繁体   中英

How to dynamically allocate a structure array?

How would I dynamically allocate a structure array for tracks so that I can access it with all_albums_p[i] ? I need it to be accessible by all_albums_p[i] because I'm returning all_albums_p.

struct tracks_{
  char tracks_title;
  int playlist_hits;
};

struct album_ {
  int num_tracks;
  struct tracks_ tracks;
};

typedef struct album_ album;
typedef struct tracks_ tracks;

album *all_albums_p = (album *)malloc(sizeof(album)*number_of_album);

** * ** * ** What I've Changed * ** * ****

struct tracks_{
      char *tracks_title;
      int *playlist_hits;
    };

Right now, each of your albums has a single track, and the track name is expected to be a single character, instead of what you probably want, a character array.

You're already allocating your albums correctly, but you need to allocate the tracks of each album, too.

The simplest way to do this would be to just specify a fixed number of tracks as a maximum, and just make sure your other code doesn't exceed that.

const int MAX_TRACKS = 20;
const int MAX_HITS = 20;
const int MAX_TRACK_NAME_LENGTH = 63;

struct track_{
    char tracks_title[MAX_TRACK_NAME_LENGTH+1];
    int playlist_hits[MAX_HITS];
    int playlist_hits_count;
};

struct album_ {
    int num_tracks;
    struct track_ tracks[MAX_TRACKS];
};

Alternatively, you could dynamically allocate the tracks and the track names to the exact sizes needed if you had that information handy. For example, say you were just making a copy of an existing array of albums:

struct track_ {
    char *track_title;
    int *playlist_hits;
    int playlist_hits_count;
};

struct album_ {
    int num_tracks;
    struct track_ *tracks;
};

typedef struct album_ album;
typedef struct track_ track;

album *copy_albums(album *all_albums_p, int number_of_album) {
    album *all_albums_copy = (album *)malloc(sizeof(album) * number_of_album);

    // copy each album
    for (int album_i = 0; album_i < number_of_album; album_i++) {
        album * current_album = all_albums_p + album_i;
        album * copy_album = all_albums_copy + album_i;

        copy_album->num_tracks = current_album->num_tracks;
        copy_album->tracks = (track *)malloc(sizeof(track) * current_album->num_tracks);

        // copy each track, and it's hits, and make a new copy of it's name
        for (int track_i = 0; track_i < current_album->num_tracks; track_i++) {
            track * current_track = current_album->tracks + track_i;
            track * copy_track = copy_album->tracks + track_i;

            copy_track->playlist_hits_count = current_track->playlist_hits_count;
            copy_track->playlist_hits = (int *)malloc(sizeof(int) * current_track->playlist_hits_count);
            memcpy(copy_track->playlist_hits, current_track->playlist_hits, current_track->playlist_hits_count * sizeof(int));

            copy_track->track_title = _strdup(current_track->track_title);
        }
    }

    return all_albums_copy;
}
typedef struct tracks_{
  char tracks_title[101];
  int playlist_hits;
} tracks;

typedef struct album_ {
  int num_tracks;
  struct tracks_ tracks[20];
} album;

album *all_albums_p = (album *)malloc(sizeof(album)*number_of_album);

would allocate number_of_albums times an album with a fixed maximum 20 tracks per album.

You have some choices to make.

  1. Fix maximum length string for title vs dynamic string for title:

     enum { MAX_TITLE_LENGTH = 32 }; typedef struct tracks { char tracks_title[MAX_TITLE_LENGTH]; int playlist_hits; } tracks; 

    vs

     typedef struct tracks { char *tracks_title; int playlist_hits; } tracks; 

    The first makes track allocation simpler, and release simpler, but runs into trouble if you find a track title that is longer than your maximum. It might also waste more space than the alternative if you have many short track titles.

  2. For the albums, you need to use either a fixed size array of tracks for each album or a pointer or a 'flexible array member' (or, if you're stuck with a pre-1999 compiler, you might need to use the 'struct hack').

     enum { MAX_TRACKS_PER_ALBUM = 32 }; typedef struct album { int num_tracks; tracks tracks[MAX_TRACKS_PER_ALBUM]; } album; 

    vs

     typedef struct album { int num_tracks; tracks *tracks; } album; 

    vs

     typedef struct album { int num_tracks; tracks tracks[]; } album; 

    The last is quite simple to use as long as you don't want an array of them. (You could use an array of album pointers with the flexible array member.) Given that you do want an array of albums, you are probably best off with the pointer version:

     album *all_albums = (album *)malloc(sizeof(album) * number_of_albums); 

    But you'll need to initialize the album structures (because malloc() will not do so), and you'll need to allocate the appropriate number of tracks for each album.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM