Swapping objects using pointers - c

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;
}

Related

C function pointers

I am learning C from "C by K&R". I was going through Function pointers section.There was an example to sort an array of strings using function pointers and void pointers.(to be specific,on page 100). I have a fair understanding of function pointers and void pointers.
The example given there calls
qsort((void**) lineptr, 0, nlines-1,(int (*)(void*,void*))(numeric ? numcmp : strcmp));
And it seemlessly uses void ptr,like as below to compare and swap.
I understand that it takes array of pointer and each element by itself is a void pointer to the string. How is it possible to compare,swap a void ptr with another.
void sort(void *v[],int i,int j)
{
id *temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}
Can anyone explain the concept behind this.
How is it possible to compare, swap a void ptr with another?
Compare: comparing a void ptr with each other is meaningless, as their values are addresses.
Swap: A pointer is a variable holding an address. By changing a pointer's value you change the address it points to. Data itself is not even considered here.
Note: void pointers does not interpret the data they are pointing to. That is why you need explicit type conversion when you dereference them, such that there is a correspondence between the data they are pointing to and the variable this data is assign to.
Remember that pointers are just variables that store a memory address. If there's not any conflict between types I can't see why this shouldn't be possible!
The only difference between a void ptr and another is that you must pay attention only during the dereference (you need a cast to complete it)
For example:
void *ptr;
int m, n;
ptr = &n;
m = *((int *) ptr);
Anyway, ignoring this particular, you can work with void pointer normally.. You can, as your code shows, for example swap them just as they were int or other types variables
The function pointer required by qsort() has the following type
int (*compar)(const void *, const void *);
it means, that you can pass pointers of any type to this function since in c void * is converted to any poitner type without a cast.
Inside a comparision funcion, you MUST "cast"1 the void * poitners in order to be able to dereference them. Because a void * pointer cannot be dereferenced.
Swaping pointers is the correct way to sort an array of poitners, just like swaping integers would be the way to sort an array of integers. The other way, with an array of strings for example, would be to copy the string to a temporary buffer and perform a swap in terms of copying the data, and I think there is no need to explain why this is bad.
1
When I say cast I don't mean that you need to "cast", just convert to the appropriate poitner type. For example:
int compare_integers(const void *const x, const void *const y)
{
int *X;
int *Y;
X = x;
Y = y;
return (*X - *Y);
}
although it's of course possible to write return (*((int *) x) - *((int *) y)).
In this type of situation, it's often helpful to typedef to gain a better understanding. For illustration purposes, you could do
typedef void* address; //to emphasize that a variable of type void* stores an address
Now your swap function looks less daunting,
void swap(address v[],int i,int j) //takes an array of addresses v
{
address temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}
A void *, however, contains no information regarding the type of object it points to. So before dereferencing it, you need to cast it to the right type, which is what strcmp and numcmp do, e.g.,
int strcmp(address a1, address a2) { //assumes a1 and a2 store addresses of strings
char *s1 = a1;
char *s2 = a2;
//s1 and s2 can be dereferenced and the strings they point to can be compared
}

Why use memcpy() in C

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);

Void array, dynamic size variables in C

