i need your help!
I like to copy a struct like this:
typedef struct PackageObject_s {
long **vertex; // vertices
long num_vertex; // count of vertices
long objectType; //
REAL r; //
long bottom[3]; // bounding box bottom vector
long top[3]; // bounding box top vector
long *start; //
REAL coverage; //
} PackageObject __attribute__ ((aligned));
I try it like this:
static inline void PackageObject_copy(PackageObject *dst, const PackageObject *src) {
dst->num_vertex = src->num_vertex;
dst->objectType = src->objectType;
dst->r = src->r;
vec_assign3l(dst->bottom, src->bottom);
vec_assign3l(dst->top, src->top);
// TODO copy **vertex ???
dst->coverage = src->coverage;
dst->coverage = src->coverage;
}
How can i solve this?
Thank you in advance for your help!!
UPDATE - my solution for deepcopy of vertex - thx for all help:
dst->vertex = (long *)malloc(dst->num_vertex * 3 * sizeof(long));
for (long i=0; i < src->num_vertex; i++) {
dst->vertex[i] = (long)malloc(3*sizeof(long));
memcpy(dst->vertex[i],src->vertex[i],3 * sizeof(long));
}
I'm going to assume that the vertices are not shared between objects. That is, they belong to the structure in question.
There are two primary cases to consider:
1. Copying into a new object
2. Copying into an existing object
Copying into the new object is straightforward.
1a. Allocate space for <num_vertex> pointers.
1b. Allocate space for each vertex.
2a. Copy <num_vertex> pointers from source to destination.
2b. Copy <num_vertex> vertices from source to destination.
Copying into an existing object is much the same as copying into a new object except that you have to do the following first.
0a. Loop through each element of <vertex> and free the vertex.
0b. Free the array of vertex pointers.
1. Follow the steps for copying into a new object.
Hope this helps.
Original answer:
Assuming vertex points to an array of vertices, and that each vertice contains 3 longs (x,y,z):
dst->vertex = (long **)malloc(dst->num_vertex * 3 * sizeof(long);
memcpy(dst,src,dst->num_vertex * 3 * sizeof(long));
Update because I realized this might work but isn't clean or especially safe
As I mentioned in comments, code would be cleaner if you had
typedef struct vertextag {
long x;
long y;
long z;
} vertex_type;
And then did:
dst->vertex = (vertex_type *)malloc(dst->num_vertex * sizeof(vertex_type);
memcpy(dst,src,dst->num_vertex * sizeof(vertex_type));
It depends on whether the vertex-array should belong to the object you are trying to copy or whether it is shared among multiple objects. Both approaches are used in practice, depending on the situation (the array must be copied if the vertices can be changed for the copy-object separately). You have to choose which of them makes sense for the application you are developing.
If the array can be shared by objects pointing to them, just copy the pointer.
dst->vertex = src->vertex;
If each object has their own vertices (so they can be changed separately for the copied object) then you have to allocate and copy the array and the place where the pointer is stored and set a pointer to that place into the copy-object.
long* vertexCopy = malloc(howmanybytes);
memcpy(vertexCopy, *src->vertex, howmanybytes);
long** holder = malloc(sizeof(void*));
holder[0] = vertexCopy;
dst->vertex = holder;
Related
I have a vector type defined as follows:
typedef struct vector {
void **items;
unsigned int capacity;
unsigned int size;
} vector_st;
typedef vector_st *vector_t;
And I allocate and free it as follows:
vector_t vector_init(unsigned int capacity)
{
vector_t v = (vector_t)calloc(1, sizeof(vector_st));
v->capacity = capacity;
v->size = 0;
v->items = malloc(sizeof(void *) * v->capacity);
return v;
}
void vector_free(vector_t v)
{
if (v) {
free(v->items);
v->capacity = 0;
v->size = 0;
free(v);
v = NULL;
}
}
Now, the point is that I want to copy one vector to another one, meaning including all its content. So, I tried to define a function like this:
void vector_copy(vector_t to, vector_t from)
{
memcpy(to, from, sizeof(vector_st));
}
But, this does not seem to work quite right, as when I do something like this:
vector_t vec = vector_init(3);
vector_add(vec, 1);
vector_add(vec, 2);
vector_add(vec, 3);
unsigned int i;
for (i = 0; i < vec->size; i++) {
printf("%d\n", (int)vector_get(vec, i));
}
vector_t copied = vector_init(3);
vector_copy(copied, vec);
vector_free(vec);
for (i = 0; i < copied->size; i++) {
printf("%d\n", (int)vector_get(copied, i));
}
For the first vector it correctly prints 1 2 3 but for the second one it prints 0 2 3. So, basically I believe it just copies maybe the memory addresses and not the actual content, as when I free the first vector the first element is set to 0. Any ideas how to copy this structure in my case?
EDIT:
void vector_resize(vector_t v, unsigned int capacity)
{
void **items = realloc(v->items, sizeof(void *) * capacity);
if (items) {
v->items = items;
v->capacity = capacity;
}
}
void vector_add(vector_t v, void *item)
{
if (v->capacity == v->size) {
vector_resize(v, v->capacity * 2);
}
v->items[v->size++] = item;
}
Now, the point is that I want to copy one vector to another one, meaning including all its content.
What you seem to want to perform is called a "deep copy". That means copying not just the data, but any additional pointed-to data, recursively. You have judged correctly that memcpy() of the structure itself does not do this; the vector elements are pointed to by pointers in the structure, but they themselves are elsewhere, and therefore are not copied.
What's worse, you have a fundamental problem here with copying the pointed-to data: your copy function doesn't know how big the pointed-to elements are. Without such knowledge, it is impossible to copy them. Furthermore, if the elements themselves contain pointers, then to perform a true deep copy, you need information about which members those are, and how large are the objects to which they point. Etc.
Basically, then, it is impossible write a generic deep copy (in any language). Performing a deep copy requires information at every level about what you are copying. To give you a bit of a flavor, however, you could copy one level deeper if you could rely on the vector elements being of a consistent size that is known at call time. That might look something like this:
void vector_copy(vector_t to, vector_t from, size_t element_size) {
// NOTE: robust code would check for memory allocation failures. This code does not.
void **temp_items;
to->capacity = from->capacity;
to->size = from->size;
// evaluates to NULL if allocation fails:
temp_items = realloc(to->items, from->capacity * sizeof(*to->items));
to->items = temp_items;
for (int i = 0; i < from->size; i++) {
to->items[i] = malloc(element_size); // evaluates to NULL if allocation fails
memcpy(to->items[i], from->items[i], element_size);
}
}
You could avoid the need to pass the element size by instead making it a member of the vector structure.
Note that this assumes that vector to has been initialized, and that it is not necessary to free the pointers to the individual items, if any, that are currently in it (i.e. the vector does not own these, and is therefore not responsible for managing their memory).
void vector_copy(vector_t to, vector_t from)
{
memcpy(to, from, sizeof(vector_st));
}
This is wrong because the vector owns its items object. So you need to do four things in vector_copy:
1) Free the existing items objects in the destination vector so that it's not leaked.
2) Copy the capacity and size.
3) Allocate a brand new items for the destination vector to own.
4) Copy the source items into the newly-allocated destination items.
If you consider vector_copy to be an initialization function, skip step 1. But in that case, I'd strongly suggest changing the name to vector_init so that it's clear that it creates a new vector.
You're simply trying to access free()d memory. First you're calling free(v->items) in vector_free(), and then you're trying to print its contents as if nothing had happened!
When you copy a vector to another (no matter how) the new vector will hold a reference to old_vector->items, so you cannot just free() it -- C is not a garbage collected language and malloc doesn't reference-count the blocks it's managing.
So, basically I believe it just copies maybe the memory addresses and not the actual content
Yes, because at this line
memcpy(to, from, sizeof(vector_st));
you simply discards whatever memory was allocated for to, so memory held by copied becomes leaked; and after vector_free(vec) copied now holds a dangling reference to an already-freed memory.
To copy vector's contents into another, well, copy it:
memcpy(to->items, from->items, sizeof(void *) * from->size);
(Or less efficient
int i;
for(i = 0; i < from->size; ++i) to->items[i] = from->items[i];
)
Or, better, define a copy-constructor:
vector_t vector_copy(vector_t src);
// this functions allocates a fresh vector on heap;
// set its size and capacity to those of src;
// sets its items to a fresh array on heap of capacity elements;
// copies src's items into that array;
// and returns it
I have some structs like the below:
typedef struct {
GLubyte red, green, blue;
} pixel;
typedef struct {
pixel *pixelData;
int w, h;
} imagen;
It's for an image loader and image processor (applies filters to a loaded image).
I'm initializing two imagen:
imagen work, original;
work is something that I want to display after having some filters applied, and original is something I can reset to.
void loadImage() {
//load data into (imagen)original
}
work = original;
After loading the image, I copy it to work so I can maintain a copy of the original should I want to reset later (reset being work = original again). The problem I'm facing is that the reset doesn't work: anything I apply to work is also applied to original, so I'm effectively resetting to what I'm resetting.
I think the problem is my work = original; I'm fairly new to C, but I'm assuming I'm only pointing work at original, so any logic I do on work is also applied to original?
original.w = 40;
work = original;
work.w = 50;
work = original;
Is work.w 40 or 50 in this case? If it is indeed pointing to original, how do I instead clone original onto work, so I can safely work on work without consequence of original?
You have a pixelData pointer in your struct:
typedef struct {
pixel *pixelData;
int w, h;
} imagen;
In order to create a completely independent copy, you need to copy the data pixelData is pointing to:
work.w = original.w;
work.h = original.h;
size_t size = sizeof(pixel) * work.w * work.h;
work.pixelData = (pixel*)malloc(size);
memcpy(original.pixelData, work.pixelData, size);
Also note that when you no longer need it you have to release the allocated memory:
free(work.pixelData);
I think the problem is in the pointer to pixeldata. When you assign it, you are copying the address of the value stored in original, and once you modify it with, the original is modified too. Try allocating a new pixelData pointer and then copy the original content in its value, instead of copying the pointed address itself.
To build nested TLV elements (e.g., 6F1A840E315041592E5359532E4444463031A5088801025F2D02656E), I'm using the following data structure:
typedef struct Element
{
int16_t nTag; // Tells you if pValue points to a primitive value or constructed one
uint16_t nLength;
void *pValue; // Could be either unsigned char* or TlvElement*
} TlvElement;
How can I implement a function that properly deallocates the memory used by the nested TLV elements?
// Let's build TLV data: 6F04A5020000
TlvElement *pTlvElement = (TlvElement*)malloc(sizeof(TlvElement));
pTlvElement->nTag = 0x6F;
pTlvElement->nLength = 4;
pTlvElement->pValue = malloc(sizeof(TlvElement)); // pValue points to another TLV element
TlvElement *pTlvElementChild = (TlvElement*)pTlvElement->pValue;
pTlvElementChild->nTag = 0xA5;
pTlvElementChild->nLength = 2;
pTlvElementChild->pValue = malloc(2 * sizeof(unsigned char)); // pValue points to a byte array
memset(pTlvElementChild->pValue, 0, 2);
Deallocate(pTlvElement);
//free(pTlvElementChild->pValue);
//free(pTlvElement->pValue);
//free(pTlvElement);
You just deallocate it in the order you gave in the commented lines:
free((TlvElement *)(pTlvElement->pValue)->pValue);
free(pTlvElement->pValue);
free(pTlvElement);
The function free(void *) takes a void *, so the compiler wont complain. The only cast you need is to access the field pValue of the child element.
A word of caution: unless the tag already marks this, you might consider to add keep somewhere that the element does indeed contain a child element.
Assuming the value of ->nTag field can be used for this, you can deallocate the child elements recursively:
void Deallocate(TlvElement *e)
{
if (e->nTag == 0x6f)
Deallocate((TlvElement *)e->pValue);
else
free(e->pValue)
free(e);
}
You might want to take precautions against endless recursion, though.
I am writing a light weight serialization function and need to include two variable sized arrays within this.
How should I track the size of each?
How should I define the struct?
Am I going about this all wrong?
EDIT: the result must be a contiguous block of memory
This resolves to something like
typedef struct
{
size_t arr_size_1, arr_size_2;
char arr_1[0/*arr_size_1 + arr_size_2*/];
} ...;
The size(s) should be in the front of the dynamic sized data, so that it doesn't move when expanding your array.
You cannot have 2 unknown sized arrays in your struct, so you must collapse them into one and then access the data relative from the first pointer.
typedef struct MyStruct_s
{
int variable_one_size;
void* variable_one_buf;
int variable_two_size;
void* variable_two_buf;
} MyStruct;
MyStruct* CreateMyStruct (int size_one, int size_two)
{
MyStruct* s = (MyStruct*)malloc (sizeof (MyStruct));
s->variable_one_size = size_one;
s->variable_one_buf = malloc (size_one);
s->variable_two_size = size_two;
s->variable_two_buf = malloc (size_two);
}
void FreeMyStruct (MyStruct* s)
{
free (s->variable_one_buf);
free (s->variable_two_buf);
free (s);
}
Since the data should be continuous in memory it is necessary to malloc a chunk of memory of the right size and manage it's contents more or less manually. You probably best create a struct that contains the "static" information and related management functions that do the memory management and give access to the "dynamic" members of the struct:
typedef struct _serial {
size_t sz_a;
size_t sz_b;
char data[1]; // "dummy" array as pointer to space at end of the struct
} serial;
serial* malloc_serial(size_t a, size_t b) {
serial *result;
// malloc more memory than just sizeof(serial), so that there
// is enough space "in" the data member for both of the variable arrays
result = malloc(sizeof(serial) - 1 + a + b);
if (result) {
result->sz_a = a;
result->sz_b = b;
}
return result;
}
// access the "arrays" in the struct:
char* access_a(serial *s) {
return &s->data[0];
}
char* access_b(serial *s) {
return &s->data[s->sz_a];
}
Then you could do things like this:
serial *s = ...;
memcpy(access_a(s), "hallo", 6);
access_a(s)[1] = 'e';
Also note that you can't just assign one serial to another one, you need to make sure that the sizes are compatible and copy the data manually.
In order to serialize variably-sized data, you have to have a boundary tag of some sort. The boundary tag can be either a size written right before the data, or it can be a special value that is not allowed to appear in the data stream and is written right after the data.
Which you choose depends on how much data you are storing, and if you are optimizing for size in the output stream. It is often easier to store a size before-hand, because you know how big to make the receiving buffer. If you don't then you have to gradually resize your buffer on load.
In some ways, I'd do things like Dan Olson. However:
1) I'd create the final struct by having two instances of a simpler struct that has just one variable array.
2) I'd declare the array with byte* and use size_t for its length.
Having said this, I'm still not entirely clear on what you're trying to do.
edit
If you want it contiguous in memory, just define a struct with two lengths. Then allocate a block big enough for both blocks that you want to pass, plus the struct itself. Set the two lengths and copy the two blocks immediately after. I think it should be clear how the lengths suffice to make the struct self-describing.
I am working with a 2-dimensional array of structs which is a part of another struct. It's not something I've done a lot with so I'm having a problem. This function ends up failing after getting to the "test" for-loop near the end. It prints out one line correctly before it seg faults.
The parts of my code which read data into a dummy 2-d array of structs works just fine, so it must be my assigning array to be part of another struct (the imageStruct).
Any help would be greatly appreciated!
/*the structure of each pixel*/
typedef struct
{
int R,G,B;
}pixelStruct;
/*data for each image*/
typedef struct
{
int height;
int width;
pixelStruct *arr; /*pointer to 2-d array of pixels*/
} imageStruct;
imageStruct ReadImage(char * filename)
{
FILE *image=fopen(filename,"r");
imageStruct thisImage;
/*get header data from image*/
/*make a 2-d array of of pixels*/
pixelStruct imageArr[thisImage.height][thisImage.width];
/*Read in the image. */
/*I know this works because I after storing the image data in the
imageArr array, I printed each element from the array to the
screen.*/
/*so now I want to take the array called imageArr and put it in the
imageStruct called thisImage*/
thisImage.arr = malloc(sizeof(imageArr));
//allocate enough space in struct for the image array.
*thisImage.arr = *imageArr; /*put imageArr into the thisImage imagestruct*/
//test to see if assignment worked: (this is where it fails)
for (i = 0; i < thisImage.height; i++)
{
for (j = 0; j < thisImage.width; j++)
{
printf("\n%d: R: %d G: %d B: %d\n", i ,thisImage.arr[i][j].R,
thisImage.arr[i][j].G, thisImage.arr[i][j].B);
}
}
return thisImage;
}
(In case you are wondering why I am using a dummy array in the first place, well it's because when I started writing this code, I couldn't figure out how to do what I am trying to do now.)
EDIT: One person suggested that I didn't initialize my 2-d array correctly in the typedef for the imageStruct. Can anyone help me correct this if it is indeed the problem?
You seem to be able to create variable-length-arrays, so you're on a C99 system, or on a system that supports it. But not all compilers support those. If you want to use those, you don't need the arr pointer declaration in your struct. Assuming no variable-length-arrays, let's look at the relevant parts of your code:
/*data for each image*/
typedef struct
{
int height;
int width;
pixelStruct *arr; /*pointer to 2-d array of pixels*/
} imageStruct;
arr is a pointer to pixelStruct, and not to a 2-d array of pixels. Sure, you can use arr to access such an array, but the comment is misleading, and it hints at a misunderstanding. If you really wish to declare such a variable, you would do something like:
pixelStruct (*arr)[2][3];
and arr would be a pointer to an "array 2 of array 3 of pixelStruct", which means that arr points to a 2-d array. This isn't really what you want. To be fair, this isn't what you declare, so all is good. But your comment suggests a misunderstanding of pointers in C, and that is manifested later in your code.
At this point, you will do well to read a good introduction to arrays and pointers in C, and a really nice one is C For Smarties: Arrays and Pointers by Chris Torek. In particular, please make sure you understand the first diagram on the page and everything in the definition of the function f there.
Since you want to be able to index arr in a natural way using "column" and "row" indices, I suggest you declare arr as a pointer to pointer. So your structure becomes:
/* data for each image */
typedef struct
{
int height;
int width;
pixelStruct **arr; /* Image data of height*width dimensions */
} imageStruct;
Then in your ReadImage function, you allocate memory you need:
int i;
thisImage.arr = malloc(thisImage.height * sizeof *thisImage.arr);
for (i=0; i < thisImage.height; ++i)
thisImage.arr[i] = malloc(thisImage.width * sizeof *thisImage.arr[i]);
Note that for clarity, I haven't done any error-checking on malloc. In practice, you should check if malloc returned NULL and take appropriate measures.
Assuming all the memory allocation succeeded, you can now read your image in thisImage.arr (just like you were doing for imageArr in your original function).
Once you're done with thisImage.arr, make sure to free it:
for (i=0; i < thisImage.height; ++i)
free(thisImage.arr[i]);
free(thisImage.arr);
In practice, you will want to wrap the allocation and deallocation parts above in their respective functions that allocate and free the arr object, and take care of error-checking.
I don't think sizeof imageArr works as you expect it to when you're using runtime-sized arrays. Which, btw, are a sort of "niche" C99 feature. You should add some printouts of crucial values, such as that sizeof to see if it does what you think.
Clearer would be to use explicit allocation of the array:
thisImage.arr = malloc(thisImage.width * thisImage.height * sizeof *thisImage.arr);
I also think that it's hard (if even possible) to implement a "true" 2D array like this. I would recommend just doing the address computation yourself, i.e. accessing a pixel like this:
unsigned int x = 3, y = 1; // Assume image is larger.
print("pixel at (%d,%d) is r=%d g=%d b=%d\n", x, y, thisImage.arr[y * thisImage.width + x]);
I don't see how the required dimension information can be associated with an array at run-time; I don't think that's possible.
height and width are undefined; you might want to initialise them first, as in
thisImage.height = 10; thisImage.width = 20;
also,
what is colorRGB?
*thisImage.arr = *imageArr; /*put imageArr into the thisImage imagestruct*
This won't work. You have to declare arr as colorRGB **, allocate it accordingly, etc.
it looks like you are trying to copy array by assignment.
You cannot use simple assignment operator to do that, you have to use some function to copy things, for example memcpy.
*thisImage.arr = *imageArr;
thisimage.arr[0] = imagearr[0];
The above statements are doing the same thing.
However this is not most likely what causes the memory corruption
since you are working with two dimensional arrays, do make sure you initialize them correctly.
Looking at the code, should not even compile: the array is declared as one-dimensional in your image structure but you refer to as two-dimensional?