Related
I was trying to swap two arrays using pointers.
What I wanted was to swap using a call by reference.
This code I wrote is given below
#include <stdio.h>
#include <stdlib.h>
void swap(int **a, int **b) {
int *temp = (int*)malloc(5*sizeof(int));
temp = *a;
*a = *b;
*b = temp;
}
int main() {
int arr1[] = {1, 2, 3, 4, 5};
int arr2[] = {6, 7, 8, 9, 10};
swap((int**)&arr1, (int**)&arr2);
for(int i=0; i<5; i++) printf("%d\t", arr1[i]);
printf("\n");
for(int i=0; i<5; i++) printf("%d\t", arr2[i]);
printf("\n");
}
The output of the code is:
6 7 3 4 5
1 2 8 9 10
instead of:
6 7 8 9 10
1 2 3 4 5
What did I do wrong?
In this call
swap((int**)&arr1, (int**)&arr2);
the passed pointers point to first elements of the arrays arr1 and arr2.
So within the function swap
void swap(int **a, int **b) {
int *temp = (int*)malloc(5*sizeof(int));
temp = *a;
*a = *b;
*b = temp;
}
dereferencing the pointers like for example
*a
results in reading the first two elements of the array arr1 as a pointer because in your system sizeof( int * ) is equal to 2 * sizeof( int ).
That is values of first two elements of the arrays are interpreted as values of pointers.
And the obtained output confirms that
6 7 3 4 5
1 2 8 9 10
^^^^^
Moreover the function has a memory leak because at first memory was allocated dynamically and its address was assigned to the pointer temp and then the pointer was reassigned
int *temp = (int*)malloc(5*sizeof(int));
temp = *a;
So the address of the allocated memory was lost and the memory was not freed.
You can not swap arrays such a way. You need to swap each pair of elements of the arrays.
The function can look for example the following way
void swap( int *a, int *b, size_t n )
{
for ( int *p = a; p != a + n; ++p, ++b )
{
int temp = *p;
*p = *b;
*b = temp;
}
}
And the function is called like
swap( arr1, arr2, 5 );
A less flexible function can look the following way
void swap( int ( *a )[5], int ( *b )[5] )
{
for ( int *p1 = *a, *p2 = *b; p1 != *a + 5; ++p1, ++p2 )
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
}
And the function is called like
swap( &arr1, &arr2 );
First of all lets fix your swap function:
void swap(int **pparr1, int **pparr2)
{
int *temp = *pparr1;
*pparr1 = *pparr2;
*pparr2 = temp;
}
This function now swaps the two pointers that parr1 and parr2 are pointing to.
Then lest update the way to call this function:
int *parr1 = arr1; // Make parr1 point to the first element of arr1
int *parr2 = arr2; // Make parr2 point to the first element of arr2
// Swap the two pointers
swap(&parr1, &parr2);
And then we print using the pointers instead of the arrays:
printf("arr1 = [ ");
for (unsigned i = 0; i < 5; ++i)
{
printf("%d ", parr1[i]);
}
printf("]\n");
printf("arr2 = [ ");
for (unsigned i = 0; i < 5; ++i)
{
printf("%d ", parr2[i]);
}
printf("]\n");
This will print the arrays as if they were swapped, but in fact the arrays themselves are not swapped. You can verify by printing using the arrays arr1 and arr2 themselves.
If you want to swap the actual contents of the arrays, you need a loop to actually swap the elements themselves:
// Function to swap two integer values
void swap(int *p1, int *p2)
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
// Function to swap two arrays
void swap_arrays(int *pa1, int *pa2, size_t size)
{
for (size_t i = 0; i < size; ++i)
{
// Swap each separate element of the arrays
swap(&pa1[i], &pa2[i]);
}
}
Call like
swap_arrays(arr1, arr2, 5);
After this the contents of the arrays themselves have been swapped.
swap((int**)&arr1, (int**)&arr2);
It looks like your idea is to have swap swap the address of arr1 with the address of arr2. Variables in C, including arrays, do not work this way, and this idea cannot possibly work.
arr1 is a name for the array. It is not the address of the array, nor is it a variable whose value is the address of the array. There is no pointer to the array that can be swapped with a pointer to the array arr2.
When the compiler processes int arr1[] = {1, 2, 3, 4, 5};, it creates an array of five int, and then it uses arr1 to refer to that array. Wherever arr1 is used, the compiler creates code that will refer to the array. It does not do this by storing the address of the array in some memory location you can swap with another address. It has ways to access the array using registers and processor instructions set up for that.
In swap((int**)&arr1, (int**)&arr2);, you take the addresses of arr1 and arr2 and convert them to int **. The address of arr1 is the address where its contents are. What is at that address in memory is the int elements, not a pointer. So the int ** type does not make sense for this; the address of arr1 is not the address of an int *.
The reason you get the output you do is that int objects are four bytes in your C implementation and int * objects are eight bytes. So when temp = *a; attempts to get the int * that a should be pointing to, it gets the first eight bytes in arr1. Then *a = *b; replaces those eight bytes with the first eight bytes in arr2. And *b = temp; replaces the first eight bytes in arr2 with the saved eight bytes from arr1.
Note that, in these three statements, temp is used to hold eight bytes from arr1. The value it was given in int *temp = (int*)malloc(5*sizeof(int)); is lost when temp is assigned another value in temp = *a;.
Also note that this behavior you observed in this instance is not specified by the C standard, and different behavior can result in other circumstances, including alignment errors and surprising transformations of the program by compiler optimization.
You cannot assign whole arrays to each other in a single operation using =; you must either use a library function like memcpy or assign each element individually.
Under most circumstances, expressions of type "N-element array of T" will be converted, or "decay", to expressions of type "pointer to T" and the value will be a pointer to the first element. If you called the function as
swap( arr1, arr2 );
it would be equivalent to writing
swap( &arr1[0], &arr2[0] );
So you're already passing the arrays "by reference", just not in the way you're probably thinking.
The easiest way to do what you want would be something like this:
void swap( int *a, int *b, size_t count )
{
for ( size_t i = 0; i < count; i++ )
{
int tmp = a[i];
a[i] = b[i];
b[i] = tmp;
}
}
Alternately, you could use memcpy with a temporary array:
void swap( int *a, int *b, size_t count )
{
int tmp[count]; // C99 or later
memcpy( tmp, a, count );
memcpy( a, b, count );
memcpy( b, tmp, count );
}
In this case tmp is a variable-length array, whose size is provided by a runtime value. VLAs are useful for things like this if the array size isn't too big, but they're only available for C99 and later, and are optional after C2011. If your arrays are very large or VLAs aren't available, then this would be a case for dynamic memory:
void swap( int *a, int *b, size_t count )
{
int *tmp = calloc( count, sizeof *tmp );
if ( tmp )
{
memcpy( tmp, a, count );
memcpy( a, b, count );
memcpy( b, tmp, count );
free( tmp );
}
}
The first method (swapping each element individually) would be my preference. It avoids any kind of dynamic memory management, it's straightforward, it's not making a bunch of library calls, etc.
In all three cases, you'd call it as
swap( arr1, arr2, 5 );
Beware explicit casts, especially pointer casts - they're usually a sign you're doing something wrong.
#include<stdio.h>
void swap(int *a,int *b){
int p=*b;
*b=*a;
*a=p;
/*int *p=b;
b=a;
a=p;
*/
}
int main(){
int a,b;
scanf("%d %d",&a,&b);
swap(&a,&b);
printf("%d %d",a,b);
}
Above is the code.
If I put 3 5 as an input, then it should swap its values, and 5 3 should come out as an output.
I got my answer by trying int p=*b thing
However I also tried commented part, but it didn't work.
So, I checked their address in swap and in main.
In swap int *a and int *b their address changed
However, when I came back to main, a and b 's addresses were not changed...
So first I thought: is it not changed in main because parameter int *a,int *b is local variable?
But I also learned that when pointers and arguments are used as arguments their value can change unlike other variables...
I really wonder why the second method(commented part) is not swapping the values...
If you want to change in a function original objects you have to pass them to the function by reference.
In C passing objects by reference means passing them indirectly through pointers that point to the original object.
Otherwise if you will pass the original objects themselves to the function the function will deal with copies of the objects. It is evident that changing copies does not influence on the original objects.
It is exactly what happens in this function
void swap(int *a,int *b){
int *p=b;
b=a;
a=p;
}
The function deals with copies of pointers passed to the function as argument in this call
swap(&a,&b);
That is the function indeed swapped values of the two pointers that are declared as its parameters. But they are not the original pointers passed to the function. They are copies of the pointers. So the values of the original pointers were not changed
The function swap in general can look the following way
void swap( T *a, T *b )
{
T tmp = *a;
*a = *b;
*b = tmp;
}
where T is same type specifier.
So if you want to swap objects of the type int then in the above function T will be int and the function will look like
void swap( int *a, int *b )
{
int tmp = *a;
*a = *b;
*b = tmp;
}
If you want to swap values of pointers of the type int * then T will be int * and the function will look like
void swap( int **a, int **b )
{
int *tmp = *a;
*a = *b;
*b = tmp;
}
Here is a demonstrative program.
#include <stdio.h>
void swap1( int *pa, int *pb )
{
int tmp = *pa;
*pa = *pb;
*pb = tmp;
}
void swap2( int **ppa, int **ppb )
{
int *tmp = *ppa;
*ppa = *ppb;
*ppb = tmp;
}
int main(void)
{
int a = 3, b = 5;
swap1( &a, &b );
printf( "a = %d b = %d\n", a, b );
// reset again the values of the variables
a = 3; b = 5;
int *pa = &a, *pb = &b;
swap2( &pa, &pb );
printf( "*pa = %d *pb = %d\n", *pa, *pb );
return 0;
}
Its output is
a = 5 b = 3
*pa = 5 *pb = 3
That is at first in the program two objects of the type int are swapped, So the imagined type specifier T is int.
Then two pointers that point to the objects a and b are swapped. So the imagined type specifier T int *.
After swapping the pointers the pointer pa now points to the object b and the pointer pb now points to the object a.
In the second method, you use the local variable that is limited in the scope of the function swap. So, the variable a or b in main function is different with variable a or b that is defined as the argument in the swap function.
When you use the pointer, the swap function will change the value that is pointed by the pointer (it means that the function change the value at the address of a and b that are declared in the main function).
Assuming you meant
void swap(int *a,int *b){
int *p=b;
b=a;
a=p;
}
That code just swaps the value of the pointers in the swap() function. That won't swap the addresses around in main() because, as you said, "parameter int *a,int *b is local variable".
When you call the function swap() like this
swap(&a,&b);
the addresses of a and b are passed and become local variables in the swap() function. You can't change the address of a or b - they have a location in memory.
In the code that works
void swap(int *a,int *b){
int p=*b;
*b=*a;
*a=p;
}
you don't change the value of the pointers, you change the values in the memory the pointers point to, which is why that works.
While C is pass-by-value, if you pass the address of something as the value a function can modify something outside its scope because you told the function where that variable is.
In C, all variables declared in a function are local to that specific function.
So, you wrote something in function swap
int *p=b;
What above code will do is, it will copy the value of b into p. So, when the function swap return, it's local variables p, b and a will vanished.
#include<stdio.h>
void fun(int **a,int **b)
{
int **k;
k=a;
a=b;
b=k;
}
int main()
{
int a=3,b=6,*x=&a,*y=&b;
fun(&x,&y);
printf("%d %d",a,b);
return 0;
}
I swap the address,why it still outputs 3 6.
So what's the correct way to swap the two address?
p = ... never persists across the function call. Like everything else in C, if you want to change the caller's data, dereference the pointers you're given. k should be int *, and the assignments should be int *k = *a; *a = *b; *b = k;. that's it. Note also this changes nothing about the original a and b. All your swapping at this point are pointer values.
This code swaps two integers
#include<stdio.h>
void fun(int *a,int *b)
{
int k = *a;
*a = *b;
*b = k;
}
int main()
{
int a=3,b=6;
printf("%d %d\n",a,b);
fun(&a,&b);
printf("%d %d\n",a,b);
return 0;
}
Output
3 6
6 3
Whereas, this code swaps two pointers. The integers they point to (a and b) remain as-is.
#include<stdio.h>
void fun(int **a,int **b)
{
int *k = *a;
*a = *b;
*b = k;
}
int main()
{
int a=3,b=6,*x=&a,*y=&b;
printf("%d %d\n",a,b);
printf("%d %d\n",*x,*y); // note using x and y with deref
fun(&x,&y);
printf("%d %d\n",a,b);
printf("%d %d\n",*x,*y); // note using x and y with deref
return 0;
}
Output
3 6
3 6
3 6
6 3
Lets make it clear from the first expression .
int a=3,b=6,*x=&a,*y=&b;
Now breaking it down .
int a = 3, b = 6
Here a and b are two memory locations . Say a is 10000000 and b is 10010000. So , after we write a = 3 , b = 6 the value 3 takes the place in memory location 10000000 and 6 in 10010000 . Now ,
*x=&a,*y=&b;
means , x is an integer pointer that has the address of integer variable a which is 10000000 and y has the address of b which is 10010000 . Note that , both x and y are also variable which can store the address as value of any integer variable . x and y has locations in memory let say 11000000 and 11011111. Now ,
fun(&x,&y);
You are passing the address of x and y to the function fun . It looks like fun(11000000, 11010000) .
Note that , you are not passing the address of a and b ! In function fun these addresses are in a ( pa for clarity ) and b (pb for clarity),
void fun(int **a,int **b)
{
int **k;
k = a;
a = b;
b = k;
}
Here , a(pa), b(pb) and k are pointers of pointer . They can hold the address of an integer pointer .a(pa) and b(pb) are holding the address of x and y respectively . Now when you swapping a(pa) and b(pb) you actually swapping the addresses ( of x and y ) in a(pa) and b(pb). So , after the function fun finishes it's execution a (pa) is pointing y and b(pb) is pointing x . In main function , nothing actually happened . When you do the following ,
void fun(int **a, int **b)
{
int *k;
k=*a;
*a = *b;
*b = k;
}
it swaps the address in x and y and they now pointing to b and a(in main function).
Now the final version comes ! If you would do the following , it actually make you happy ,
void fun(int **a, int **b)
{
int k;
k=**a;
**a = **b;
**b = k;
}
I hope you understand it . Happy coding !
Try this to swap the values to which *a and *b of fun() points
void fun(int **a, int **b)
{
int k;
k = **a;
**a = **b;
**b = k;
}
Instead of this:
int **k;
k=a;
a=b;
b=k;
you should have tried this:
int *k;
k=*a;
*a=*b;
*b=k;
And yeah, you should print *x and *y, because those are the variables you swap, not a and b.
I just started learning C and I was confused about why do I have to use pointers to implement a swap function?
Version where swap does not work:
#include <stdio.h>
void swap(int i, int j) {
int t = i;
i = j;
j = t;
}
int main() {
int a = 23, b = 47;
printf("Before. a: %d, b: %d\n", a, b);
swap(a,b);
printf("After. a: %d, b: %d\n", a, b);
return 0;
}
Version where swap works:
#include <stdio.h>
void swap(int *i, int *j) {
int t = *i;
*i = *j;
*j = t;
}
void main() {
int a = 23, b = 47;
printf("Before. a: %d, b: %d\n", a, b);
swap(&a, &b);
printf("After . a: %d, b: %d\n", a, b);
}
By default function arguments are passed by value in C and C++. This basically means a copy of the passed argument is received in the function. This copy is distinct from the passed variable and any change on this copy is not reflected back to the passed argument.
So your first snippet actually swaps copies of the passed arguments and not the arguments themselves.
For the swapping to be reflected back to the arguments being passed, You need to pass by reference, In C this is acheived by using pointers. Where the address of the arguments is passed to function and the function actually operates on the memory address passed to it, i.e: the original variable who's value is being passed.
swap(a,b);
void swap(int i, int j) {
int t = i;
i = j;
j = t;
}
The above code fails because, the variables i and j are local to the function swap , which means the variables have their scope limited to the function swap , and their life is lost once the function terminates.
One workaround is to use pass by address as shown in the code below...
swap(&a,&b);
void swap(int* i, int* j) {
int t = *i;
i* = *j;
j* = t;
}
Now the variables i and j, are pointers to original variables a and b , which means they are acting on behalf of a and b, and hence even if the pointers have limited scope within the function, they are able to indirectly modify variables a and b.
Why have you presented two programs back to back?Those are two separate programs.The first one ,despite all its fallacies about void main() and stuff, intends to(but doesn't,as it deals with local variables) swap values by using a function that is passed copies of the integer variables a and b.This is pass-by-value.In fact, C only has pass-by-value, despite what your book by Yeshwant Kanetkar says.Anyways, to make the first program work,use the printf() to display the swapped values inside swap() function itself,as being local variables the change in values won't show in main().
void swap(int i, int j) {
int t = i;
i = j;
j = t;
printf("After. a:%d,b:%d",i,j);
}
The second program, which he may claim uses pass-by-reference, is essentially pass-by-value where copies of the addresses of the variables are passed,not the actual addresses themselves.And again, despite it's non-portable eccentricities like void main(), it does swap the values of a and b.
void swap(int *i, int *j) {
int t = *i;
*i = *j;
*j = t;
}
Output Before. a:23 b:47
After. a:47 b:23
I ran it on CodeBlocks.But then your author Mr.Void Main must have suggested you to use 16-bit Turbo C eh?
You can not do swap this way:
void swap(int i, int j) {
int t = i;
i = j;
j = t;
}
because i and j are passed by value. That means that it is the same as local variable tmp. Thus, modifying of the i and j does not actually modify variables that you passed, as local copies of the i and j do not exist outside the function swap().
Because of it, if you need to modify i and j from main(), you have to pass to swap() addresses of i and j of the main().
That's why the following version is actually works.
void swap(int *i, int *j) {
int t = *i;
*i = *j;
*j = t;
}
EDIT: In order to understand these things better, I would like to recommend you Stanford Lectures Programming Paradigms, that are available at YouTube.
Complete C newb here. Trying to learn/understand pointers by messing with simple code fragments.
#include <stdio.h>
void swap(int *px, int *py)
{
int tmp;
tmp = *px;
*px = *py;
*py = tmp;
}
main()
{
int *a, *b;
*a = 1;
*b = 2;
swap(&a,&b);
printf("%d %d\n", *a, *b);
}
Why is this not valid? The code works when I remove the dereferencing operator * from main.
Conceptually, this seems like it should work. I initialize a and b as pointers which point to int 1 and int 2, respectively. I then send their addresses to swap(), which should switch what they point to.
There are a couple of problems. First, the pointers a and b are not pointing to valid memory. So the assignment of the integer values is undefined (possible crash). Secondly, the call to swap (assuming a and b are pointing to valid memory) should not include the address (it is currently sending the address of the pointer variable).
The following changes would make it work:
int a, b;
a = 1;
b = 2;
swap(&a,&b);
printf("%d %d\n", a, b);
The swap() function is OK but inside main you are taking the addresses of pointers, so you're passing int** arguments to int* parameters.
int *a, *b;
swap(&a,&b);
To fix it, replace the code in main() with :
int a = 1, b = 2;
swap(&a,&b);
printf("%d %d\n", a, b);
Pointers point to data. A pointer itself doesn't comprise memory for storage, it just points to existing memory. So when you declare int *a; , you just have a garbage pointer with no useable value, and you mustn't dereference it.
The only sensible way to use pointers is to assign them the address-of something (or the result of some allocation function):
int i;
int *a = &i; // now a points to i
Therefore, the right way to use your swap function is to pass it addresses of integers:
int i = 10;
int j = -2;
swap(&i, &j);
a and b are uninitialized pointers, dereferencing them induces undefined behavior. You want:
int main() {
int a, b;
a = 1;
b = 2;
swap(&a,&b);
printf("%d %d\n", a, b);
return 0;
}
Your method signature is wrong. You ask for two pointers to int, yet you pass in two pointers to pointers to int.
When you say, " I then send their addresses to swap(), which should switch what they point to." Are you trying to change the address values within the pointer variables in main, to switch which bit of memory they are pointing to? In that case you will need another step of redirection:
#include <stdio.h>
void swap(int **px, int **py) {
int *tmp;
tmp = *px;
*px = *py;
*py = tmp;
}
int main (void) {
int x, y; /* storage to point to */
int *a, *b;
a = &x;
b = &y;
*a = 1;
*b = 2;
printf("(*a, *b, x, y) == (%d, %d, %d, %d)\n", *a, *b, x, y);
swap(&a, &b);
printf("(*a, *b, x, y) == (%d, %d, %d, %d)\n", *a, *b, x, y);
}
$ ./a.out
(*a, *b, x, y) == (1, 2, 1, 2)
(*a, *b, x, y) == (2, 1, 1, 2)
The x & y values have not changed, but a was pointing to x and now points to y and vice versa for b.