Alright so i'll try to explain my problem clearly.
I would like to have a function which would sort an array of anything, based on the size of an element and on the offset and the size of the the variable in an element (for use with structures).
So my function would look like:
void sort(void* array, size_t elem_size, int elem_count, size_t operand_offset, size_t operand_size)
array is a pointer to the beginning of the array
elem_size is the size of one element in the array
elem_count is the count of elements in the array
operand_offset is the offset of the variable within the element to base the sort on (it would be 0 if the element is only one variable, but it could be more if the element is a struct)
operand_size is the size of that variable
In this function i need to create a temp variable, i would do it like that:
void* temp = malloc(elem_size);
*temp = *(array+ i*elem_size);
but the compiler doesn't agree: dereferencing void* pointer, and he doesn't know the size of my temp variable...
I know i could do it byte per byte, but i would like to know if there is a better way.
So my question is:
How to set the "size" of a pointer to elem_size ?
Aditional question:
Could i type array[i] to access an element if the size is known ?
EDIT
Ok so my problem is solved i must use memcpy
But now i have another problem i didn't expect.
Given the size and the offset of the operand within the element, how could i extract it and compare it?
kinda like:
void *a = malloc(operand_size);
void *b = malloc(operand_size);
memcpy(a, array+i*elem_size + operand_offset, operand_size);
memcpy(b, array+j*elem_size + operand_offset, operand_size);
if (a < b)
...
else
...
How can i do that?
*EDIT 2: *
Well, finally it was too complicated managing an if statement for each size of operand, so i did something completely different
So basically i had a void *array containing n elements, and i was writing a function to sort it.
But instead of giving directly the offset and the size of the operand within the element, i gave the function another function to compare two elements. That works well
int compareChar(void* a, void* b);
int compareShort(void* a, void* b);
int compareInt(void* a, void* b);
int compareLong(void* a, void* b);
int compareFOO(void* a, void* b);
void sort(void* array, size_t elem_size, int elem_count, int (*compare)(void*,void*));
Couldn't you just use memcpy? That will likely do it in the most efficient manner.
uint8_t* temp = malloc(elem_size);
memcpy(temp, array + i * elem_size, elem_size);

Why the type doesn't match in this value swap code in C?

