¿Por qué la dirección de la matriz no se puede convertir a ** en C?

programación


Hola. ¿Por qué la dirección de la matriz (es decir, &) no convertible a ** ¿Cª?

Lo que he probado:

Intenté lo siguiente …

C
#include <stdio.h>


int main()
{
    int** a;
    int b[5];
    b[1] = 123;
    
    //a = &b; //< results in output of warning "assignment to ‘int **’ from incompatible pointer type ‘int (*)[5]’"
    int* c = b;
    a = &c; //< this works
    printf("*a is %i\n", (*a)[1]);
    
    return 0;
}

Yo esperaría que, como b se puede convertir a int*sería posible convertir &b a int**. Sin embargo, esto da como resultado la advertencia mencionada en el bloque de código anterior.

Usando mingw gcc en Windows esto (escribir y luego leer desde un ** que fue asignado a la dirección de una matriz) en realidad funcionó una vez, pero no una segunda vez.

Solución 1

b es una matriz: el nombre de una matriz es un puntero al primer elemento, por lo que técnicamente, &b es un puntero a un puntero a un número entero. Pero… su compilador no está de acuerdo porque (justificadamente) lo considera un puntero a una matriz de números enteros. Y las matrices son un azúcar sintáctico para la aritmética de punteros que se produce en segundo plano, por lo que no funcionan como se podría pensar.
Puedes evitarlo haciendo b un puntero a un int en su lugar:

C
#include <stdio.h>
#include <malloc.h>
int main()
    {
    int** a;
    int* b = malloc(sizeof(int) * 5);
    b[1] = 123;
    
    a = &b; 
    printf("*a is %i\n", (*a)[1]);

    free(b);
    return 0;
    }

Solución 2

Dicha advertencia significa que debe establecer explícitamente el tipo de conversión resultante; esto significa que comprende que el resultado del uso de dicha variable en el código puede provocar fallas o pérdidas de memoria. Como ejemplo, el código de comentarios de esta discusión. https://www.codeproject.com/Answers/5370174/C-language-I-dont-understand-multi-dimensional-arr#answer3[^]:

int mat[3][3] = { {0,1,2},{3,4,5},{6,7,8} };
int **ptr = (int **)&mat;
printf("%d\n", mat[1][1]); /* prints "4" */
printf("%d\n", ptr[1][1]); /* seg faults! */ 

Aquí tienes una matriz multidimensional y la transmites al int**. Este código funcionará en la plataforma x86 y fallará en x64 en el lugar especificado en el comentario.

Entonces, la advertencia de conversión solo le muestra que debe ocuparse del uso de la variable resultante, eso es todo.

Solución 3

Gracias en particular a Maxim Kartavenkov porque señalar la infracción de acceso acabó ayudándome en la dirección correcta.

Usando mi ejemplo…

C
#include <stdio.h>


int main()
{
    int a[5];
    a[1] = 123;
    a[2] = 456;
    
    printf("&a is %p\n", &a); //< type of &a is int(*)[], which apparently is some sort of special type
    printf("a is %p\n", a); //< type is int*
    // ^
    // both will print the same address

    printf("&(&a)[1] is %p\n", &(&a)[1]);
    printf("((char*)a) + sizeof(a) is %p\n", ((char*)a) + sizeof a);
    // ^
    // both will print the same address

    int** b = &a;

    printf("sizeof(int) is %i\n", sizeof(int));
    printf("sizeof(int**) is %i\n", sizeof(int**));
    // ^
    // in test case this printed..
    // sizeof(int) is 4
    // sizeof(int**) is 8
    
    printf("b[1] is %p\n", b[1]);
    // ^
    // printed..
    // b[1] is 0x1c8
    printf("b[1] is %i\n", b[1]); //< as indexing into array of int** goes to a[2] rather than a[1] because int** is twice the size of int
    // ^
    // printed..
    // b[1] is 456

    return 0;
}

Así, la confusión que tenía surgió de la expectativa “que &a (dónde typeof(a) es int[5]) sería una dirección de puntero diferente aunque eso no fue lo que sucedió”.

Tal vez &a requeriría crear otra variable de tipo int** ¿implícitamente ya que una matriz en la pila no requiere dicha variable porque puede almacenar los elementos directamente? Tal vez sea por eso &a en lugar de eso, ¿solo devuelve el mismo puntero pero de un tipo diferente, para evitar crear una variable oculta?

Solución 4

Es más fácil usar una conversión cuando se establece a en la dirección de b:

C++
int** a;
int b[5];
b[0] = 1;
b[1] = 3;
b[2] = 5;
b[3] = 7;
b[4] = 9;

a = (int**)&b;
for (int i = 0; i < 5; i++)
{
    printf("a = %p, *a = %d\n", a, *a++);
}

コメント

タイトルとURLをコピーしました