6

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

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Dr.Java
  • 73
  • 1
  • 1
  • 5
  • 5
    If you enable compiler warnings then you will get some very helpful information from the compiler about what you are doing wrong, particularly in regard to your call to `swapArray` (which I am surprised even compiles). – Paul R Apr 10 '18 at 10:38
  • 1
    Are you sure that you read the assignment correctly? Swapping hardwired arrays like that doesn't even make sense, though swapping pointers (which could be functioning as pointers to arrays) does. – John Coleman Apr 10 '18 at 11:36

4 Answers4

6

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 );
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
4

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.

Andreas H.
  • 5,557
  • 23
  • 32
4

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;
Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
  • Thank you very much. Unfortunetly, I couldn't use malloc. The assigment was incorrect from the first place, but at least I learned a lot during the process. – Dr.Java Apr 11 '18 at 17:54
1

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.

reichhart
  • 813
  • 7
  • 13