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.
Related
Is this a correct way to define array of pointers to array in C programming language?
int* ptr[2];
int n1[5] = { 2,3,4,5,6 };
int n2[5] = { 2,3,4,5,6 };
ptr[0] = &n1;
ptr[1] = &n2;
I am getting errors like:
epi_2.c:20:12: warning: incompatible pointer types assigning to 'int *' from 'int (*)[5]' [-Wincompatible-pointer-types]
ptr[1] = &n2;
You have to write
ptr[0] = n1;
ptr[1] = n2;
Array designators used in expressions with rare exceptions are converted to pointers to their first elements.
That is in the above statements expressions n1 and n2 have the type int * - the type of the left side expressions.
As for these statements
ptr[0] = &n1;
ptr[1] = &n2;
then the right side expressions have the type int ( * )[5] that is not compatible with the type int * of the left side expressions. So the compiler issues messages.
Otherwise you need to declare the array of pointers like
int ( * ptr[2] )[5];
//...
ptr[0] = &n1;
ptr[1] = &n2;
Here is a demonstration program.
#include <stdio.h>
int main( void )
{
int* ptr[2];
int n1[5] = { 2,3,4,5,6 };
int n2[5] = { 2,3,4,5,6 };
ptr[0] = n1;
ptr[1] = n2;
for ( size_t i = 0; i < 2; ++i )
{
for ( size_t j = 0; j < 5; j++ )
{
printf( "%d ", ptr[i][j] );
}
putchar( '\n' );
}
}
The program output is
2 3 4 5 6
2 3 4 5 6
And here is another demonstration program.
#include <stdio.h>
int main( void )
{
int ( * ptr[2] )[5];
int n1[5] = { 2,3,4,5,6 };
int n2[5] = { 2,3,4,5,6 };
ptr[0] = &n1;
ptr[1] = &n2;
for ( size_t i = 0; i < 2; ++i )
{
for ( size_t j = 0; j < 5; j++ )
{
printf( "%d ", ( *ptr[i] )[j] );
}
putchar( '\n' );
}
}
The program output is the same as shown above
2 3 4 5 6
2 3 4 5 6
Is this a correct way to define array of pointers to array?
&n1 does return a pointer to an array.
But ptr[0] is not a pointer to an array. It's a pointer to an int.
You have two options.
Change ptr[0] to be a pointer to an array
By using the following, ptr becomes an array of pointers to arrays of 5 ints.
int ( *ptr[2] )[5] = { &n1, &n2 };
Change &1n to something that returns a pointer to int
But we rarely deal with pointer to arrays. We usually work with pointers to the first element of the array.
int *ptr[2] = { &( n1[0] ), &( n2[0] ) };
Because an array degenerates into a pointer to its first element, the following is equivalent but shorter:
int *ptr[2] = { n1, n2 };
In both cases, you end up with a pointer to the same address. But the type of the pointer is different. About the only difference is that sizeof( *ptr[0] ) will vary.
#include <stdio.h>
int main( void ) {
int ( *ptrA[2] )[5];
int *ptrB[2];
printf( "%zu\n", sizeof( *ptrA[0] ) ); // 20, size of array of 5 `int`.
printf( "%zu\n", sizeof( *ptrB[0] ) ); // 4, size of one `int`.
}
In C, there are two kinds of pointers to arrays:
Pointers that point to the first element of the array.
Pointers that point to the array as a whole.
If you have an array
int arr[5] = { 2,3,4,5,6 };
then you can create a pointer to the first element of the array the following way:
int *ptr = arr;
In the line above, the expression arr will automatically decay to &arr[0], i.e. to a pointer to the first element of the array.
You can create a pointer to the array as a whole the following way:
int (*ptr)[5] = &arr;
In C, it is more common to use the first kind of pointer. However, which kind of pointer you want depends on the situation.
For example, do you want sizeof *ptr to evaluate to the size of the entire array? Or do you want that expression to evaluate to the size of a single element of the array?
Also, how do you want ptr++ to behave? Do you want the pointer jump to the next element of the array? Or do you want the pointer to jump over the entire array (for example because you are using an array of arrays and want to jump to the next element of the outer array)?
If you want sizeof *ptr to evaluate to the size of a single element and want ptr++ to jump to the next element of the array, then you want the first kind of pointer. However, if you want sizeof *ptr to evaluate to the size of the entire array and want ptr++ to jump over the entire array, then you want the second kind of pointer.
If in doubt, I recommend that you chose the first kind of pointer, because that kind of pointer is easier to handle and more common.
Once you have decided which kind of pointer you want, you can then create an array of these pointers.
If you want an array of the first kind of pointer, then you can define that array like this:
int *ptrs[2];
ptrs[0] = n1;
ptrs[1] = n2;
If you instead want an array of the second kind of pointer, then you can define that array like this:
int (*ptrs[2])[5];
ptrs[0] = &n1;
ptrs[1] = &n2;
I got this code:
#include <stdio.h>
#include <string.h>
int main(void)
{
int a[3]={1,2,3},
b[3];
int (*p)[3]= &a;
b = p;
for(int i=0;i<3;i++)
printf("%i",b[i]);
}
-I wanted output to be like "123", but I am having problems assigning the b array to what the p is pointing.
ps -
memcpy( b, p, sizeof(b)); does just what i want but i want to do it without the use of that function.
The line
b = p;
has a couple of problems. First of all, array expressions may not be the target of the = operator; you can't assign an entire array in a single operation like that1.
Secondly, the types don't match; p has type int (*)[3], while b has type int [3]. Arrays are not pointers - array expressions "decay" to pointer expressions under most circumstances, but in this case even the pointers would be of incompatible types (b would decay to an expression of type int *, not int (*)[3]).
No, the only ways to copy the contents of one array to the other are to use library functions like memcpy or to use a loop to assign each element individually:
for ( size_t i = 0; i < 3; i++ )
b[i] = (*p)[i]; // or b[i] = a[i]
That's it.
Initialization is different from assignment.
Arrays do not have the assignment operator. You need somehow to copy elements of one array to another array.
Without using the standard function memcpy you can use an ordinary loop as for example
for ( size_t i = 0; i < sizeof( a ) / sizeof( *a ); i++ )
{
b[i] = a[i];
}
Or if to use intermediate pointers you can write
for ( int *p = a, *q = b; p != a + sizeof( a ) / sizeof( *a ); ++p )
{
*q++ = *p;
}
You have a small fixed size array, perfectly suitable for wrapping inside a struct, so you can do this:
#include <stdio.h>
#include <string.h>
struct ia3 {
int data[3];
}
int main(void)
{
struct ia3 a = {{1,2,3}};
struct ia3 b;
struct ia3 *p = &a;
b = *p; // struct assignment
for(int i=0;i<3;i++) {
printf("%i",b.data[i]);
}
}
"...but i want to do it without the use of [memcpy(,,)]."
It is unclear why using memcpy() is not agreeable in this exercise, but it does do the task more efficiently then loop for large array sizes.
If you just want a pointer to the array...
int a[3] = {1,2,3};
//create pointer
int *b = a;//does not copy array a, just points to it
//If an additional array is needed, do this...
int b[3] = {0};
int i = 0;
//to copy, without memcpy(), use this alternative.
for(i=0; i<3; i++) b[i] = a[i];//makes copy of array a
for(i=0;i<3;i++)
printf("%i", b[i]);
I am trying to print a 2-D array in C by using pointers but I am not getting the expected output.
Program:-
#include <stdio.h>
int main()
{
int arr[2][3] = {{1,2,3},{4,5,6}};
int* p;
for ( p = arr; p <= arr+6; p++)
{
printf("%d ", *p);
}
return 0;
}
Output:-
1 2 3 4 5 6 -1116112128 1587637938 0 0 1893963109 32521 -1453950296 32766 -1453805568 1 800797033 21984 -1453949463
Could you tell me where I am wrong as the output should only be:
1 2 3 4 5 6
Could you tell me where I am wrong
The elements of arr are not integers, but arrays of 3 integers. So arr+6 is surely a different address than what you expect, since pointer arithmetic works in multiples of the size of the type in the array.
You'll always be better off using nested loops to iterate over a multidimensional array; treating it as one single-dimensional array of int leads to exactly the kinds of confusion you see here. The code is harder to understand and verify, it won't be any slower.
First, when looping through arrays of size n wth an index i, the condition for continuation should be i < n rather than i <= n, because array indexes in C run from 0 through n-1.
However, your code has a more serious error: 1-dimensional arrays can be 'decayed' into pointers to the elements' type; however, 2-dimensional arrays decay into pointers to 1-dimensional arrays. So, in your case, the type of the pointer used in the arr + 6 expression is a pointer to an array of three integers; further, when the 6 is added, that operation is performed in terms of the size of the pointed-to object, which is sizeof(int) * 3 – so, even when changing the <= to <, you will be running far beyond the actual bounds of the array.
To make the pointer arithmetic work in the correct 'units' (i.e. sizeof(int)), cast the arr to an int* before the addition (and also change the <= to <):
#include <stdio.h>
int main()
{
int arr[2][3] = { {1,2,3},{4,5,6} };
int* p;
for (p = (int*)arr; p < (int*)arr + 6; p++) {
printf("%d ", *p);
}
return 0;
}
You are trying to access the value in the wrong way, The two-dimensional array is saved as a continuous block in the memory. So, if we increment the value of ptr by 1 we will move to the next block in the allocated memory.
int arr[2][3] = {{1,2,3},{4,5,6}};
int *ptr = arr;
int i,j;
for (i = 0; i < 6; i++) {
printf("%d ", *(ptr + i));
}
return 0;
Array designators used in expressions with rare exceptions are implicitly converted to pointers to their first elements.
The type of the array elements of this array
int arr[2][3];
is int [3]. So a pointer to the first element of the array has the type int ( * )[3].
This assignment
p = arr;
where p has the type int * is incorrect because the operands of the assignment have incompatible pointer types.
At least you need to cast the right expression to the type int * like
p = ( int * )arr;
The same casting you need to use in the condition in the for loop. That is instead of
p <= arr+6
you have to write
p < ( int * )arr+6
Below there is a demonstration program that shows how to output a two-dimensional array as a two-dimensional array using pointers.
#include <stdio.h>
int main( void )
{
int arr[2][3] = {{1,2,3},{4,5,6}};
for ( int ( *p )[3] = arr; p != arr + 2; p++ )
{
for ( int *q = *p; q != *p + 3; ++q )
{
printf( "%d ", *q );
}
putchar( '\n' );
}
return 0;
}
If you want to output the two-dimensional array as a one-dimensional array then you can write
#include <stdio.h>
int main( void )
{
int arr[2][3] = {{1,2,3},{4,5,6}};
for ( int *p = ( int * )arr; p != ( int * )arr + 6; p++ )
{
printf( "%d ", *p );
}
putchar( '\n' );
return 0;
}
In
for ( p = arr; p <= arr+6; p++)
the expression arr, as an rvalue, is a pointer to the first element of the array (which is of type int [3], so each time you increment that pointer, it moves three int positions forward ---a whole row---, and so, arr + 6 points just after the sixth row of the array (if the array should ever had six rows) You can do it (with the proper explicit pointer conversions, as you are mixing pointers to int with pointers to int [3]) with the expression arr + 2 which is the addres of the first array element after the second row (and the number of rows of the array).
You can do it also declaring
int (*aux)[2][3] = &arr; /* aux is a pointer to the whole 3x2 array,
* so aux + 1 will be the position of the second
* 2D array after this one */
and then
int *end = (int *)(aux + 1);
or simply
int *end = (int *)(&arr + 1); /* see below */
(Beware that arr and &arr are both pointers and point to the same place, but they are not the same type (arr is of type int (*)[3] and &arr is of type int(*)[2][3])
So let's rewrite your code as
for (p = (int *)arr; p < end; p++)
or
for (p = (int *)arr; p < (int *)&arr + 1; p++)
would work, which seems more natural to do the calculus in complete array units than in rows or single cells (and you can change freely the dimensions of the array)
Your code would be:
#include <stdio.h>
int main()
{
int arr[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
int *end = (int *)(&arr + 1); /* try to avoid evaluating this expression in the loop
* despite that it can be optimized to comparing
* with a constant value */
char *sep = "";
for (int *p = (int *)arr; p < end; p++)
{
printf("%s%d", sep, *p);
sep = ", ";
}
putchar('\n');
return 0;
}
(Beware that you have to use < operator and not <= as you don't want to print the value pointed by end, because it lies one place outside of the array)
Finally a note: this will work with true arrays, but not with function parameters declared as arrays, because they decay to pointers and then &arr is not a pointer to data the size of the array, but it is the address of the parameter itself, which points to the array somewhere else.
I need to swap the values of 2 arrays in a function. The problem is I can change anything in the main, just the function itself. It should recive 2 integer arrays, and swap those. The problem is, that I don't know the size of the arrays, and for my understading they can even be in diffrent sizes. Trying this code:
int main()
{
int size = 4; //Please notice that I'm using this only to print the array
int a[] = {1,2,3,4};
int b[] = {5,6,7,8};
printArr(a,"a",size);
printArr(b,"b",size);
swapArray(a,b);
printf("Swapped:\n");
printArr(a,"a",size);
printArr(b,"b",size);
}
and this function:
void swapArray(int **a,int **b)
{
int *p = *a;
*a = *b;
*b = p;
}
while printArr simply prints the array:
void printArr(int arr[],char name[],int size)
{
printf("%s:\t",name);
for(int i=0;i<size;i++){
printf("%d\t",arr[i]);
}
printf("\n");
}
I got a really weird result:
a: 1 2 3 4
b: 5 6 7 8
Swapped:
a: 5 6 3 4
b: 1 2 7 8
I would like to understand why it happens, and not only a working solution.
Thank you :)
In this call
swapArray(a,b);
the argument expressions have the type int * while the function parameters have the type int **. There is no implicit conversion from the type int * to the type int **. So the compiler shall issue a diagnostic message.
In any case the swap function as it is implemented does not make sense. Your program has undefined behavior at least because it tries to swap pointers instead of the arrays themselves.
Take into account that arrays are not pointers though in expressions with rare exceptions they indeed are implicitly converted to pointers to their first elements.
To swap elements of two arrays you have to swap each pair of elemenets separatly.
And you have to supply the number of elements in the arrays. Otherwise the arrays need to have a sentinel value.
Here is a demonstrative program that shows how the function swap can be defined.
#include <stdio.h>
void printArr( const int a[], size_t n, const char *s )
{
printf( "%s:\t", s );
for ( size_t i = 0; i < n; i++ )
{
printf( "%d ", a[i] );
}
putchar( '\n' );
}
void swapArray( int *a, int *b, size_t n )
{
for ( size_t i = 0; i < n; i++ )
{
int tmp = a[i];
a[i] = b[i];
b[i] = tmp;
}
}
int main(void)
{
enum { N = 4 };
int a[N] = { 1, 2, 3, 4 };
int b[N] = { 5, 6, 7, 8 };
printArr( a, N, "a" );
printArr( b, N, "b" );
putchar( '\n' );
swapArray( a, b, N );
printArr( a, N, "a" );
printArr( b, N, "b" );
putchar( '\n' );
return 0;
}
Its output is
a: 1 2 3 4
b: 5 6 7 8
a: 5 6 7 8
b: 1 2 3 4
You could swap visual representations of original arrays using pointers. But in this case the arrays themselves will not be swapped.
Consider the following program.
#include <stdio.h>
void printArr( const int a[], size_t n, const char *s )
{
printf( "%s:\t", s );
for ( size_t i = 0; i < n; i++ )
{
printf( "%d ", a[i] );
}
putchar( '\n' );
}
void swapArray( int **a, int **b )
{
int *tmp = *a;
*a = *b;
*b = tmp;
}
int main(void)
{
enum { N = 4 };
int a[N] = { 1, 2, 3, 4 };
int b[N] = { 5, 6, 7, 8 };
printArr( a, N, "a" );
printArr( b, N, "b" );
putchar( '\n' );
int *pa = a;
int *pb = b;
swapArray( &pa, &pb );
printArr( pa, N, "pa" );
printArr( pb, N, "pb" );
putchar( '\n' );
printArr( a, N, "a" );
printArr( b, N, "b" );
putchar( '\n' );
return 0;
}
Its output is
a: 1 2 3 4
b: 5 6 7 8
pa: 5 6 7 8
pb: 1 2 3 4
a: 1 2 3 4
b: 5 6 7 8
As you see the arrays were not swapped. However the pointers that point to first elements of the arrays were swapped. Using the pointers you can simulate swapping of arrays.
Opposite to C C++ has a template function std::swap for arrays that can be called indeed simply like
std::swap( a, b );
I guess on your platform the size of the pointer is 64 bit, and the size of an in is 32 bit.
When calling swapArray, the compiler implicitly reinterprets your arrays of int as an array of pointers. (These are pointers to int but this is irrelevant here).
swapArray then just swaps the first element of these pointer arrays.
Luckily your original int arrays are large enough so that no illegal access happens.
Since pointer is 64 bit is corresponds to two int which get swapped.
In C an array is not a single "thing" you can swap. You will need to swap it element-by-element.
The only case in which you can swap these array "things" in one time is if they are pointers to arrays.
int *a = malloc(n*sizeof(int));
int *b = malloc(n*sizeof(int));
int *tmp;
tmp=a; a=b; b=tmp;
The problem is, that I don't know the size of the arrays, and for my
understading they can even be in diffrent sizes.
Then let's do it with different sizes! But I don't want to support a "C&P behaviour" and hence I won't provide a complete program. I just provide some short cuts and explain them.
As already shown in the other answers you need to specify the size of an array x[] if you pass it to a function like e.g. swapArray().
But in your main() you are statically defining your two arrays. Let me do it this way:
int a[] = { 1, 2, 3 };
int b[] = { 5, 6, 7, 8, 9 };
Here we defined two arrays statically with different sizes. But the sizes are known. The compiler knows them at build/compile time. There's a build time operator sizeof() which returns the size of a type or a variable at compile time. Hence we can use sizeof(a) to get the size of array a.
But there's one light issue: The "unit" returned by sizeof() is bytes and not elements. Hence we must divide it by the size of the type (here: int) to get the actual number of elements in the array:
size_t size_a = sizeof(a) / sizeof(int);
(Actually this means that for e.g. size_a it will end up with 12 / 4 which will actually write a 3 as a pre-calculated value in your compiled program. I assume here that int takes up 4 bytes.)
For your swapping function you must pass the lower value of both size_a and size_b. We can simply get the minimum value with this:
size_t size_min = (size_a < size_b) ? size_a : size_b;
In case that size_a is smaller then size_a is taken. Otherwise size_b. This is calculated at run time. (If you want to do this at build time because of static values then you need to use preprocessor directives.)
Calling printArr() is straight forward, just pass the correct size:
printArr(b,"b",size_b);
And for swap we use size_min:
swapArray(a, b, size_min);
That's it for handling arrays with different sizes.
A very simple swapArray() could look like this:
void swapArray(int a[],int b[], size_t size) { // or int *a, int *b...
while (size > 0) {
size--;
int tmp = a[size];
a[size] = b[size];
b[size] = tmp;
}
}
We don't need to define an additional loop variable because we can simply use size and decrease it until it reaches 0.
I would like to swap two variables containing 2D arrays. I believe this can be simply done by swapping their pointers. I tried this code, but it does not work and I have no idea why, perhaps I am not understanding pointers correctly.
#include <stdio.h>
void swap(int ***a, int ***b) {
int ** temp = *a;
*a = *b;
*b = temp;
}
int main(void) {
int a[10][10];
int b[10][10];
a[1][5] = 4;
b[1][5] = 2;
printf("%d, %d\n", a[1][5], b[1][5]);
swap(&b, &a);
printf("%d, %d\n", a[1][5], b[1][5]);
return 0;
}
This outputs
4, 2
4, 2
I would expect it to output
4, 2
2, 4
So, what am I doing wrong?
a and b in main function are not pointers but arrays.
If you want to use pointers, use pointers.
#include <stdio.h>
#define N 10
void swap(int (**a)[N][N], int (**b)[N][N]) {
int (*temp)[N][N] = *a;
*a = *b;
*b = temp;
}
int main(void) {
int a[N][N];
int b[N][N];
int (*pa)[N][N] = &a;
int (*pb)[N][N] = &b;
(*pa)[1][5] = 4;
(*pb)[1][5] = 2;
printf("%d, %d\n", (*pa)[1][5], (*pb)[1][5]);
swap(&pb, &pa);
printf("%d, %d\n", (*pa)[1][5], (*pb)[1][5]);
return 0;
}
This would not work because what you are swapping is actually what the variables in the swap() function are pointing to, and not what they are pointing at. Its like if a was pointing at 5 and b was pointing at 6 in the swap() function, then it will make a point at 6 and b point at 5, without changing the contents of the memory. This would mean the in the main() function they would be residing at the same place and would be getting pointed by the same variable a and b (different from the variable in swap())
To swap you need to swap the contents of that memory in the swap() function, so that it is reflected in the main() function.
Recall that while doing swapping using pointers, one sends the address and actually swaps the content by dereferencing (*p and *q).