void
void

Reputation: 358

How to iterate using pointers to structures?

I have written a small program in which I use a pointer to keep track of array of structures. I have a few questions regarding the same:

1) In main(), I iterate using the macro "COUNT". How can I iterate using the arr_struct or arr_struct[i] in place of COUNT? Is it possible to derive the number of entries in arr_struct from arr_struct?

2) Is the following statement OK if I do not wish to assign a value to place?

(*as)[i].name = strdup("foo"); (*as)[i].place = NULL; (*as)[i].n = 1234;

3) Do you see any wrong programming practice, bug, or memory (allocation and free) related issues in the following code?

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

typedef struct info_s {
    char *name;
    char *place;
    int n;
} info_t;

#define COUNT 2

static void
get_data (info_t **as)
{
    int i = 0;
    for (i = 0; i < COUNT; i++) {
        info_t *tmp = (info_t *)realloc(*as, (i + 1) * sizeof(info_t));
        if (tmp != NULL) {
            *as = tmp;

            (*as)[i].name = strdup("foo");
            (*as)[i].place = strdup("bar");
            (*as)[i].n = 1234;
        }
    }
}

int main (int argc, char** argv)
{
    info_t *arr_struct = NULL;
    int i;

    get_data(&arr_struct);

    for(i = 0; i < COUNT; i++) {
        printf("[%d].name:%s,\t", i, arr_struct[i].name);
        printf("[%d].place:%s,\t", i, arr_struct[i].place);
        printf("[%d].n:%d\n", i, arr_struct[i].n);
    }

    for(i = 0; i < COUNT; i++) {
        free(arr_struct[i].name);
        free(arr_struct[i].place);
    }
    free(arr_struct);
    return 0;
}

Upvotes: 0

Views: 81

Answers (2)

Sergey
Sergey

Reputation: 532

Since realloc() is a too "expensive" function, the standard aproach is as follows.

const int capacity = 100; // for example
    
static void
get_data (info_t **as)
{
    int i = 0;
    for (i = 0; i < COUNT; i++) {
        info_t *tmp = *as;
        if (i % capacity == 0)
            tmp = (info_t *)realloc(*as, capacity * (i/capacity + 1) * sizeof(info_t));
        if (tmp != NULL) {
            *as = tmp;

            (*as)[i].name = strdup("foo");
            (*as)[i].place = strdup("bar");
            (*as)[i].n = 1234;
        }
    }
}

I apologize for the non-optimal code in this example. I made minimal changes to the source code solely for demonstration.

UPDATE

More accurate example

const int capacity = 100; // for example

static void
get_data (info_t **as)
{
    int i = 0;
    for (i = 0; i < COUNT; i++) {       
        if (i % capacity == 0)
            info_t *tmp = (info_t *)realloc(*as, capacity * (i/capacity + 1) * sizeof(info_t));
            if (tmp != NULL) {
                *as = tmp;
            }
            else {
                fprintf(stderr, "Not enough memory\n");
                exit(1);
            }
        }

        (*as)[i].name = strdup("foo");
        (*as)[i].place = strdup("bar");
        (*as)[i].n = 1234;
    }
}

Upvotes: 2

FastAl
FastAl

Reputation: 6280

1) add an 'end' member to your structure set to Zero normally, add another instance of that structure in get_data, with that member set to -1 and then loop up to it in your main.

2) That will work in get_data but blow up the printf (and your free). You'd have to check for it. Better to always set it to "". If it means something special to be null, it would be clearer from a 'be nice to the programmer' standpoint to add another member. (yes it takes more memory. Your computer has a lot of that.)

3) Looks pretty good to me. I would have forgotten to free the strings. General advice - realloc will work for <1000 items but if you have 100s of k, use a linked list. It will also solve some of the other problems you speak of (of course, you won't have index access, but for this sample you don't demonstrate a need).

good luck!

Upvotes: 2

Related Questions