Home > Blockchain >  I'm using array of structures inside a structure and my program behaves wierdly
I'm using array of structures inside a structure and my program behaves wierdly

Time:12-14

I'm trying to create a little playlist organiser inside a C program. And I manage to create this code. Point of the code is create array of structure track_ inside structure listOfSongs and fill it by for cycle. I've get segmentation fail when the count of songs is smaller then 6. But if count of songs is <=6 program behave normally and works fine. I'm pretty new into C. So I cant spot the mistake. Can somebody help me? Thnx <3

struct track_t
{ 
    char *nazev;
    char *autor;
    char *album;
    int orderInAlbum;
};

struct listOfSongs
{     
    struct track_t **track;
}; 


int main(int argc, char *argv[])
{
    (void) argc;
    (void) argv;
    printf("Write count of songs:\n");
    int countOfSongs;
    scanf("%d", &countOfSongs);
    struct listOfSongs *sez;
    sez = malloc(sizeof(* sez));
    sez->track = malloc(sizeof(struct track_t *) * countOfSongs);
    for(int i = 0; i<countOfSongs; i  )
    {
        sez->track[i] = malloc(sizeof(struct track_t));
    }
    for(int i = 0; i<countOfSongs; i  )
    {
        printf("%d\n", i);
        scanf("%s", sez->track[i]->nazev);
        printf("%s\n", sez->track[i]->nazev);
    }
    return 0;
}

CodePudding user response:

The elements of the structure (except one data member)

struct track_t
{ 
    char *nazev;
    char *autor;
    char *album;
    int orderInAlbum;
};

have the pointer type char *. They were not initialized and have indeterminate values.

Thus this for loop

for(int i = 0; i<countOfSongs; i  )
{
    printf("%d\n", i);
    scanf("%s", sez->track[i]->nazev);
    printf("%s\n", sez->track[i]->nazev);
}

invokes undefined behavior.

Either you need to redeclare the structure declaring character arrays as data members or you need to allocate dynamically character arrays addresses of which will be assigned to the pointers.

Pay attention to that instead casing arguments of main to the type void to avoid warnings about unused variables

int main(int argc, char *argv[])
{
    (void) argc;
    (void) argv;
    //...

You could declare the function main like

int main( void )

CodePudding user response:

"...trying to create little playlist..., ...Point of the code is create array of structure track inside structure listOfSongs and fill it by for cycle..."_

The segmentation fault is caused when you attempt to access areas of memory for which the program does not own. Because char *nazev; (and other members) are pointers, the following expression will invoke undefined behavior:

scanf("%s", sez->track[i]->nazev); //attempting to scan value into memory not owned by process. 

It requires memory before used. Same for similar members in struct.

One suggestion to simplify struct is to replace pointer members with char arrays of reasonable length to accommodate data each is used for.

However, because of your stated intent to create a play list, another suggestion might be to use a list construct that may be better suited to contain a playlist. The C construct that can do this is commonly called a linked list.

Following is an example of a form of linked list that allows your program to enter information for each new item in your playlist into a new node. Each new node is connected by pointers to the next node, and to the previous node, thus allowing the user to traverse the list both forward and backward.

Example of linked list approach:

typedef struct track_s { //this struct contains the type information
    char nazev[80];      //intended to be stored in the list
    char autor[80];      //it can easily be exande to have more members
    char album[80];
    int orderInAlbum;
}track_s;

track_s sample_input[4] = {{"song 1 title", "name of author 1", "name of album 1", 1},
                           {"song 2 title", "name of author 2", "name of album 2", 2},
                           {"song 3 title", "name of author 3", "name of album 3", 3},
                           {"song 4 title", "name of author 4", "name of album 4", 4}
                        };

typedef struct track {     
    track_s track; //payload containing information to be added to list
    struct track *prev;//pointers to next and previous nodes
    struct track *next;
}list_tracts_s; 

//prototypes
void Insert(list_tracts_s** head, track_s *new); //insert
void deleteRecord(list_tracts_s** head_ref, list_tracts_s* del); //free

int main(int argc, char *argv[])
{
    list_tracts_s *head = NULL;
    //populate list of nodes to contain sample input
    Insert(&head, &sample_input[0]);//insert one record into one node
    Insert(&head, &sample_input[1]);
    Insert(&head, &sample_input[2]);
    Insert(&head, &sample_input[3]);
    //use list in program
    //free when done (call once for each Insert
    deleteRecord(&head, head);
    deleteRecord(&head, head);
    deleteRecord(&head, head);
    deleteRecord(&head, head);
    
    return 0;
}

void Insert(list_tracts_s** head, track_s *new)
{
    /* 1. allocate node */
    list_tracts_s *new_node = malloc(sizeof(*new_node));
    if(new_node)
    {        
        /* 2. assign input data  */
        strcpy(new_node->track.nazev , new->nazev);
        strcpy(new_node->track.autor , new->autor);
        strcpy(new_node->track.album , new->album);
        new_node->track.orderInAlbum = new->orderInAlbum;
    
    
        /* 3. Make next of new node as head and previous as NULL */
        new_node->next = (*head);
        new_node->prev = NULL;
     
        /* 4. change prev of head node to new node */
        if ((*head) != NULL)
            (*head)->prev = new_node;
     
        /* 5. move the head to point to the new node */
        (*head) = new_node;
    }
}

void deleteRecord(list_tracts_s** head_ref, list_tracts_s* del)
{
    /* base case */
    if (*head_ref == NULL || del == NULL)
        return;
 
    /* If node to be deleted is head node */
    if (*head_ref == del)
        *head_ref = del->next;
 
    /* Change next only if node to be deleted is NOT the last node */
    if (del->next != NULL)
        del->next->prev = del->prev;
 
    /* Change prev only if node to be deleted is NOT the first node */
    if (del->prev != NULL)
        del->prev->next = del->next;
 
    /* Finally, free the memory occupied by del*/
    free(del);
    return;
}
  • Related