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:
- Pass an array of eight
struct cell
intocellGetNeighbors
so that the caller is responsible for allocating that memory. - Allocate
cn
on the heap (i.e.malloc
) insidecellGetNeighbors
and return it as you are now. The caller would, of course, have tofree
thecellGetNeighbors
return value when it was finished with it (and this fact should be documented as part of thecellGetNeighbors
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.
精彩评论