Estoy escribiendo una función que toma un puntero doble como parámetro. Noté que expresiones como esta char *tmp = arr[i]; funcionan, donde arr es un puntero char **arr. Toda la función se ve así:

void string_sort(char** arr,const int len,int (*cmp_func)(const char* a, const char* b))
{
    for (int i = 0; i < len; ++i)
    {
        for (int j = i + 1; j < len; ++j)
        {
            if(cmp_func(arr[i], arr[j]) > 0)
            {
                char *tmp = arr[i];
                arr[i] = arr[j];
                arr[j] = tmp;
            }
        }
    }
}

Mi pregunta es: ¿por qué arr[i] se considera una dirección y no un puntero desreferenciado? (Entiendo que un puntero doble "apunta" a la dirección de otro puntero, pero no entiendo por qué esta sintaxis es válida). ¿Puedes dar un ejemplo de una expresión equivalente sin una sintaxis tipo matriz?

1
S.Sot 4 dic. 2019 a las 22:58

2 respuestas

La mejor respuesta

Aquí estás

#include <stdio.h>

int main(void) 
{
    char *s = "Hello";

    printf( "%p -> %s\n", ( void * )s, s );

    char **t = &s;

    printf( "%p -> %p ->  %s\n", ( void * )t, ( void * )*t, *t );
    printf( "%p -> %p ->  %s\n", ( void * )t, ( void * )t[0], *t );

    return 0;
}

La salida del programa podría verse así

0x55a06f99c004 -> Hello
0x7ffc051a83d8 -> 0x55a06f99c004 ->  Hello
0x7ffc051a83d8 -> 0x55a06f99c004 ->  Hello

Ese es el puntero s apunta al primer carácter del literal de cadena "Hello".

El puntero t apunta al puntero s que a su vez apunta al primer carácter del literal de cadena "Hello".

Por ejemplo, si tiene una declaración como esta

char *s = "Hello";

Entonces las dos expresiones s[0] y *s tienen el tipo char y producen el primer carácter del literal de cadena que es 'H'.

Otro ejemplo. Si tienes una serie de enteros

int a[] = { 1, 2, 3, 4, 5 };

Entonces el número de sus elementos se puede calcular como

sizeof( a ) / sizeof( a[0] )

O como

sizeof( a ) / sizeof( *a )

[Aunque incluso puedes escribir como

sizeof( a ) / sizeof( a[1000] )

Porque la expresión utilizada no se evalúa. Es importante solo el tamaño de un objeto del tipo int. Entonces también podrías escribir

sizeof( a ) / sizeof( int )

-final nota]

1
Vlad from Moscow 4 dic. 2019 a las 20:13

Esta sintaxis es válida porque arr[i] es literalmente exactamente igual que *(arr + i). Este también es un ejemplo sin utilizar la sintaxis de subíndice de matriz, por cierto.

... ¿por qué arr[i] se considera una dirección y no un puntero desreferenciado?

Sí, arr[i] es un puntero desreferenciado, como se discutió anteriormente. También es una dirección porque cuando desreferencia un puntero a un puntero (char **arr), obtienes un puntero, una dirección.

2
ForceBru 4 dic. 2019 a las 20:03