0

So, I have an array containing 1 value. And then I copy(assign) it to another array. But, if I change the value on the second array, the value of first array got changed too. This is my code:

#include <stdio.h>

void change(int a[]){
    int *temp = a;
    for(int i=0; i<2; i++){
        a[i] = temp[0]*10+7;
    }
    //What I expect for the result is a[0] = 7, a[1] = 7 instead of a[0] = 7, a[1] = 77
}
int main(){
    int num[1];
    num[0] = 0;
    change(num);
    printf("%d", num[0]);
    return 0;
}

What happen to my array?

EDIT : I want to copy the value, not the address of array

EDIT 2: I have change a little bit of my code above to make it more clear what I want.

  • What do you consider to be 1st array and which the 2nd? – alk Dec 02 '18 at 11:26
  • The first array is num, and the second one is a. – Bernhard Josephus Dec 02 '18 at 11:32
  • @BernhardJosephus I do not think that changing the code is a good option to be honest. 1. The code has a bug (`num` is of size 1, but you access the second position) 2. It discourages people from answering - I suggest you revert it back in this case and add the new code under **EDIT 2** – Ely Dec 02 '18 at 16:20

6 Answers6

4

"But, if I change the value on the second array, the value of first array got changed too"

Array is not passed as copy (arrays not passed by values) - it is a pointer pointing to an address where the first element is in memory. Therefore, you are actually modifying the values (arrays passed by reference)

Be aware ! When passing an array as a parameter :

void func(int a[])

means exactly the same as :

void func(int *a)

Kobip
  • 114
  • 1
  • 8
  • So, how can I copy it? I need a copy of that array. – Bernhard Josephus Dec 02 '18 at 11:29
  • You are changing the first element in the passed array a[] by assigning a value to it in the change() - a[0] = temp[0]*10+7; What are you trying to do ? What is the purpose ? You can copy the a[] to a b[] in main and send the later one the function. – Kobip Dec 02 '18 at 11:33
  • It's just an example. I have another code that just similar to above with the same formula. So, I want that value of temp to be a new value(not the address of a), so when I want to use it again, the value of temp still like before. I have a looping inside the function that use temp twice with same value. – Bernhard Josephus Dec 02 '18 at 11:40
  • @BernhardJosephus: "*So, how can I copy it?*" this might be worth another question. – alk Dec 02 '18 at 11:41
  • The title is already consist of that question I though. Maybe I need to edit it? – Bernhard Josephus Dec 02 '18 at 11:44
0

In c arrays are passed by reference. Meaning you are not passing the value but the adress where the elements of array are stored.

When you assign value to a[0] in a function, you are actually updating the num array.

Mayank Kumar Chaudhari
  • 16,027
  • 10
  • 55
  • 122
0

When you use just an array's name to pass to a function, you actually create a temporary pointer to the first element of your array. So, your change() function receives as a copy of that temporary pointer the address of your num[] array in main.

The whole concept is called 'passing by reference'.

GermanNerd
  • 643
  • 5
  • 12
0

If you want to pass a copy of an array to a function in C, you may put the array into a struct and pass this struct by value, e.g.

struct s {
  int a[4];
};

void change(struct s elem)
{
   elem.a[0] = 1; //assigment to copy
}
0

First, this declaration

void change(int a[]);

is equivalent with this declaration

void change(int *a);

Second (see this link for more info),

The C language is pass-by-value without exception. Passing a pointer as a parameter does not mean pass-by-reference.

So you are passing a copy of the pointer's address (which points to the same array/address). Then you merely dereference the array's first position and assign a value to it (this really is just pointer arithmetic here).

Maybe it helps to rewrite the code in order to make the pointer arithmetic more obvious:

#include <stdio.h>

void change(int *a){
    int temp[1];
    *(temp+0) = *(a+0);
    *(a+0) = *(temp+0) * 10 + 7;
}

int main(){
    int num[1];
    *(num+0) = 0;
    change(num);
    printf("%d", *(num+0));
    return 0;
}

I am not sure how to understand the EDIT

EDIT : I want to copy the value, not the address of array

Looking at the code I fail to understand what you might want to try to achieve with this. Please clarify on this.

Having read your clarification I understand that you do not want to modify the array elements in the main function yet modifying them in the change function.

The answer is you cannot do that. The explanation is as mentioned above. I suggest you take some time to learn about pointer arithmetic and arrays in C. The K&R book is really excellent in that regard; I really recommend the book.

What you could do is copy the content of the array into another array and modify that one; e.g. in the beginning of the function or before calling the function and passing that copied array as parameter.

Ely
  • 10,860
  • 4
  • 43
  • 64
  • So, I want to use the second array value in formula and assign that value to first array. So, the first array got updated but won't effect to the second array. – Bernhard Josephus Dec 02 '18 at 12:42
  • @Ely >The C language is pass-by-value without exception. Passing a pointer as a parameter does not mean pass-by-reference.< Sorry but that is not correct. It absolutely **means** 'pass by reference'. "Pass by reference" is a **concept**, and it is implemented in C by passing a pointer value. C++ does have the **type** of reference, but that too gets passed by value and is internally implemented as a pointer, just like in C. – GermanNerd Dec 07 '18 at 08:58
  • 1
    Hello @GermanNerd - I believe I understand what you are trying to say. Though, I would like to say that you are "wrong". Please follow the link to see what is meant https://stackoverflow.com/questions/2229498/passing-by-reference-in-c/30519731#30519731 - Before engaging in further discussion please note that the citation is from K&R. Don't argue with me, argue with the authors about the "Deutungshoheit". – Ely Dec 07 '18 at 12:52
