开发者

C: Unable to receive a pointer to struct array

I have the following structs and functions

// KEY
// ----------------------------
struct key  {
    double k1, k2;
};

// CELL
// ----------------------------
struct cell {
    double x, y, h, g, rhs;
    struct key *keys;
};

void cellPrintData(struct cell *c)  {
    printf("\n\tCELL\n\t.............\n");
    printf("\t%f\n", c->x);
    printf("\t%f\n", c->y);
    printf("\t%f\n", c->g);
    printf("\t%f\n", c->h);
    printf("\t%f\n", c->rhs);
    printf("\t%f\n", c->keys->k1);
    printf("\t%f\n", c->keys->k2);
}

/* cellCopyValues
 * ----------------------------
 * Copy values from source cell
 * into target cell.
 */
void cellCopyValues(struct cell *targetcell, struct cell *sourcecell)   {

    targetcell->x = sourcecell->x;  
    targetcell->y = sourcecell->y;  
    targetcell->h = sourcecell->h;  
    targetcell->g = sourcecell->g;  
    targetcell->rhs = sourcecell->rhs;  
    targetcell->keys->k1 = sourcecell->keys->k1;    
    targetcell->keys->k2 = sourcecell->keys->k2;    

}

/* cellDuplicate
 * ----------------------------
 * Create a duplicate cell using
 * values from given cell and return it.
 */
struct cell * cellDuplicate(struct cell *c) {


    struct cell *c2 = (struct cell *) malloc(sizeof(struct cell));
        if (c2 == NULL) {
        printf("--> Unable to malloc *c2!\n");
        errno = ENOMEM;
        return NULL;
        }
    c2->keys = (struct key *) malloc(sizeof(struct key));
        if (c2->keys == NULL) {
        printf("--> Unable to malloc *c2->keys!\n");
        errno = ENOMEM;
        return NULL;
        }
    cellCopyValues(c2, c);

    return c2;
}

Now, I'm facing a problem in receiving the struct array from this method:

/* cellGetNeighbors()   
 * ----------------------------
 * Gets the n开发者_如何学编程eighbors of a cell
 */
struct cell * cellGetNeighbors(struct cell *c, struct cell *sstart, struct cell *sgoal, double km)  {

    int i;

    // CREATE 8 CELLS
    struct cell cn[8];

    //cellPrintData(c);

    for(i = 0; i < 8; i++)  {
        cn[i] = *cellDuplicate(c);
    }

    // MAKE THEM NEIGHBORS

    cn[0].y -= _DISTANCETOMOVE;
    cn[1].x -= _DISTANCETOMOVE;
    cn[2].y += _DISTANCETOMOVE;
    cn[3].x += _DISTANCETOMOVE;

    cn[4].x -= _DISTANCETOMOVE;
    cn[4].y -= _DISTANCETOMOVE;

    cn[5].x -= _DISTANCETOMOVE;
    cn[5].y += _DISTANCETOMOVE;

    cn[6].x += _DISTANCETOMOVE;
    cn[6].y += _DISTANCETOMOVE;

    cn[7].x += _DISTANCETOMOVE;
    cn[7].y -= _DISTANCETOMOVE;



    // CALCULATE g, h, rhs, key
    for(i = 0; i < 8; i++)  {
        cn[i].g = cellG(&cn[i], sgoal);
        cn[i].h = cellH(&cn[i], sstart);
        cn[i].rhs = _INFINITY;

        cn[i].keys = cellCalculateKey(&cn[i], km);
        //cellPrintData(&cn[i]);
    }

    // STORE THESE NEIGHBORS IN FILE.
    struct cell *cptr = &cn[0];
    cellPrintData(&cn[2]);
    return cptr;
}

.. into THIS method -

struct cell * cellMinNeighbor(struct cell *c, struct cell *sstart, struct cell *sgoal, double km)   {

