Search code examples
carraysdata-structuresdynamic-data

The Notorious Dynamic allocation of pointers to arrays of structures


I've a long version of a program that uses this code and a short version. This is the short version and oddly, this code runs perfectly fine in short version program, but because I get an access violation in the larger version, I get the feeling something is wrong. Does anyone see anything terribly wrong (that might lead to data corruption and/or access violation errors) with the following code? Or is this alright?

char strlist[5][11] = {
    { "file01.txt" },
    { "file02.txt" },
    { "file03.txt" },
    { "file04.txt" },
    { "file05.txt" }
};

typedef struct DYNAMEM_DATA {
    char *string;
    int   strlen;
} DYNAMEM_DATA;

typedef struct DYNAMEM_STRUCT {
    struct DYNAMEM_DATA **data;
    int           num_elements;
} DYNAMEM_STRUCT;

DYNAMEM_STRUCT *create_dynamem_struct(int num_elements, char *strlist)
{
    DYNAMEM_STRUCT *ds = (DYNAMEM_STRUCT *)calloc(1, sizeof(DYNAMEM_STRUCT));
    wchar_t wstring[128];
    char len[3];
    int i;

    ds->data = (DYNAMEM_DATA **)calloc(num_elements, sizeof(DYNAMEM_DATA *));
    ds->num_elements = num_elements;

    for(i = 0; i < num_elements; i++) {
        ds->data[i] = (DYNAMEM_DATA *)calloc(1, sizeof(DYNAMEM_DATA));
        ds->data[i]->string = (char *)calloc(1, strlen(&strlist[i*11])+5);
        ds->data[i]->strlen = strlen(&strlist[i*11]);
        sprintf(ds->data[i]->string, "%s, %d", &strlist[i*11], ds->data[i]->strlen);
        mbstowcs(wstring, ds->data[i]->string, 128);
        MessageBox(NULL, wstring, TEXT("Error"), MB_OK);
    }

    return ds;
}

Solution

  • This code runs, produces 5 'Error' messages (which is to be expected), and doesn't leak any memory. Running valgrind (3.7.0) on Mac OS X 10.7.4 (using GCC 4.7.1), it is given a clean bill of health.

    The problem is not, apparently, in this version of the code.

    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
    #include <wchar.h>
    
    char strlist[5][11] = {
        { "file01.txt" },
        { "file02.txt" },
        { "file03.txt" },
        { "file04.txt" },
        { "file05.txt" }
    };
    
    typedef struct DYNAMEM_DATA {
        char *string;
        int   strlen;
    } DYNAMEM_DATA;
    
    typedef struct DYNAMEM_STRUCT {
        struct DYNAMEM_DATA **data;
        int           num_elements;
    } DYNAMEM_STRUCT;
    
    enum { MB_OK = 0 };
    static void destroy_dynamem_data(DYNAMEM_DATA *dd)
    {
        free(dd->string);
        free(dd);
    }
    static void destroy_dynamem_struct(DYNAMEM_STRUCT *ds)
    {
        for (int i = 0; i < ds->num_elements; i++)
            destroy_dynamem_data(ds->data[i]);
        free(ds->data);
        free(ds);
    }
    static void MessageBox(const void *null, const wchar_t *wcs, const char *ncs, int status)
    {
        if (null == 0 || status == MB_OK)
            fprintf(stderr, "%s\n", ncs);
        else
            fwprintf(stderr, L"%s\n", wcs);
    }
    static const char *TEXT(const char *arg) { return arg; }
    
    extern DYNAMEM_STRUCT *create_dynamem_struct(int num_elements, char *strlist);
    
    DYNAMEM_STRUCT *create_dynamem_struct(int num_elements, char *strlist)
    {
        DYNAMEM_STRUCT *ds = (DYNAMEM_STRUCT *)calloc(1, sizeof(DYNAMEM_STRUCT));
        wchar_t wstring[128];
        //char len[3];
        int i;
    
        ds->data = (DYNAMEM_DATA **)calloc(num_elements, sizeof(DYNAMEM_DATA *));
        ds->num_elements = num_elements;
    
        for(i = 0; i < num_elements; i++) {
            ds->data[i] = (DYNAMEM_DATA *)calloc(1, sizeof(DYNAMEM_DATA));
            ds->data[i]->string = (char *)calloc(1, strlen(&strlist[i*11])+5);
            ds->data[i]->strlen = strlen(&strlist[i*11]);
            sprintf(ds->data[i]->string, "%s, %d", &strlist[i*11], ds->data[i]->strlen);
            mbstowcs(wstring, ds->data[i]->string, 128);
            MessageBox(NULL, wstring, TEXT("Error"), MB_OK);
        }
    
        return ds;
    }
    
    int main(void)
    {
        DYNAMEM_STRUCT *ds = create_dynamem_struct(5, strlist[0]); 
        destroy_dynamem_struct(ds);
        return 0;
    }