I was testing the linked list examples in the "Mastering Algorithms with C (By Kyle Loudon)"
In the example, there was an error in the operation of the function using the void** parameter. The operation error is as below code.
code:
#include <stdio.h>
void myswap(void **val1, void **val2)
{
void **val3;
*val3 = *val1;
*val1 = *val2;
*val2 = *val3;
}
int main()
{
int val1 = 10;
int val2 = 20;
printf("%d, %d\n", val1, val2);
myswap((void **)&val1, (void **)&val2);
printf("%d, %d\n", val1, val2);
return 0;
}
result:
10, 20
0, 10 <- must be 20, 10
This seems to be an error caused by the difference between the size of the variable and the size of the pointer. This can be solved by using a long variable instead of an int variable or by creating a padding variable between the two variables in main(). (I use a 64bit system. So, the size of pointers and long types is 64 bits.)
However, I want to know how to solve it without modifying the variables, structures, and functions of the already written examples. if it is possible.
If anyone knows about this issue, please help
Built with gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
, your myswap
function throws a segmentation fault when dereferencing val3
that is not initialized (cf. *val3 = *val1
statement).
If myswap
's goal is to make val1
points on what val2
pointed to (and the opposite), then the code should be:
void myswap(void **val1, void **val2)
{
void *tmp;
tmp = *val1;
*val1 = *val2;
*val2 = tmp;
}
This way, your code prints the expected 10, 20
and 20, 10
messages.
However, it still ends with a "*** stack smashing detected ***: terminated
" and abort (core dumped)
error messages.
This is due to the wrong way of passing val1
and val2
arguments to myswap
function.
The myswap
function considers val1
(resp. val2
) as a double pointer variable, something that point to a void *
address (itself pointing to something else).
In the main
context, &val1
is something that points to an int
variable, and not a void *
content!
So when myswap
runs a *val1 = ...
operation, it gets problematic if sizeof(int)
and sizeof(void*)
are different (which is the case on x86_64 architecture).
So, there are 3 things you could do:
intptr_t
(from stddint.h
) instead of int
, because intptr_t
has the same size as void *
.
int main()
{
intptr_t val1 = 10;
intptr_t val2 = 20;
printf("%ld, %ld\n", (signed long)val1, (signed long)val2);
myswap((void **)&val1, (void **)&val2);
printf("%ld, %ld\n", (signed long)val1, (signed long)val2);
return 0;
}
But this won't work for non-integer variables (i.e. struct
, float
...), where you cannot guarantee that variable size is the same as void *
int main()
{
int val1 = 10;
int val2 = 20;
int * ptr1 = &val1;
int * ptr2 = &val2;
printf("%d, %d\n", *ptr1, *ptr2);
myswap((void **)&ptr1, (void **)&ptr2);
printf("%d, %d\n", *ptr1, *ptr2);
return 0;
}
But this keep val1
and val2
variables unchanged, which might not be what you want.memcpy
and sizeof
, as @0___________ is suggesting.