I am having some issues with a program I am writing in C, and I have surpassed my knowledge. In summary, I need to deep copy a link list from one list to another. The lists have malloc'd data in them and I need to preserve all the data without having pointers pointing at the same information.
I have only posted the code that I think is relevant. If I am missing any important contextual information please let me know.
Here is the code:
matrix.h
typedef struct matrix {
char *name;
int R;
int C;
int dim;
void (*concat_matrices)( struct matrix *A, struct matrix *B, struct matrix *ret );
} Matrix;
void concat_matrices( Matrix *A, Matrix *B, Matrix *ret ) {
int L1 = strlen( A->name );
int L2 = strlen( B->name );
int len = L1 + L2;
char *Ap = (char*)malloc(L1*sizeof(char)); strcpy(Ap,A->name);
char *Bp = (char*)malloc(L2*sizeof(char )); strcpy(Bp,B->name);
char *c = (char*)malloc(sizeof(char)*(len + 2));
c[0] = '('; strcat(c, Ap); strcat(c, Bp); c[len+1] = ')';
ret->name = (char*)malloc(sizeof(char)*(len + 2));
strcpy(ret->name, c);
ret->R = A->R; ret->C = B->C;
ret->dim = ret->R*ret->C;
free(Ap); free(Bp); free(c);
}
matrix_list.h
typedef struct node {
Matrix *M;
struct node *next;
struct node *prev;
} Node;
typedef struct matrix_list {
Node *head;
Node *tail;
int size;
void (*append)( struct matrix_list *list, Matrix *M );
void (*print)( struct matrix_list *list );
void (*reverse_print)( struct matrix_list *list );
void (*delete)( struct matrix_list *list, const char *name );
void (*delete_tail)( struct matrix_list *list );
void (*delete_head)( struct matrix_list *list );
void (*release)( struct matrix_list *list );
void (*clone_list)( struct matrix_list *from, struct matrix_list *to );
} MatrixList;
...
void clone_list( MatrixList *from, MatrixList *to ) {
if( from->head == NULL ) {
to = NULL;
} else {
Node *tmp = from->head;
while( tmp != NULL ) {
Matrix *m_copy = (Matrix*)malloc(sizeof(Matrix*));
char *c_copy = (char*)malloc(sizeof(char*)*strlen(tmp->M->name));
strcpy(c_copy,tmp->M->name);
m_copy->name=c_copy;
m_copy->R=tmp->M->R;
m_copy->C=tmp->M->C;
m_copy->concat_matrices = concat_matrices;
to->append( to,m_copy );
tmp = tmp->next;
}
}
}
main.c
chain->print(chain);
MatrixList *chain_copy = (MatrixList*)malloc(sizeof(MatrixList));
set_list_functions( chain_copy );
chain->clone_list(chain, chain_copy);
chain_copy->print(chain_copy);
The problem arises when I try and print out the clone. Because I am malloc'ing in the clone function I understand the data goes out of scope. How can I do this copy so after the function is called clone has its own version of the data?
UPDATE:
First I would like to thank you all for taking your time to answer my question, and for teaching me more about C. I have only been coding for about 3 years. And I have a lot to learn. The updated source with 0 errors from Valgrind can be found at.
http://matthewh.me/Scripts/c++/matrix_chain/ for anyone else trying to figure out things like me. User = guest Password = guest. The clone_list function now looks like this.
void clone_list( MatrixList *from, MatrixList *to ) {
if( from->head == NULL ) {
to = NULL;
} else {
Node *tmp = from->head;
while( tmp != NULL ) {
Matrix *m_copy = (Matrix*)malloc(sizeof(Matrix));
m_copy->name = (char*)malloc(strlen(tmp->M->name) + 1);
sprintf( m_copy->name, "%s", tmp->M->name );
m_copy->R=tmp->M->R;
m_copy->C=tmp->M->C;
m_copy->concat_matrices = concat_matrices;
to->append( to,m_copy );
tmp = tmp->next;
}
}
}
If anyone else sees anything else wrong and would like to add additional pointers please feel free to do so.
You haven't allowed for the null that terminates strings, so you have classic buffer overflows.
You also do not need to copy the names three times. Your current code is:
int L1 = strlen( A->name );
int L2 = strlen( B->name );
int len = L1 + L2;
char *Ap = (char*)malloc(L1*sizeof(char)); strcpy(Ap,A->name);
char *Bp = (char*)malloc(L2*sizeof(char )); strcpy(Bp,B->name);
char *c = (char*)malloc(sizeof(char)*(len + 2));
c[0] = '('; strcat(c, Ap); strcat(c, Bp); c[len+1] = ')';
ret->name = (char*)malloc(sizeof(char)*(len + 2));
strcpy(ret->name, c);
ret->R = A->R; ret->C = B->C;
ret->dim = ret->R*ret->C;
free(Ap); free(Bp); free(c);
This should be:
int L1 = strlen(A->name);
int L2 = strlen(B->name);
ret->name = (char *)malloc(L1 + L2 + sizeof("()")); // That adds 3
sprintf(ret->name, "(%s%s)", A->name, B->name);
ret->R = A->R;
ret->C = B->C;
ret->dim = ret->R * ret->C;
This eliminates Ap, Bp and c altogether, and avoids the buffer overflow problems. I'm not sure I'd slam the two names together like you do, but that's your choice.
Apparently, this isn't sufficient of a problem...there are other issues too.
void clone_list( MatrixList *from, MatrixList *to ) {
if (from->head == NULL) {
to = NULL;
} else {
Node *tmp = from->head;
while( tmp != NULL ) {
Matrix *m_copy = (Matrix*)malloc(sizeof(Matrix*));
char *c_copy = (char*)malloc(sizeof(char*)*strlen(tmp->M->name));
strcpy(c_copy,tmp->M->name);
m_copy->name=c_copy;
m_copy->R=tmp->M->R;
m_copy->C=tmp->M->C;
m_copy->concat_matrices = concat_matrices;
to->append( to,m_copy );
tmp = tmp->next;
}
}
}
The first assignment zeroes the local pointer; it doesn't do a thing to the MatrixList passed in as the target. This should presumably be:
if (from->head == 0)
{
*to = *from;
}
This does a wholesale structure copy, but sets the head and tail to null, and the function pointers are all fine - they can be shared. Assuming that the size in from was correctly zero, it will be correct in to too. (Again, this is probably not the code you are exercising.)
The next problem is with the memory allocation:
Matrix *m_copy = (Matrix*)malloc(sizeof(Matrix*));
This allocates one pointer's worth of memory, not one Matrix's worth. Use either of these:
Matrix *m_copy = (Matrix *)malloc(sizeof(*m_copy));
Matrix *m_copy = (Matrix *)malloc(sizeof(Matrix));
That is a major source of your trouble (and one which valgrind will find easily).
When the +1 gets forgotten once, it gets forgotten many times, but this time it doesn't cause problems unless the name is the empty string because you multiply by 4 or 8 (32-bit or 64-bit) because of the sizeof(char *) instead of the intended sizeof(char).
char *c_copy = (char*)malloc(sizeof(char*)*strlen(tmp->M->name));
strcpy(c_copy,tmp->M->name);
This should probably be:
m_copy->name = (char *)malloc(strlen(tmp->M->name) + 1);
strcpy(m_copy->name, tmp->M->name);
I'd probably use a name like old instead of tmp. I am also remiss in not reminding previously that you should religiously check every return from every memory allocation. Or use a set of cover functions for the memory allocation routines which do the check for you (often called xmalloc() or emalloc(), etc.).
The code below that does not seem to copy the dim member across, which is a bug if you ever depend on it.
I'm not entirely happy that you seem to rely on the to list being appropriately initializes before calling clone_list(). In particular, the head, tail and size members are not zeroed here, and the function pointers are not set. I'd be happier to see something like:
*to = *from; // Copy function pointers
to->head = 0;
to->tail = 0;
to->size = 0;
Node *old = from->head;
for (Node *old = from->head; old != NULL; old = old->next)
{
Matrix *m_copy = clone_matrix(old->M);
to->append(to, m_copy);
}
Or even:
matrixlist_initialize(to);
Node *old = from->head;
for (Node *old = from->head; old != NULL; old = old->next)
{
Matrix *m_copy = clone_matrix(old->M);
to->append(to, m_copy);
}
The clone_matrix() function looks like:
Matrix *clone_matrix(const Matrix *old)
{
Matrix *m_copy = (Matrix*)malloc(sizeof(*m_copy));
m_copy->name = (char*)malloc(strlen(old->name)+1);
strcpy(m_copy->name, old->name);
m_copy->R = old->R;
m_copy->C = old->C;
m_copy->dim = old->dim;
m_copy->concat_matrices = concat_matrices;
return(m_copy);
}
I downloaded a version your code and it now seems to work, more or less. You should be compiling with at least -Wall as a compiler option; I refuse to compile with anything less and usually use -Wextra too. I make too many simple-to-spot mistakes not to make full use of the compiler, and while you are learning, you will too. (I've only been coding in C for just over a quarter century; the compiler still catches typos and other silly mistakes, but I seldom have big problems once the code is compiling.)
When I turned on -Wall, there was a problem with the (unused) perm() function because it doesn't return a value even though it says it will, and there was a problem because the correct definition for main() with arguments is int main(int argc, char **argv) and you were missing one of the stars. Other than that, it seems to be working OK now - you can continue with your development.
There is a function in POSIX called strdup() which duplicates a string reliably. It is useful and avoids the off-by-one mistakes.
You should review the use of headers. They are for declarations, primarily. If you explicitly use inline (your code doesn't yet), it can be appropriate to include inline functions in a header, but otherwise, function bodies should not be in headers. They should be in source files (.c suffix). Each header should contain the minimum necessary information for the code that uses the functionality provided by the source to use. It should not include extraneous headers, but it should include all necessary headers. In matrix.h, you include <stdio.h> which is unnecessary. And if you removed the code, neither <string.h> nor <stdlib.h> would be needed either.
int L1 = strlen( A->name );
int L2 = strlen( B->name );
int len = L1 + L2;
char *Ap = (char*)malloc(L1*sizeof(char)); strcpy(Ap,A->name);
char *Bp = (char*)malloc(L2*sizeof(char )); strcpy(Bp,B->name);
I'm willing to bet that your strcpy(3) calls here have written outside the bounds of the memory you've allocated: strlen(3) does NOT account for the '\0' terminator at the end of C strings, so your *Ap and *Bp are allocated one-byte-too-short.
Because this is so common it is an easy pattern to find bugs:
int len = strlen(s);
char *new = malloc(len); /* FAIL */
If I don't see a + 1 in the malloc(3) call, it's almost certainly a bug. :) I prefer to see:
int len = strlen(s);
char *new = malloc(len + 1);
rather than:
int len = strlen(s) + 1;
char *new = malloc(len);
If you follow the former, I think it is far easier to spot the wrong cases when you forget the + 1. I think the latter one is too easy to overlook the wrong ones amidst a sea of correct ones.
Similarly, your c and ret->name have been allocated too short.
But, I think there is a far easier answer:
void concat_matrices( Matrix *A, Matrix *B, Matrix *ret ) {
int len = strlen(A->name) + strlen(B->name) + 2 + 1; /* parens + NUL */
ret->name = malloc(len);
sprintf(ret->name, "(%s%s)", A->name, B->name);
ret->R = A->R; ret->C = B->C;
ret->dim = ret->R*ret->C;
}
Use sprintf(3) to build the string in one fell swoop. You only need to allocate one string, and that's the one you intend to keep, which will reduce memory fragmentation due to frequent allocate / deallocate cycles. But the most important reason for the re-write is I think this new version is easier to read. Note I broke my rule about the + 1 here -- clarity is improved by adding together all the memory required in one line.
Update
Your clone_list() function suffers from the same problem:
Matrix *m_copy = (Matrix*)malloc(sizeof(Matrix*));
char *c_copy = (char*)malloc(sizeof(char*)*strlen(tmp->M->name));
strcpy(c_copy,tmp->M->name);
Your m_copy looks fine, because it is a binary object and the size is known exactly. But c_copy is allocated one byte too short -- it is not long enough to contain the '\0' byte that is copied into place with the strcpy(3) call immediately following. This routine too is scribbling over unallocated memory.
Related
I have a major issue that is happening to my code, that I've been trying to fix for hours now.
The code below is the one relevant to the issue that I am having...
The method addBucket:
void addBucket(SPACE * hashmap,char * tempvalue, char * tempkey){
printf("BEGINNING OF FUNC...\n");
void *prevadd = hashmap[0];
char *value = varString(tempvalue);
char *key = varString(tempkey);
void *aftadd = hashmap[0];
printf("BUCKET %s - %s\n",value,key);
BUCKET *newBucket = malloc(sizeof(BUCKET *));
fillBucket(value,key,newBucket);
int hash = hashFunc(key);
printf("FILL, FULFILLED\n");
if(!hashmap[hash]){
hashmap[hash] = malloc(sizeof(BASE*));
hashmap[hash]->first = NULL;
}
ITEM *location;
location = hashmap[hash]->first;
//This creates a new item in the list, if there isn't any.
//It does this by initialising the base, called box.
if(!location){
hashmap[hash]->first = (ITEM *) calloc(1,sizeof(ITEM *));
hashmap[hash]->first->next = NULL;
hashmap[hash]->first->prev = NULL;
hashmap[hash]->first->data = newBucket;
}
//This instead adds a new item to the list.
else{
//This loop reaches the last ITEM in the linked list itself
while(location->next){
location = location->next;
}
//This initialises the newItem that will be added
ITEM *newItem = (ITEM *) calloc(1,sizeof(ITEM));
newItem->next = NULL;
newItem->data = newBucket;
newItem->prev = location;
location->next = newItem;
}
}
The declared structs that are used:
//Declares a struct called BUCKET.
//Serves as the bucket of the hash table.
typedef struct bucket{
char * value; //The value inputted.
char * key; //The key to be hashed.
}BUCKET;
//Declares a struct called ITEM.
//Holds the bucket, as well as the address to the next bucket.
//It also holds the address to the previous bucket.
typedef struct item{
struct bucket * data;
struct item * next;
struct item * prev;
}ITEM;
//Declares a struct called BASE.
//Serves as the base node for the linked lists.
//The amount of initialised linked lists is the same as the amount of bases.
typedef struct base{
struct item * first;
}BASE;
//Declares a struct of an array of BASES, meaning linked lists.
//Essentially defines the size of the hashspace.
typedef BASE *SPACE;
...And the method expandHashspace(); :
//Makes the size of the entire hashspace larger.
//Only takes a value larger than the current size due to possible data loss.
SPACE* expandHashspace(SPACE *hashmap, int newSize){
if(newSize>100 || newSize<hashSpaceSize){
printf("Exiting...\n");
return NULL;
}
else {
SPACE *nw = NULL;
nw = realloc(hashmap, sizeof(SPACE *) * newSize);
hashmap = nw;
hashSpaceSize = newSize;
return hashmap;
}
}
Here's also the initHashmap() method:
SPACE* hashmapInit(SPACE *hashmap){
hashmap = calloc(5, sizeof(SPACE *));
hashSpaceSize = 5;
return hashmap;
}
What I am doing here is initialising the hashmap, adding three buckets, expanding the hashmap, then adding three more buckets. Here's the order in more simple terms:
initHashmap();
addBucket(...); x3
expandHashmap();
addBucket(...); x3
However, on that last part, as soon as I run addBucket once, I get a SIGSEGV error. Checking through debugging, I realised something that was off.
Do you see the variables *prevadd and *aftadd? I added them while debugging to see what was happening to the address of hashmap[0]. Here is a picture of my results:
As you can see there, the address of hashmap[0] varied wildly during those two char * lines. Specifically, the change of address happens on the char *value line.
Please go easy on me, as I've just started learning C 3 months ago, and I am still incredibly unaccustomed to memory allocation. If the error is obvious, please point it out, and if I have some problem with the way that I am allocating memory, or freeing it, I am more than happy to hear them (my code has a pretty major heisenbug that I cannot fix for the life of me, but that's beside the point).
Thank you in advance... Sorry for all the recent questions.
update : forgot to add varString();...
char* varString(const char *origString){
size_t i;
for(i = 0;origString[(int)i]!='\0';i++){}
if(origString[i-1]=='\n') i-=2;
char *newString = malloc(i);
for(int j = 0; j <= i; j++){
newString[j] = origString[j];
}
newString[i+1] = '\0';
return newString;
}
This is not an answer, but it needed more formatting than would fit in a comment:
Note that you are writing "Value No. 1"
Note the value of aftadd is 0x756c6156
In memory, assuming a little-endian machine, the layout of the number in aftadd would be:
0x56 0x61 0x6c 0x75
In ASCII these would be:
'V' 'a' 'l' 'u'
Hint hint.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
I wonder what is the best strategy for alloc memory for a struct with many pointers within.
Like this:
struct Test{
long unsigned int size;
double *A;
int *B;
double *C;
};
Then I could use many allocations, like this:
struct Test *alloc_test(long unsigned int size){
struct Test *ans = (struct Test*)malloc(sizeof(struct Test));
if(ans == NULL){
return NULL;
}
ans->size = size;
ans->A = (double *)malloc(sizeof(double)*size);
if(ans->A == NULL){
free(ans);
return NULL;
}
ans->B = (int *)malloc(sizeof(int)*size);
if(ans->B == NULL){
free(ans->A);
free(ans);
return NULL;
}
ans->C = (double *)malloc(sizeof(double)*size);
if(ans->C == NULL){
free(ans->A);
free(ans->B);
free(ans);
return NULL;
}
return ans;
}
Or I could usi a single allocation, like this:
struct Test *alloc_test(long unsigned int size){
long unsigned int mem_size = sizeof(struct Test) + sizeof(double)*2*size + sizeof(int)*size;
struct Test *ans = (struct Test*)malloc(mem_size);
if(ans == NULL){
return NULL;
}
ans->size = size;
ans->A = ans + sizeof(struct Test);
ans->B = ans->A + sizeof(double)*size;
ans->C = ans->B + sizeof(int)*size;
return ans;
}
This is possible in that sittuation because this object shouldn't be realloced. In this case, does anyone knows the advantage of each one?
Both are possible, and which one you choose is your freedom. However, you should obey alignment constraints (perhaps using alignas and alignof from <stdalign.h> for the single allocation variant)
Read also about flexible array members, which permits a single malloc in the particular case you have only one array member.
Notice that each call to malloc has its overhead (both in memory, perhaps consuming an extra word or two for internal management, and in time; a typical malloc takes less than a microsecond on my desktop).
For long-lasting programs e.g. servers you might also care about fragmentation (not an issue for most short lived applications)
The second approach (single malloc) might be slightly more cache friendly. Most often, you won't care.
BTW (as commented by chux)
ans->A = ans + sizeof(struct Test);
is wrong, because pointer arithmetic happens in units of the pointed type. You may want
ans->A = ((char*)ans)+sizeof(struct Test);
and actually you should compute mem_size more carefully (using also alignof in it, or supposing that alignof(long unsigned int) >= alignof(double) and so on) then prefer
char* ad = malloc(mem_size);
if (!ad) return NULL;
ans = ad;
ans->A = ad + sizeof(struct Test);
The exact computation of mem_size (which needs some conditional and using alignof) and the real code is left as an exercise (I'm too lame to explain it here).
In Plan A, you get memory fencing, architecture-specific memory alignment, ability to realloc. Of course one could refactor this a little bit so that error handling is not scattered all over - but that's a matter of personal style.
In Plan B, you lose all that automatic stuff - you will have to take care of it. Then it might get very difficult to read.
Depending on your allocator, you might have an easier time finding multiple smaller chunks of memory than one mega chunk. So, strategy-wise, you have to make your own decision - if you have your own allocator.
Let me show you how to handle the error in a much cleaner way for your first case:
struct Test *alloc_test(long unsigned int size)
{
struct Test *ans = malloc(sizeof(struct Test));
if(ans == NULL)
{
return NULL;
}
ans->size = size;
ans->A = malloc(sizeof(ans->A) * size);
ans->B = malloc(sizeof(ans->B) * size);
ans->C = malloc(sizeof(ans->C) * size);
if(ans->A == NULL || ans->B == NULL || ans->C == NULL)
{
free(ans->A);
free(ans->B);
free(ans->C);
free(ans);
return NULL;
}
return ans;
}
You may not need to use multiple calls to malloc() or deal with alignment at all.
If all the dynamically-allocated arrays will always have the same number of elements, use a struct that contains the actual values, and create an array of the struct:
typedef struct data
{
double A;
double B;
int C;
};
Allocation:
struct data *dataPtr = malloc( size * sizeof( *dataPtr ) );
Deallocation:
free( dataPtr );
Simple and easily understandable.
If you need to carry the size around with the data, use a struct with a flexible array of struct data:
typedef struct test
{
unsigned long size;
struct data[];
}
Allocation:
struct test *testPtr = malloc( sizeof( *testPtr ) + size * sizeof( testPtr->data ) );
testPtr ->size = size;
Deallocation:
free( testPtr );
I'm currently new to C programming, and appreciate for any tip.
Is there a shorter way to initialize struct pointers in C without removing the pointer tags?
typedef struct {
int x, y, z;
} Point3;
typedef struct {
Point3 *pos, *direction;
} Vector;
int main() {
Vector *p;
p = malloc(sizeof(Vector));
p->pos = malloc(sizeof(Point3));
p->direction = malloc(sizeof(Point3));
return 0;
}
Yes, there is a shorter way — one which is one malloc() call shorter.
Vector *p = malloc(sizeof(Vector));
if (p != 0)
{
p->pos = malloc(2 * sizeof(Point3));
if (p->pos != 0)
p->direction = &p->pos[1];
}
Allocate an array of 2 Point3 values. p->pos points to the first, and p->direction points to the second (or vice versa).
It is still 3 statements (plus error checking) and two calls to malloc(), though.
In practice, you could almost certainly get away with:
Vector *p = malloc(sizeof(Vector) + 2 * sizeof(Point3));
if (p != 0)
{
p->pos = (void *)((char *)p + sizeof(Vector));
p->direction = (void *)((char *)p + sizeof(Vector) + sizeof(Point3));
}
I am not sure that is sanctioned by the C standard, but I can't immediately think of a plausible platform configuration where it would actually fail to work correctly. It would fail if you found some bizarre platform where addresses were 16-bits each but int was 8 bytes and had to be 8-byte aligned, but that's hardly plausible.
To me, it makes far more sense to put the Point3 members directly in the Vector, instead of pointers. Fewer allocations, less memory fragmentation, fewer de-references, fewer cache-misses.
typedef struct {
int x, y, z;
} Point3;
typedef struct {
Point3 pos, direction;
} Vector;
int main(void) {
/* Local (stack) allocation of a Vector, initialized to all zeros */
Vector v = {};
/* Dynamic (heap) allocation of a Vector, initialized to all zeros */
Vector *p;
p = malloc(sizeof(Vector));
if (!p) {
return 1; // failure
}
*p = (Vector){};
return 0;
}
Unfortunately, there is no other way. You can simplify memory allocation with another function, like this
Vector* allocate_vector( ) {
Vector* v = (Vector*)malloc( sizeof(Vector) );
if( v == NULL ) {
/**/
}
v->pos = (Point3*)malloc( sizeof(Point3) );
if( v->pos == NULL ) {
/**/
}
v->direction = (Point3*)malloc( sizeof(Point3) );
if( v->direction == NULL ) {
/**/
}
return v;
}
And then use it, when you need new Vector.
Vector* v = allocate_vector( );
I try to use a new struct for a dynamic "MapNode"s array, yet the program crashes:
Unhandled exception at 0x000C191C in Astar.exe: 0xC0000005: Access violation reading location 0xCCCCCCCC.
I call the getConnectedNodesArray function, which calls the other two functions.
I know it's some kind of pointers problem.
When I used copies of the data instead of trying to point to existing data in MapNode map[][12] it worked.
Thanks.
typedef struct MapNode * MapNodePointer;
typedef struct MapNode{
int x;
int y;
int value;
int traversable;
double f;
double g;
double h;
MapNodePointer parentNode;
}MapNode;
typedef struct MapNodesArray{
MapNode* nodes;
int size;
}MapNodesArray;
void addNodeToEnd(MapNodesArray* arr, MapNode* p) {
arr->size++;
arr->nodes = realloc(arr->nodes, arr->size * sizeof(MapNode*));
(&(arr->nodes))[arr->size - 1] = p;
}
MapNodesArray* NewNodesArr() {
MapNode *first = realloc(NULL, 0 * sizeof(MapNode));
MapNodesArray temp = { first, 0 };
return &temp;
}
MapNodesArray* getConnectedNodesArray(MapNodePointer node, MapNode map[][12]) {
MapNodesArray* arr = NewNodesArr();
addNodeToEnd(&arr, &map[node->x - 1][node->y - 1]);
return arr;
}
You seem to fear indirection. Face it head-on and make sure you get exactly the amount you want:
typedef struct MapNode * MapNodePointer;
The above is a bad idea, because it hides the pointer-ness.
typedef struct MapNodesArray{
MapNode* nodes;
int size;
}MapNodesArray;
The above structure is no good for storing a dynmaic list of pointers to nodes. The nodes-member needs one more star: MapNode** nodes;
void addNodeToEnd(MapNodesArray* arr, MapNode* p) {
arr->size++;
arr->nodes = realloc(arr->nodes, arr->size * sizeof(MapNode*));
There's a better way to indicate the amount of memory you need: arr->size * sizeof *arr->nodes Always check for allocation failure. Bare-bones would be aborting the program. Insert here:
if(!arr->nodes) abort();
The compiler will rightfully complain about the next line now, just remove the address-of-operator:
(&(arr->nodes))[arr->size - 1] = p;
}
MapNodesArray* NewNodesArr() {
MapNode *first = realloc(NULL, 0 * sizeof(MapNode));
The above line could be replaced with MapNode* first = 0;
MapNodesArray temp = { first, 0 };
The above line defines an automatic variable, never return a pointer to that.
return &temp;
}
oops. Complete rewrite:
MapNodesArray* NewNodesArr() {
MapNodesArray temp* = malloc(sizeof *temp);
*temp = (MapNodesArray){ 0, 0 };
return temp;
}
Or even better:
MapNodesArray NewNodesArr() {
return (MapNodesArray){ 0, 0 };
}
Exactly how much memory do you think
MapNodesArray* NewNodesArr() {
MapNode *first = realloc(NULL, 0 * sizeof(MapNode));
MapNodesArray temp = { first, 0 };
return &temp;
}
will allocate? (hint: none at all.)
Also, you're returning a pointer to a local variable (via &temp). That thing dies with the function return.
Agree with what EOF has said, also the line
(&(arr->nodes))[arr->size - 1] = p;
in function addNodeToEnd, will be writing the address p in a memory location outside the the nodes array. This will lead to memory corruption.
to illustrate
say variable 'nodes' has a memory address 0x00000002 and you have assigned a memory location say 0x00000050 through the call to realloc. The statement above takes the offset (arr->size-1) from 0x00000002 instead of taking it from 0x00000050. This is because you are taking the address of nodes by using &. Something of the form
(arr->nodes)[arr->size - 1] = p;
will take the offset from 0x00000050 which is what you seem to be needing.
I have defined struct like
typedef struct {
char *oidkey;
int showperf;
char oidrealvalue[BUFSIZE];
char *oidlimits;
} struct_oidpairs;
and I have array of struct
struct_oidpairs b[] ={{.....},....}
and I want to copy it to new struct array a[]
please help
Something like this:
memcpy(dest, src, sizeof(struct) * sizeof(src));
Your struct contains pointers as data members, this means you will have to roll out your own copy function that will do something sensible with the pointers. memcpy only works is all the data related to the struct is stored in the struct.
For real copy of the contents, follow Sjoerd's answer and then:
for (i = 0; i < sizeof(src); i++)
{
if (src[i].oidkey != NULL)
{
dest[i].oidkey = malloc(strlen(src[i].oidkey) + 1);
strcpy(dest[i].oidkey, src[i].oidkey);
}
if (src[i].oidlimits != NULL)
{
dest[i].oidlimits = malloc(strlen(src[i].oidlimits) + 1);
strcpy(dest[i].oidlimits, src[i].oidlimits);
}
}
You may consider memcpy if you are interested in speed.
Update:
Following harper's code, I
updated the code to check NULL
pointers
This is a quoted note from
gordongekko:
This solution will crash if
oidkey or oidlimits are != NULL and not
'\0'-terminated means not initialized
Makes NOT a deep copy:
struct_oidpairs b[] = {...};
size_t len = sizeof b/sizeof*b;
struct_oidpairs *a = malloc(sizeof b);
if( !a ) /* ERROR handling */
memcpy( a, b, sizeof b );
...
free( a );
or
while( len-- )
a[len] = b[len];
...
free( a );
maybe using :
for(int i=0; i<b.size() ;i++)
//I am not sure if this is the correct name for the size function
{
a[i]=b[i];
}