0

If you want to make a copy of an array inside a function so that you can work on the array copy without changing the original array, the best option is to make an explicit copy of the array yourself.

The most portable way to do this is by using malloc() or calloc() to allocate memory, and then copying the contents of the original array to the new memory allocation. If you choose this path your code must be sure to free any dynamically allocated memory when it is no longer needed. The copying can be done by looping and using array index notation to access the allocated memory, or by using memcopy() to copy the contents of the original array. Another option is to use a Variable Length Array (added to C with C99, made optional in C11 and C17 but still widely supported) to avoid dynamically allocating and deallocating the memory yourself.

Here is an example program that contains two functions, work_on_copy() and work_on_copy_vla(), that each take an array, copy it, and do some work that changes the copy. A final argument provides an array index which is used to illustrate how the array copy can be used to modify the original array selectively after work has been done inside the function. If this argument is a valid array index, the value at that index is copied from the array copy to the original array.

Note that this problem could also be solved by wrapping an array in a struct, but this method has the disadvantage of requiring that the array member of that struct be the same size as the largest array that is expected, wasting memory in the general case.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void print_array(size_t arr_sz, int arr[]);
void work_on_copy(size_t arr_sz, int arr[], int index);
void work_on_copy_vla(size_t arr_sz, int arr[], int index);

int main(void)
{
    int my_arr[] = { 1, 2, 3, 4 };
    size_t my_arr_sz = sizeof my_arr / sizeof *my_arr;

    puts("-- Do not change original array at all --");
    printf("Array in main(): ");
    print_array(my_arr_sz, my_arr);

    work_on_copy(my_arr_sz, my_arr, -1);

    printf("Array in main(): ");
    print_array(my_arr_sz, my_arr);

    work_on_copy_vla(my_arr_sz, my_arr, -1);

    printf("Array in main(): ");
    print_array(my_arr_sz, my_arr);
    putchar('\n');

    puts("-- Change specified index of original array after work --");
    printf("Array in main(): ");
    print_array(my_arr_sz, my_arr);

    work_on_copy(my_arr_sz, my_arr, 1);

    printf("Array in main(): ");
    print_array(my_arr_sz, my_arr);

    work_on_copy_vla(my_arr_sz, my_arr, 3);

    printf("Array in main(): ");
    print_array(my_arr_sz, my_arr);

    return 0;
}

void print_array(size_t arr_sz, int arr[])
{
    for (size_t i = 0; i < arr_sz; i++) {
        printf("%d ", arr[i]);
    }
    putchar('\n');
}

void work_on_copy(size_t arr_sz, int arr[], int index)
{
    /* make copy of array: could return a pointer to this allocation */
    int *arr_copy = malloc(sizeof *arr_copy * arr_sz);

    /* handle error if allocation fails */
    if (arr_copy == NULL) {
        perror("unable to allocate memory");
        return;
    }
    memcpy(arr_copy, arr, sizeof *arr_copy * arr_sz);  // or use a loop

    /* do work on local copy */
    for (size_t i = 0; i < arr_sz; i++) {
        arr_copy[i] += 10;
    }

    printf("Array copy after work (malloc): ");
    print_array(arr_sz, arr_copy);

    /* update original array if needed */
    if (index >= 0 && (size_t)index < arr_sz) {
        arr[index] = arr_copy[index];
    }

    /* deallocate memory to avoid memory leaks */
    free(arr_copy);
}

void work_on_copy_vla(size_t arr_sz, int arr[arr_sz], int index)
{
    /* make local copy of array using a VLA */
    int arr_copy[arr_sz];
    for (size_t i = 0; i < arr_sz; i++) {
        arr_copy[i] = arr[i];
    }

    /* do work on local copy */
    for (size_t i = 0; i < arr_sz; i++) {
        arr_copy[i] *= 2;
    }

    printf("Array copy after work (VLA): ");
    print_array(arr_sz, arr_copy);

    /* update original array if needed */
    if (index >= 0 && (size_t)index < arr_sz) {
        arr[index] = arr_copy[index];
    }
}

Program output:

-- Do not change original array at all --
Array in main(): 1 2 3 4 
Array copy after work (malloc): 11 12 13 14 
Array in main(): 1 2 3 4 
Array copy after work (VLA): 2 4 6 8 
Array in main(): 1 2 3 4 

-- Change specified index of original array after work --
Array in main(): 1 2 3 4 
Array copy after work (malloc): 11 12 13 14 
Array in main(): 1 12 3 4 
Array copy after work (VLA): 2 24 6 8 
Array in main(): 1 12 3 8 
ad absurdum
  • 19,498
  • 5
  • 37
  • 60