void swap(char *a,char *b){
char t;
t = *a;
*a = *b;
*b = t;
}
int main(void){
char a = '1';
char b = '2';
swap(&a,&b);
printf("The value is %c and %c respectively\n",a,b);
return 0;
}
in the above code, there's a spot that confuse me
I think if a is a pointer, and *a is the value it points to
int *ptr, a = 1;
ptr = &a;
printf("The value of *ptr should be a: %d\n",*ptr);
printf("The value of *a should be an hex address: %p\n",ptr);
so in the swap(char *a, char *b) function,it takes the value not pointer( *a not a),
swap(&a, &b)
but it actually pass the pointer value to it as the parameter, and the code works. Anybody can explain it to me?(I think for swap(char *a){...} part, the declaration doesn't mean it require *a to pass in, it means declare a pointer value a, not the value a points to as *ain elsewhere means).
* is confusing because it means two different, but closely related, things. In a variable declaration, * means "pointer". In an expression, * means "dereference the pointer".
It's intended to be a helpful mnemonic: if you have char *a in your code it means that *a is a char.
Your function
swap(char *a, char *b)
takes two parameters, both of which are of type char *. Quite literally that means they point to a character somewhere in memory.
When you dereference the pointer
t = *a;
You are saying "grab whatever a is pointing to and put it in t.
Perhaps the confusion is from the fact that * means two related but different things. In the case char *, it's defining a type, specifically one that points to a character somewhere in memory. In the case *a, the * means "look at the character being pointed to by a and let me know what it is".
In main:
a is a char
&a is a pointer to the char a.
In swap:
a is a pointer to a char
*a is the char pointed to by a.
You passed a pointer to a pointer, and it worked beautifully. Try drawing a picture with boxes and errors. Clears things up every time. Just remember your code has two as and two bs.
Yes, the asterisk * has multiple meanings related to pointers:
It be used in a declaration to introduce a variable that contains an address - a pointer:
int *ptr = NULL;
Similarly in an argument list, such as void swap(char *, char *).
It can also be used to dereference an existing pointer, or get the value pointed to, as within the function swap:
t = *a;
This generally causes a good deal of confusion for students who are new to C, but it's actually quite simple.
In this our aim is to swap the value
when you write char a='1'; i.e you are putting '1' at address 662442(suppose &a=662442).
char b='2'; i.e you are putting '2' at address 662342(suppose &b=662342).
now consider swapping a and b,here our aim is to change value at 662442(&a) to value at 662342(&b) and value at 662342(&b) to value at 662442(&a).
now for swapping we take a temporary variable char temp and will do the following
temp=*a; i.e assigning value at address 662442(&a) to temp.
*a = *b; i.e assigning value at address 662342(&b) to value at address 662442(&a).
now we will put previous value of a (i.e value kept in variable temp) at address 662342(&b)
*b = temp; i.e assigning temp to address 662442(&a)

Simple swap function...why doesn't this one swap?

I'm new to C and still trying to grasp the concept of pointers. I know how to write a swap function that works...I'm more concerned as to why this particular one doesn't.
void swap(int* a, int* b)
{
int* temp = a;
a = b;
b = temp;
}
int main()
{
int x = 5, y = 10;
int *a = &x, *b = &y;
swap(a, b);
printf(ā€œ%d %d\nā€), *a, *b);
}
You're missing *s in the swap function. Try:
void swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
That way, instead of just swapping the pointers, you're swapping the ints that the pointers are pointing to.
Your swap() function does work, after a fashion - it swaps the values of the variables a and b that are local to swap(). Unfortunately, those are distinct from the a and b in main() - so you don't actually see any effect from swapping them.
When thinking about pointers, you need to be clear on a few abstractions.
An object in memory. This can be of any type (and size). An integer object, for example, will occupy 4 bytes in memory (on 32 bit machines). A pointer object will occupy 4 bytes in memory (on 32 bit machines). As should be obvious, the integer object holds integer values; a pointer object holds addresses of other objects.
The C programming language lets symbols (variables) represent these objects in memory. When you declare,
int i;
the symbol (variable) i represents some integer object in memory. More specifically, it represents the value of this object. You can manipulate this value by using i in the program.
&i will give you the address of this object in memory.
A pointer object can hold the address of another object. You declare a pointer object by using the syntax,
int* ptr;
Just like other variables, the pointer variable represents the value of an object, a pointer object. This value just happens to be an address of some other object. You set the value of a pointer object like so,
ptr = &i;
Now, when you say ptr in the program, you are referring to its value, which is the address of i. But if you say *ptr, you are referring to not the value of ptr, but rather the value of the object whose address is in ptr i.e. i.
The problem with your swap function is that you are swapping values of pointers, not the values of objects that these pointers hold addresses for. To get to the values of objects, you would have to use *ptr.
C is a pass-by-value language. Your swap routine doesn't dereference the pointers passed to it, so from main's perspective nothing has happened.
The pointers are passed by value. This means a & b are still a and b when the come back from the function;
try something like this
void swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
The right way to do it:
void swap(int* a, int* b)
{
int temp = *a; // Temp is set to the value stored at a (5)
*a = *b; // value stored at a is changed to the value stored at b (10)
*b = temp; // value stored in address b is changed to 5.
}
It does swap. It swaps local pointers a and b inside swap function. It swaps them perfectly fine, as it should.
If you want to swap the values these pointers are pointing to, you should re-implement your swap function accordingly, i.e. make it swap the pointed values, not the pointers.
Umm maybe using this
void swap(int** a, int** b)
{
int** temp = a;
a = b;
b = temp;
}
int main()
{
int x = 5, y = 10;
int *a = &x, *b = &y;
swap(&a, &b);
printf(ā€œ%d %d\nā€), *a, *b);
}
Without using a third variable (temp)
void swap(int* a,int* b)
{
// a = 10, b = 5;
*a = *a + *b; // a now becomes 15
*b = *a - *b; // b becomes 10
*a = *a - *b; // a becomes 5
}
zildjohn1's answer is the easiest and clearest way to do it. However if you insist on swapping the pointers, then you have to pass the pointer to the pointer because the pointer itself is passed by value.
You need to send the address of a and b for swap function so while calling swap function you must call ass swap (&a,&b)
So that you pass the address, and alter the address
#define SWAP(a,b) ((a)=(b)+(a),(b)=(a)-(b),(a)=(a)-(b))
Works good.

Resources