C Pointer and Memory Allocation: Realloc Arrays and Pointer Passing

半城伤御伤魂 提交于 2019-12-19 11:53:47

问题


For those experienced with C, this will be a simple memory allocation/referencing problem:

Here are my data structures:

struct configsection {
    char *name;
    unsigned int numopts;
    configoption *options;
};
typedef struct configsection configsection;

struct configfile {
    unsigned int numsections;
    configsection *sections;
};
typedef struct configfile configfile;

Here are my routines for initializing a configsection or configfile, and for adding a configsection to a configfile:

// Initialize a configfile structure (0 sections)
void init_file(configfile *cf) {
    cf = malloc(sizeof(configfile));
    cf->numsections = 0;
}
// Initialize a configsection structure with a name (and 0 options)
void init_sec(configsection *sec, char *name) {
    sec = malloc(sizeof(configsection));
    sec->numopts = 0;
    sec->name = name;
    printf("%s\n", sec->name);
}
// Add a section to a configfile
void add_sec(configfile *cf, configsection *sec) {
    // Increase the size indicator by 1
    cf->numsections = cf->numsections + 1;
    // Reallocate the array to accommodate one more item
    cf->sections = realloc(cf->sections, sizeof(configsection)*cf->numsections);
    // Insert the new item
    cf->sections[cf->numsections] = *sec;
}

I believe my problem originates in my init_sec() function. Here is an example:

int main(void) {

// Initialize test configfile
configfile *cf;
init_file(cf);

// Initialize test configsections
configsection *testcs1;
init_sec(testcs1, "Test Section 1");
// Try printing the value that should have just been stored
printf("test name = %s\n", testcs1->name);

Although the printf() in init_sec() successfully prints the name I just stored in the configsection, attempting the same thing in the printf() of main() produces a segmentation fault. Further, addsec() produces a segmentation fault.


回答1:


This routine should be

void init_file(configfile **cf) { 
    *cf = malloc(sizeof(configfile)); 
    (*cf)->numsections = 0;
    (*cf)->sections = NULL; // You forgot to initialise this.
}

i.e. called by init_file(&myconfigfilepointer); so the malloc return value gets passed back.

Need to do the same trick for init_sec

This function is incorrect - here is a corrected version

void add_sec(configfile *cf, configsection *sec) {     
    // Increase the size indicator by 1     
    // Reallocate the array to accommodate one more item     
    cf->sections = realloc(cf->sections, sizeof(configsection)*(1 + cf->numsections));     
    // Insert the new item     
    cf->sections[cf->numsections] = *sec; // Since arrays start at 0     
    cf->numsections = cf->numsections + 1;     
} 

You then need to adjust the calls in main




回答2:


At no point do you initialise cf->sections, which means when you try to realloc it the first time, you're passing rubbish. Adding:

 cf->sections = NULL;

to init_file should help.

You're also not checking any return codes, but you knew that yes?




回答3:


You need to pass a pointer of the value to be updated... eg:

// Initialize a configfile structure (0 sections)
void init_file(configfile **cf) {
    *cf = malloc(sizeof(configfile));
    (*cf)->numsections = 0;
}

configfile *var;
init_file(&var);
printf("%d\n", var->numsections);

Otherwise you are just updating the local pointer *cf and not the original passed in value




回答4:


You need to really rethink how function arguments are passed in C and what pointers are. Your problem has nothing to do with memory allocation. Rather, your code is assigning a pointer to dynamically allocated memory only to a local variable, of which the calling code knows nothing.

While you could solve the problem by passing a pointer to the caller's pointer (i.e. a double pointer), this is not necessarily the most elegant or most usual way of handling things. Rather, you should return the result of the allocation from the function. While you're at it, you should also use calloc to zero out the memory right away. Wrapping it all up:

typedef struct substuff_
{
    int a;
    double b;
} substuff;

typedef struct stuff_
{
    unsigned int n;
    substuff * data;
} stuff;

substuff * init_substuff()
{
    substuff * const p = malloc(sizeof *p);
    if (p) { p->a = 5; p->b = -0.5; }
    return p;
}

stuff * init_stuff()
{
    substuff * const p = init_substuff();
    if (!p) return NULL;

    stuff * const q = malloc(sizeof *q);
    if (q) { q->n = 10; q->data = p; }
    return q;
}

As an exercise, you should write the corresponding functions void free_substuff(substuff *) and void free_stuff(stuff *).




回答5:


Yes, there is a problem in init_sec

// Initialize a configsection structure with a name (and 0 options)
void init_sec(configsection *sec, char *name) {
    sec = malloc(sizeof(configsection));
    sec->numopts = 0;
    sec->name = name;
    printf("%s\n", sec->name);
}

You're just copying the name pointer here, which means, that it points to the original storage of name. If you'd call init_sec like this

configsection foobar()
{
    configsection sec;
    char name[80];

    get_name(name);
    init_sec(sec, name);
    return sec;    
}

The name pointer became invalid the moment foobar returned. You need to duplicate the string and keep your private copy around. In init_sec:

    sec->name = strdup(name);

But there's more. In the very first line of init_sec you're overwriting the pointer that was passed to init_sec with the one of malloc. So the new pointer never gets passed back to the calle. Either use a pointer to a pointer, don't take a configsection pointer at all (after all, you're allocating), but just return the allocated pointer: Complete corrected function:

// Initialize a configsection structure with a name (and 0 options)
configsection* init_sec(char *name) {
    configsection *sec = malloc(sizeof(configsection));
    sec->numopts = 0;
    sec->name = name;
    printf("%s\n", sec->name);
    return sec;
}


来源:https://stackoverflow.com/questions/9443617/c-pointer-and-memory-allocation-realloc-arrays-and-pointer-passing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!