arrayscpointersdereference

Is it acceptable to pass a pointer as an argument for a double pointer in C?


So I've been doing some learning projects in c, and I'm starting to get more comfortable with pointers, however I have come across some phenomena that I can't seem to find much information for.

Basically, I make an array, for simplicity's sake I'm starting with an integer array:

int x[2] = {1, 3};

Now, if I want to modify the contents of this array, I found that I can make a function which takes an integer pointer as a parameter, and pass x as an argument, and dereference x by specifying an index.

#include <stdio.h>

void foo(int* input){
    input[0] = 2;
    input[1] = 4;
}

int main(){
    int x[2] = {1, 3};
    printf("x[0] before: %d\nx[1] before: %d\n", x[0], x[1]);
    foo(x);
    printf("x[0] after: %d\nx[1] after: %d\n", x[0], x[1]);
}

output

x[0] before: 1
x[1] before: 3
x[0] after: 2
x[1] after: 4

which, is interesting, but I don't see it done often, so im unsure if it's acceptable.

Now, for the bigger question, for some reason, whenever I want to change the address that the pointer itself points to, by specifying a new value and pointer, and then setting the argument to that new pointer, it only seems to work whenever I do the following:

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

void foo(int** input){
    int x[3] = {2, 4};
    int** ptr = x;
    *input = *ptr;
}

int main(){

    int x[2];
    x[0] = 1;
    x[1] = 3;
    printf("x[0] before: %d\n", x[0]);
    printf("x[1] before: %d\n", x[1]);
    foo(x);
    printf("x[0] after: %d\n", x[0]);
    printf("x[1] after: %d\n", x[1]);

    return 0;
}

Output:

x[0] before: 1
x[1] before: 3
x[0] after: 2
x[1] after: 4

So I have several questions that I can't seem to find an answer to, probably due to my lack of technical vocabulary: Answers added as edit below

1: Whenever I pass the array with and without referencing as an argument, why does the argument behave as an array of pointers, without initializing an array of pointers and setting it to the address of the array first? Are there any unintended consequences of doing this?

Answer by Eric Postpischil

It is normal and common to give an array as an argument for a parameter that is a pointer. The array is automatically converted to a pointer to its first element.

2: If the argument is a pointer, rather than a pointer to a pointer, is it acceptable to pass a pointer as an argument, to a function that takes a double pointer as a parameter like I did, is there any undefined behavior by doing this I should know of?

Answer by Eric Postpischil

foo is declared to take an int **, so the compiler converted the pointer to the type int . But it still points to x[0]. int ptr = x; initializes ptr to point to the first element of the x local to foo. Again, the compiler converts the pointer to the type int **.

3: Why does this work?

Answer by Eric Postpischil

In your C implementation, int is four bytes, so eight bytes is two int. When the compiler loads eight bytes from memory, it gets the two int that the pointer is pointing to, so it gets the bytes of x[0] and x1 (in the local array x).

EDIT:

Thank you everyone for all of your help, as it turns out, my compiler will not allow that weird solution to work, it just happened to work when running the program in debug mode on visual studio code, when compiled in the terminal, it will indeed throw error codes.

user Lundin posted this helpful link for compiler options for beginners


Solution

  • … which, is interesting, but I don't see it done often, so im unsure if it's acceptable.

    It is normal and common to give an array as an argument for a parameter that is a pointer. The array is automatically converted to a pointer to its first element.

    This conversion is performed whenever an array is used in an expression other than as the operand of sizeof, as the operand of unary &, as the operand of a typeof operator, or as a string literal used to initialize an array.

    Regarding this code:

    void foo(int** input){
        int x[3] = {2, 4};
        int** ptr = x;
        *input = *ptr;
    }
    

    This is horrible, and you should never do it.

    What is actually happening here is:

    This all “worked” by coincidence. It is in fact behavior that is not defined by the C standard: These implicit pointer conversions are not defined, accessing memory using the wrong type is not defined, and the pointer to x[0] may not be correctly aligned for an int *. If you enable optimization in the compiler or otherwise change the program or how it is executed, the program may cease “working.”