Home > OS >  Using a pointer to an array of structs does not return the complete array
Using a pointer to an array of structs does not return the complete array

Time:10-12

I have a main program that is supposed to receive as result of calling a function to load data (array of structs, undefined size), the proper data and then continuing processing it.

Following is a little example of what I'm trying to do. The function loadData receives a pointer to the main pointer, so that the main pointer may be assigned a portion of memory through malloc. The data is loaded and printed within the loadData function. But when it returns to main it only shows a correct content for the first item of the array of structures. The second item is garbage.

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

typedef struct
{ 
    int dni;
    char cat;
    int weight;
} boxers;

void loadData(boxers *(*xbox), int *xcount)
{
    printf("How many boxers? ");
    scanf("%d", xcount);

    *xbox = (boxers *) malloc(sizeof(boxers) * (*xcount));

    for (int i = 0; i < (*xcount); i  )
    {
        printf("Provide the DNI for boxer number %d: ", i);
        scanf("%d", &xbox[i]->dni);
        printf("Provide the Category for boxer number %d: ", i);
        scanf(" %c", &xbox[i]->cat);
        printf("Provide the Weight for boxer number %d: ", i);
        scanf("%d", &xbox[i]->weight);
    }

    // First print the result of data loading
    for (int i = 0; i < *xcount; i  )
    {
        printf("DNI for boxer number %d, is: %d \n", i, xbox[i]->dni);
        printf("Category for boxer number %d, is: %c \n", i, xbox[i]->cat);
        printf("Weight for boxer number %d, is: %d \n", i, xbox[i]->weight);
    }

}

int main()
{
    boxers *box;
    int count;

    loadData(&box, &count);

    // Second print the result of data loading
    printf("\n\n");
    for (int i = 0; i < count; i  )
    {
        printf("DNI for boxer number %d, is: %d \n", i, box[i].dni);
        printf("Category for boxer number %d, is: %c \n", i, box[i].cat);
        printf("Weight for boxer number %d, is: %d \n", i, box[i].weight);
    }

    free(box);
    
    return 0;
}

The console output is the following:

How many boxers? 2
Provide the DNI for boxer number 0: 123
Provide the Category for boxer number 0: A
Provide the Weight for boxer number 0: 45
Provide the DNI for boxer number 1: 789
Provide the Category for boxer number 1: B
Provide the Weight for boxer number 1: 56

DNI for boxer number 0, is: 123
Category for boxer number 0, is: A
Weight for boxer number 0, is: 45
DNI for boxer number 1, is: 789
Category for boxer number 1, is: B
Weight for boxer number 1, is: 56


DNI for boxer number 0, is: 123
Category for boxer number 0, is: A
Weight for boxer number 0, is: 45
DNI for boxer number 1, is: 7471203
Category for boxer number 1, is: x
Weight for boxer number 1, is: 7536756

CodePudding user response:

&xbox[i]->dni is wrong. The return value from malloc was assigned to *xbox, so *xbox points to the memory, and xbox points to that that pointer.

So the memory is at *xbox. The first structure there is **xbox or, equivalently, (*xbox)[0]. The next structure is (*xbox)[1], and so on. So you want (*xbox)[i] for the structure with index i. Then, since that is a structure, not a pointer to it, you want .dni, not ->dni. So that member is (*xbox)[i].dni. Then its address is &(*xbox)[i].dni.

In contrast, since xbox is a pointer to a pointer, then xbox[0] is that pointer, and xbox[1] would be the pointer after that. But there is no pointer after that; xbox just points to a single pointer. So xbox[i] is wrong.

The same change is needed in the other member references in the routine.

To avoid this easy-to-make mistake, in routines where a pointer-to-a-pointer is passed, a local pointer may be defined to make references easier:

void loadData(boxers **xbox, int *xcount)
{
    …
    boxers *p = *xbox = malloc(xcount * sizeof *p);
    …
        scanf("%d", &p[i]->dni);
    …
}

CodePudding user response:

These assignments

for (int i = 0; i < (*xcount); i  )
{
    printf("Provide the DNI for boxer number %d: ", i);
    scanf("%d", &xbox[i]->dni);
    printf("Provide the Category for boxer number %d: ", i);
    scanf(" %c", &xbox[i]->cat);
    printf("Provide the Weight for boxer number %d: ", i);
    scanf("%d", &xbox[i]->weight);
}

are incorrect. You have to write

for (int i = 0; i < (*xcount); i  )
{
    printf("Provide the DNI for boxer number %d: ", i);
    scanf("%d", &( *xbox )[i].dni);
    printf("Provide the Category for boxer number %d: ", i);
    scanf(" %c", &( *xbox )[i].cat);
    printf("Provide the Weight for boxer number %d: ", i);
    scanf("%d", &( *xbox )[i].weight);
}

and then

for (int i = 0; i < *xcount; i  )
{
    printf("DNI for boxer number %d, is: %d \n", i, ( *xbox )[i].dni);
    printf("Category for boxer number %d, is: %c \n", i, ( *xbox )[i].cat);
    printf("Weight for boxer number %d, is: %d \n", i, ( *xbox )[i].weight);
}

Compare the above loop with this loop in main

for (int i = 0; i < count; i  )
{
    printf("DNI for boxer number %d, is: %d \n", i, box[i].dni);
    printf("Category for boxer number %d, is: %c \n", i, box[i].cat);
    printf("Weight for boxer number %d, is: %d \n", i, box[i].weight);
}

The difference is that in main the pointer box has the type boxers * while in the function the pointer xbox has the type boxers **. So you need at first to dereference the pointer in the function like ( *xbox ) and then to apply the subscript operator as you are doing in main as for example ( *xbox )[i].weight

  • Related