It's been a long since I don't use C language, and this is driving me crazy. I have an array of structs, and I need to create a function which will copy one array to another (I need an exact copy), but I don't know how to define the function call. I guess I need to use pointers, but when I try it gives me an error.
struct group{
int weight;
int x_pos;
int y_pos;
int width;
int height;
};
struct group a[4];
struct group b[4];
copySolution(&a, &b);
That last declaration send me an error. As I said, it's been a long since programming in C, so I'm a bit lost right now :(
That should do it:
memcpy(&b, &a, sizeof(a));
EDIT: By the way: It will save a copy of a in b.
As Johannes Weiß says, memcpy() is a good solution.
I just want to point out that you can copy structs like normal types:
for (i=0; i<4; i++) {
b[i] = a[i]; /* copy the whole struct a[i] to b[i] */
}
This has a feel of poorly masqueraded homework assignment... Anyway, given the predetermined call format for copySolution in the original post, the proper definition of copySolution would look as follows
void copySolution(struct group (*a)[4], struct group (*b)[4])
{
/* whatever */
}
Now, inside the copySolution you can copy the arrays in any way you prefer. Either use a cycle
void copySolution(struct group (*a)[4], struct group (*b)[4])
{
const struct group *pb, *pbe;
struct group *pa;
for (pa = *a, pb = *b, pbe = pb + sizeof *b / sizeof **b;
pb != pbe;
++pa, ++pb)
*pa = *pb;
}
or use memcpy as suggested above
void copySolution(struct group (*a)[4], struct group (*b)[4])
{
memcpy(b, a, sizeof *b);
}
Of course, you have to decide first which direction you want your arrays to be copied in. You provided no information, so everyone just jumped to some conclusion.
In my case previous solutions did not work properly! For example,
#Johannes Weiß's solution did not copy "enough" data (it copied about half of the first element).
So in case, somebody needs a solution, that will give you correct results, here it is:
int i, n = 50;
struct YourStruct *a, *b;
a = calloc(n, sizeof(*a));
b = malloc(n * sizeof(*b));
for (i = 0; i < n; ++i) {
// filling a
}
memcpy(b, a, n * sizeof(*a)); // <----- see memcpy here
if (a != NULL) free(a);
a = calloc(n*2, sizeof(*a));
memcpy(a, b, n * sizeof(*b)); // <------ see memcpy here again
Some notes, I used calloc for a, because in the '// filling a' part I was doing operations that required initialized data.
The compiler has no information about the size of the array after passing them as pointer into a function. So you often need a third parameter: The size of the arrays to copy.
A solution (without any error checking) could be:
void copySolution(struct group* a, struct group* b, size_t size) {
memcpy(a, b, size * sizeof(*a));
}
The easiest way is probably
b=a
although a solution with memcpy() will also work.
Related
I want to implement a generic growing array and use this struct for it:
struct dynamic_array
{
void** data;
size_t length;
size_t capacity;
};
Because void* doesn't allow arithmetic, I wanted to know if a void* array allows it, since it is a pointer to a void*. If that doesn't work, I'd like to know how else I could implement a generic array.
Edit: Since not everyone knows what I want to do with it, here's a code snippet how I could use the array:
for(size_t i = 0; i < array->length; i++)
{
if(strcmp((char*)array->data[i], some_string) == 0)
{
break;
}
}
Of course it's not only going to be char* but struct* too, and I know I have to cast them, but void* should allow casting back and forth without data loss, right?
Yes, this works. A pointer to void (void *) is a perfectly valid data object, so you can have an array of pointers to void, and access elements in that array in the normal way.
An example code snippet:
int i;
char c;
float f;
struct dynamic_array a;
a.capacity = 1024;
a.data = malloc(a.capacity * sizeof(void*));
a.data[0] = &i;
a.data[1] = &c;
a.data[2] = &f;
a.length = 3;
As Lee Daniel Crocker wrote, void * doesn't allow pointer arithmetic because the compiler doesn't know what it's pointing to. But void ** does, because we know exactly what it points to: pointers.
I'm converting Java code to C, and something as simple as swapping contents of multi arrays in Java:
boolean[][] temp = board;
board = nextBoard;
nextBoard = temp;
Seems to be a lot more troublesome in C.
After viewing similar questions on this site, I have learned that I have to use memcpy which I initiated in a method called arrayCopy.
This is arrayCopy:
void arrayCopy(char * a, char * b)
{
struct universe data;
int r;
for(r = 0; r < data.rows; r++)
memcpy(b, a, sizeof(a));
}
Which I call from the main method:
char temp[SIZE][SIZE];
arrayCopy(&data.board, &temp);
arrayCopy(&data.nextBoard, &data.board);
arrayCopy(&temp, &data.nextBoard);
With the following struct:
struct universe
{
char board[SIZE][SIZE];
char nextBoard[SIZE][SIZE];
int columns;
int rows;
}universe;
But I'm getting warnings such as:
A2Q1.c:189:15: warning: incompatible pointer types passing
'char (*)[60][60]' to parameter of type 'char *'
Yet memcpy only returns pointers, so I can't switch the parameters. I also can't use malloc() yet as other questions suggest because I have not learned it yet, so any other suggestions would be appreciated.
try this
void swapBoard(struct universe *x){
char temp[SIZE][SIZE];
memcpy(temp, x->board, sizeof(temp));
memcpy(x->board, x->nextBoard, sizeof(temp));
memcpy(x->nextBoard, temp, sizeof(temp));
}
int main(){
struct universe data;
//...
swapBoard(&data);
I think you are making it a bit over-complicated. You can use memcpy directly in your example above to copy everything from a to b without iterating through it. If you run this code...
int main()
{
char temp[60][60];
printf("%d", sizeof(temp));
}
You'll see that sizeof will give you 3600 bytes, 60*60 to the total bytes allocated by the array. These byte are allocated in a contiguous chunk of memory and memcpy can copy them in one swoop. This demonstrates the point:
int main()
{
char temp[60][60];
memset(temp, 'a', sizeof(temp));
char temp2[60][60];
memset(temp2, 'b', sizeof(temp2));
memcpy(temp2, temp, sizeof(temp2));
printf("%c", temp2[23][34]);
}
The printf will print 'a'. In your code above, this should work just fine:
char temp[SIZE][SIZE];
memcpy(data.board, temp, sizeof(data.board));
memcpy(data.nextBoard, data.board, sizeof(data.nextBoard));
memcpy(temp, data.nextBoard, sizeof(temp));
Note that this assumes all of these arrays are identical in size. You may want to create a minsize function or use a macro function like #define MINSIZE(a,b) (sizeof((a)) < sizeof((b)) ? sizeof((a)) : sizeof((b))) to be safe.
This might be a very stupid question but i don't understand this:
If i have:
void* a;
void* b;
And I want to implement a generic swap function, why can't I do this:
void swap(void* a, void* b)
{
void* temp = malloc(sizeof(*a));
*a = *b;
*b = *temp;
free(temp);
}
Thank you
I added this later on:
So i understand now why it is impossible but now i have another question:
Since
sizeof(*a)
is undefined, someone told me i could do this:
#define SWAP(a,b) \
{ \
void* temp = malloc(sizeof(*a)); \
memcpy(temp , a , sizeof(*a)); \
memcpy(a, b, sizeof(*a)); \
memcpy(b, temp, sizeof(*a));
free(temp);
}
of course i assume a and b are of the same type.
Why will this solution work?
thank you
You cannot dereference a void *, there is no information about the type of data it's pointing at. So your code won't compile, which is why you cannot do that.
That's the point of void *, it's a "pointer to anything", and there is absolutely no additional information available if you don't add it yourself.
If I have:
char a; /* size 1 */
int b; /* assume size 4 */
and call:
swap(&a, &b); /* assuming it compiled */
All information the function gets is the address of the two variables. There's no way for the function (or the compiler) to magically follow those pointers backward and figure out what the sizes of the pointed-to values are. None.
This way you only "copy" the pointer address but not the actual data. once after you freed temp, y becomes an invalid address. Besides that you're not using a or b in any case
To answer your 2nd question, your SWAP() macro will still NOT work as intended if you pass void* pointers to it. Or for that matter, if you pass two pointers of different types.
It will work for something like this:
int a = 2, b = 3;
char c = '0', d = '1';
SWAP(&a, &b);
SWAP(&c, &d);
Here is the piece of codes where I don't understand
#include "malloc.h"
/*some a type A and type for pointers to A*/
typedef struct a
{
unsigned long x;
} A, *PA;
/*some a type B and type for pointers to B*/
typedef struct b
{
unsigned char length;
/*array of pointers of type A variables*/
PA * x;
} B, *PB;
void test(unsigned char length, PB b)
{
/*we can set length in B correctly*/
b->length=length;
/*we can also allocate memory for the array of pointers*/
b->x=(PA *)malloc(length*sizeof(PA));
/*but we can't set pointers in x*/
while(length!=0)
b->x[length--]=0; /*it just would not work*/
}
int main()
{
B b;
test(4, &b);
return 0;
}
Can anyone elaborate conceptually to me why we can't set pointers in array x in test()?
On the last line of test() you are initializing the location off the end of your array. If your length is 4, then your array is 4 pointers long. b->x[4] is the 5th element of the array, as the 1st is b->x[0]. You need to change your while loop to iterate over values from 0 to length - 1.
If you want to set to null every PA in b->x, then writing --length instead of length-- should do the job.
Obviously trying to figure out where the -- belongs is confusing. You better write:
unsigned i;
for (i = 0; i < length; i++)
b->x[i] = 0;
But in fact, in this case, you could simply use:
memset(b->x, 0, length*sizeof(PA));
Your structure is more complicated by one level of dynamic memory allocation than is usually necessary. You have:
typedef struct a
{
unsigned long x;
...and other members...
} A, *PA;
typedef struct b
{
unsigned char length;
PA * x;
} B, *PB;
The last member of B is a struct a **, which might be needed, but seldom is. You should probably simplify everything by using:
typedef struct a
{
unsigned long x;
} A;
typedef struct b
{
unsigned length;
A *array;
} B;
This rewrite reflects a personal prejudice against typedefs for pointers (so I eliminated PA and PB). I changed the type of length in B to unsigned from unsigned char; using unsigned char saves on space in the design shown, though it might conceivably save space if you kept track of the allocated length separately from the length in use (but even then, I'd probably use unsigned short rather than unsigned char).
And, most importantly, it changes the type of the array so you don't have a separate pointer for each element because the array contains the elements themselves. Now, occasionally, you really do need to handle arrays of pointers. But it is relatively unusual and it definitely complicates the memory management.
The code in your test() function simplifies:
void init_b(unsigned char length, B *b)
{
b->length = length;
b->x = (A *)malloc(length*sizeof(*b->x));
for (int i = 0; i < length; i++)
b->x[i] = 0;
}
int main()
{
B b;
init_b(4, &b);
return 0;
}
Using an idiomatic for loop avoids stepping out of bounds (one of the problems in the original code). The initialization loop for the allocated memory could perhaps be replaced with a memset() operation, or you could use calloc() instead of malloc().
Your original code was setting the pointers in the array of pointers to null; you could not then access any data because there was no data; you had not allocated the space for the actual struct a values, just space for an array of pointers to such values.
Of course, the code should either check whether memory allocation failed or use a cover function for the memory allocator that guarantees never to return if memory allocation fails. It is not safe to assume memory allocation will succeed without a check somewhere. Cover functions for the allocators often go by names such as xmalloc() or emalloc().
Someone else pointed out that malloc.h is non-standard. If you are using the tuning facilities it provides, or the reporting facilities it provides, then malloc.h is fine (but it is not available everywhere so it does limit the portability of your code). However, most people most of the time should just forget about malloc.h and use #include <stdlib.h> instead; using malloc.h is a sign of thinking from the days before the C89 standard, when there was no header that declared malloc() et al, and that is a long time ago.
See also Freeing 2D array of stack; the code there was isomorphic with this code (are you in the same class?). And I recommended and illustrated the same simplification there.
I just added a printf in main to test b.length and b.x[] values and everything's work.
Just added it like that printf("%d, %d %d %d %d", b.length, b.x[0], b.x[1], b.x[2], b.x[3]); before the return.
It gaves 4, 0, 0, 0, 0 which is I think what you expect no? Or it is an algorithmic error
I assume you are trying to zero all of the unsigned longs inside the array of A's pointed to within B.
Is there a precedence issue with the -> and [] operators here?
Try:
(b->x)[length--] = 0;
And maybe change
typedef struct a
{
unsigned long x;
} A, *PA;
to
typedef struct a
{
unsigned long x;
} A;
typedef A * PA;
etc
I'm trying to swap objects for a homework problem that uses void pointers to swap objects. The declaration of my function has to be:
void swap(void *a, void *b, size_t size);
I'm not looking for the exact code how to do it so I can figure it out by myself, but I'm not sure if I understand it correctly. I found that one problem is by doing:
void *temp;
temp = a;
a = b;
b = temp;
only changes what the pointers point to. Is that correct? If it is correct, why doesn't swapping pointers actually change the contents between *a and *b. Because if your pointer points to something different, couldn't you dereference it and the objects would now be different?
Similarly, just switching the values like:
void *temp;
*temp = *a;
*a = *b;
*b = *temp;
Is not correct either, which I'm not sure why. Because again, it seems to me that the content is switched.
Does swapping objects mean complete swapping of memory and value of what a pointer points to?
So it seems like I have to use malloc to allocate enough space for my swap. If I allocate enough memory for one object, assuming they are the same size, I don't really see how it is different than the other two methods above.
void *temp = malloc(sizeof(pa));
// check for null pointer
temp = a;
// do something I'm not sure of since I don't quite get how allocating space is any
// different than the two above methods???
Thanks!
Swapping pointers does not change the pointed-to values. If it did, that would be like swapping address labels on envelopes moving me into your house and you into mine.
You were nearly there:
void swap(void *a, void *b, size_t size) {
char temp[size]; // C99, use malloc otherwise
// char serves as the type for "generic" byte arrays
memcpy(temp, b, size);
memcpy(b, a, size);
memcpy(a, temp, size);
}
The memcpy function copies memory, which is the definition of objects in C. (Called POD or plain ol' data in C++, to compare.) In this way, memcpy is how you do assignment without caring about the type of the object, and you could even write other assignments as memcpy instead:
int a = 42, b = 3, temp;
temp = b;
b = a;
a = temp;
// same as:
memcpy(&temp, &b, sizeof a);
memcpy(&b, &a, sizeof a);
memcpy(&a, &temp, sizeof a);
This is exactly what the above function does, since you cannot use assignment when you do not know the type of the object, and void is the type that stands in for "unknown". (It also means "nothing" when used as function return type.)
As a curiosity, another version which avoids malloc in common cases and doesn't use C99's VLAs:
void swap(void *a, void *b, size_t size) {
enum { threshold = 100 };
if (size <= threshold) {
char temp[threshold];
memcpy(temp, b, size);
memcpy(b, a, size);
memcpy(a, temp, size);
}
else {
void* temp = malloc(size);
assert(temp); // better error checking desired in non-example code
memcpy(temp, b, size);
memcpy(b, a, size);
memcpy(a, temp, size);
free(temp);
}
}
To answer your first question, let's fill in some values to see what is happening:
void* a = 0x00001000; // some memory address
void* b = 0x00002000; // another memory address
/* Now we'll put in your code */
void* temp; // temp is garbage
temp = a; // temp is now 0x00001000
a = b; // a is now 0x00002000
b = temp; // b is now 0x00001000
So at the end of those statements, the pointer's values have been swapped, that is, whatever a was pointing to is now pointed to by b, and vice versa. The values of what those pointers are pointing to are unmodified, it's just that now their memory addresses are being held by different pointers.
To answer your second question, you cannot dereference a void*. The reason for this is that void has no size, so to try and dereference or assign to something that has no size is nonsensical. Thus, void* is a way of guaranteeing you can point to something, but you will never know what that something is without more information (hence the size parameter to your routine).
From there, knowing the pointer and the size of the data the pointer points to, you can use a routine like memcpy to move the data pointed to by one pointer into the location pointed to by another.
Parameters are like local variables, with values copied into them before the function starts executing. This prototype:
void swap(void *a, void *b, size_t size);
Means that the two addresses are copied into new variables called a and b. So if you change what is stored in a and b, nothing you do will have an any effect after swap returns.
I had a question similar to this for my C course. I think memcopy is probably best but you can also try this:
typedef unsigned char * ucp;
void swap(void *a, void *b, int size){
ucp c=(ucp)a;
ucp d=(ucp)b;
for(int i=0; i<size; i++){
int temp=(int)c[i];
c[i]=(int)d[i];
d[i]=temp;
}
}
Basically what this does is cast both pointers to an unsigned char pointer type. Then you increment the pointer, which in the case of an unsigned char, increments one BYTE at a time. Then what you're doing is basically copying the contents of each byte at a time in memory. If anyone wants to correct or clarify on this I would appreciate it too.
First of all, note that any changes to the pointers inside the function won't be propagated to outside the function. So you're going to have to move memory around.
The easiest way to do that is with memcpy - allocate a buffer on the stack, memcpy the appropriate size from a into it, memcpy from b to a, and one last memcpy from temp into b.
If you were writing a function to swap two integers, given pointers to them, your solution of swapping the values pointed to would work. However, consider the situation with
struct {
int a;
int b;
} a, b;
swap(&a, &b, sizeof(a));
You need to figure out a way to swap the contents of each value passed without any knowledge of what they actually consist of.
You're close.
The problem is: you are "swapping" only pointers a and b which are local variables in the function.
I assume outside of the function you have some variables, let's call them:
void *x = ...;
void *y = ...;
When you call:
swap(x, y, some_size);
a and b points to the same objects as x and y respectively. Now, when you swap what a and b points too, x and y are still pointing to what they where pointing before.
To change what memory x and y points you would have to pass a pointer to the x variable, so a pointer to a pointer :)
Because you can't change function declaration you can only swap the content of the memory where x (and a) and y (and b) points to. Some solutions are in other answers :) Generally memcpy is what you want.
To have any real effect, you need to do the equivalent of the second block you mentioned:
void *temp;
*temp = *a;
*a = *b;
*b = *temp;
The problem here is that 'void' doesn't have a size, so you can't assign 'void's as they stand. You need to allocate space for temp to point at, then copy the values using something like memcpy().
To change the pointer inside and keep it outside, you have to pass the pointer by reference or a double pointer.
If your function has to be like:
void swap(void *a, void *b, size_t size);
I suppose that you have to implement something like:
void * temp;
temp = malloc(size);
memcpy(temp,a,size);
memcpy(a,b,size);
memcpy(b,temp,size);
free(temp);
We need not use memcpy for swapping two pointers, following code works well(tested for swapping int* and char* strings):
void swap(void **p, void **q)
{
void *t = *p;
*p = *q;
*q = t;
}