1

In the university we did this code:

int cargaArreglo(int ** A);

int main(){

int * A = NULL;
int i = 0;
int dimension = cargaArreglo(&A);

for( i = 0; i < dimension; i++ )
     printf( "[%d]", A[i] );

free( A );
return 0;
}

int cargaArreglo(int ** A){

int i = 0;
char bandera = 's';
(*A) = malloc( 1*sizeof(int) );

while( bandera != 'n' ){
     printf( "Ingrese un numero" );
     scanf( "%d", &(*A)[i] );
     printf( "Desea seguir ingresando?" );
     i++;
     fflush( stdin );
     scanf( "%c", &bandera );
     if( bandera != 'n' )
     (*A) = realloc( (*A), (i+1)*sizeof(int) );
}
return i;
}

We tried to load a dinamic array, and add values without a limit. The code works very fine but in the functions we need to declare the parameters with Double Pointers, exist any posibility of to convert this in a simple pointer? I mean, the teacher said that is impossible, because without the double pointer I cant change the value of the global variable. This made me confuse respect to the pointers.

Thank you for your time!

PD: If you find a mistake respect a my english, please tell me because I would help me much with my studies.

3 Answers3

4

If you don't like pointers-to-pointers, you could always modify the function's signature so that it returns the new pointer-value to assign to A, and sets the dimension value via a pointer instead:

[...]
int dimension;
int * A = cargaArreglo(&dimension);
[...]


int * cargaArreglo(int * retDimension){
   int i = 0;
   char bandera = 's';
   int * B = malloc( 1*sizeof(int) );

   while( bandera != 'n' ){
        printf( "Ingrese un numero" );
        scanf( "%d", &B[i] );
        printf( "Desea seguir ingresando?" );
        i++;
        fflush( stdout ); /* fflush( stdin ) is UB */
        scanf( "%c", &bandera );
        if( bandera != 'n' )
           B = realloc( B, (i+1)*sizeof(int) );
   }
   *retDimension = i;

   return B;
}

I mean, the teacher said that is impossible, because without the double pointer I cant change the value of the global variable. This made me confuse respect to the pointers.

What the teacher meant was that when you call a function in C, a temporary copy of each argument is pushed onto the stack for use inside the function. So if you change the value of the argument inside the called function, it doesn't change the value back in the calling function... for example, running this code:

void foo(int x, int * A)
{
   x = 6;
   A = NULL;
}

int x = 5;
int * A = &x;
printf("BEFORE x=%i A=%p &x=%p\n", x, A, &x);
foo(x, A);
printf("AFTER x=%i A=%p &x=%p\n", x, A, &x);

... will print out:

BEFORE x=5 A=0x2345678 &x=0x2345678
AFTER x=5 A=0x2345678 &x=0x2345678

... which is to say that foo() did not actually change the value of either x or A in the calling function, because foo() modified only the copy of x and the copy of A that were passed to it, and not the original variables.

However, foo() can use the A pointer to (indirectly) modify the value of calling function's x, because the function's copy of A still points to the calling function's x, so you could implement foo do this:

void foo(int * A)
{
   *A = 666;
}

int x = 5;
printf("BEFORE x=%i\n", x);
foo(&x);
printf("AFTER x=%i\n", x);

... and you'd get this output:

BEFORE x=5
AFTER x=666

... and if the above makes sense to you, then the pointer-to-a-pointer case is really just the same thing as above, except that instead of A pointing to an int, the type of the value it is pointing to is a pointer:

void foo(int ** x)
{
    *x = NULL;
}

int y = 5;
int * x = &y;
int ** A = &x;
printf("BEFORE x=%p\n", x);
foo(A);
printf("AFTER x=%p\n", x);

... would print out:

BEFORE x=0x2345845  (actual value will vary depending on your computer)  
AFTER x=NULL
Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
1

exist any posibility of to convert this in a simple pointer?

It is a simple pointer. C has no other kind.

Understanding that point is one of the keys to C mastery. Another way to look at it is that pointers are just one kind of value the C supports. Valid pointer values have significance as addresses (in some sense) of functions or objects in the program, but that does not make them in any way magical. They are first-class values. In particular, pointers can point objects of pointer type as a natural consequence of the language's type system. That a pointer points to another pointer does not make it non-simple.

I think some people get confused by pointers because they read the type from left to right, so they see the name of some base type first (int in your case) and attribute the most significance to that. But although the int *, int **, etc. types are related to the int type, values of those pointer types are not much related to ints at all. Instead of reading types from left to right, you should read them from the inside out, which in many common cases is right-to-left. Reading int **A as "A is a pointer to pointer to int" emphasizes that its value is a pointer, which is the most significant thing about it.

As for specific ways in which you could restructure your program, @JeremyFriesner has already covered the matter very well. The key thing to understand in this area is why you (may) want to use a pointer argument in the first place.

In general, there are several reasons why you might want to do so, but the main one and the one applicable to your particular code is the one your instructor gave you: so that the function can modify an object declared in a different scope or allocated dynamically. In this case, that object is a pointer to the address of your dynamically-allocated array. (Remember: pointers are objects in their own right.)

Additionally, C functions have only one return value. If you want a function to communicate several pieces of data to its caller then either you must provide pointer arguments by which it can do so, or you must return a value of a suitable structure type (which you might not have studied yet), or you must return a pointer to a structure or array containing all the data.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
0

If you don't like the way the syntax looks, you can use a local pointer variable when doing the work inside of the function and assign that back to the dereferenced pointer-to-pointer at the end:

int cargaArreglo(int **A){

    int i = 0;
    char bandera = 's';
    int *B;
    B = malloc( 1*sizeof(int) );

    while( bandera != 'n' ){
         printf( "Ingrese un numero" );
         scanf( "%d", &B[i] );
         printf( "Desea seguir ingresando?" );
         i++;
         fflush( stdin );
         scanf( "%c", &bandera );
         if( bandera != 'n' )
         B = realloc( B, (i+1)*sizeof(int) );
    }
    *A = B;
    return i;
}
dbush
  • 205,898
  • 23
  • 218
  • 273