    // GET NEIGHBORS of c
    int i;
    struct cell *cn = cellGetNeighbors(c, sstart, sgoal, km);
    double sum[8];
    double minsum;
    int mincell;

cellPrintData(cn + 2);

    for(i = 0; i < 8; i++)  {
    //  sum[i] = 0.00;
    //  sum[i] += cellCost(c, cn + i);
    //  sum[i] += cellG(cn + i, sgoal);
    }
/*
    // Find min sum
    minsum = sum[0];
    mincell = 0;    
    for(i = 0; i < 8; i++)  {
        if(minsum < sum[i]) {
            minsum = sum[i];
            mincell = i;        
        }
    }

    //return (cn+mincell);
*/
    return cellCreateNew();
}   

When i compare the cellPrintData() outputs in the two methods -> method1: (sender)

CELL
.............
27.203030
71.435282
34.713147
0.000050
999.000000
34.713197
34.713147

method2: (receiver)

CELL
.............
27.203030
71.435282
34.713147
0.000050
999.000000
0.000000
0.000000

This also leads to very large values for k1 and k2 - and segmentation faults. What am i doing wrong.. Thanks.. : )


Your problem is right here in cellGetNeighbors:

struct cell cn[8];

You're allocting cn on the stack so when your cellGetNeighbors function is finished and returns, the value of cn (the cellGetNeighbors version of it) will no longer be valid and cn in cellMinNeighbor will be pointing at a chunk of the stack that is being used for something else.

You have two easy options:

  1. Pass an array of eight struct cell into cellGetNeighbors so that the caller is responsible for allocating that memory.
  2. Allocate cn on the heap (i.e. malloc) inside cellGetNeighbors and return it as you are now. The caller would, of course, have to free the cellGetNeighbors return value when it was finished with it (and this fact should be documented as part of the cellGetNeighbors interface).

I'd recommend the second option and I'd recommend building a separate cellFree function to properly free a single cell. The cellFree function is a good idea because your struct cell has a pointer in it and that pointer will need to be freed. This is, of course, complicated further if you ever need to use an array that doesn't have exactly eight elements; if that happens then you'll have to return the array size as well by adding an extra pointer argument to getCellNeighbors. If things get to that point then you'll want to add a separate struct:

struct cells {
    int n; /* How many cells there are */
    struct cell *items; /* The cells themselves */
}

and a set of functions to allocate and free these new structs.

I'm guessing that you have similar stack versus heap issues with cellCalculateKey as well.

And, you don't need to do this:

struct cell *cptr = &cn[0];
cellPrintData(&cn[2]);
return cptr;

The cn array will decay to a pointer without your intervention, just this is fine:

cellPrintData(&cn[2]);
return cn;

Furthermore, since I'm already writing a book here, you don't need to cast the return from malloc (or calloc or realloc or anything else that returns void *) in C and doing so can cover up problems. So, where you say this:

struct cell *c2 = (struct cell *) malloc(sizeof(struct cell));
/* ... */
c2->keys = (struct keys *) malloc(sizeof(struct key));

you should just say:

struct cell *c2 = malloc(sizeof(struct cell));
/* ... */
c2->keys = malloc(sizeof(struct key));

And another thing, you have a memory leak right here:

for(i = 0; i < 8; i++)  {
    cn[i] = *cellDuplicate(c);
}

The memory that cellDuplicate allocates for the new struct cell is leaked. You'd be better off with something more like this:

for(i = 0; i < 8; i++)  {
    cellDuplicateContent(c, &cn[i]);
}

And cellDuplicateContent would just copy the individual members and, of course, allocate the data for keys as that's a pointer (i.e. cellCopyValues plus an allocation of keys).


Looks like cellGetNeighbors is returning stack memory--it returns cptr, which points to &cn[0]. Once the method returns, anything you declared on the stack is no longer valid. You're duplicating the cells into that, so you probably just need to malloc-up the array. Note that you will need to eventually free that array too.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