¿Por qué no podemos usar el puntero doble para representar arreglos bidimensionales?

8 minutos de lectura

avatar de usuario
Thangaraj

¿Por qué no podemos usar el puntero doble para representar arreglos bidimensionales?

arr[2][5] = {"hello","hai"};
**ptr = arr;

Aquí, ¿por qué el puntero doble (**ptr) no funciona en este ejemplo?

  • ¿Qué código ha compilado que es similar al código en su pregunta?

    –Steve Jessop

    17 de diciembre de 2010 a las 13:40

  • Huya de las matrices multidimensionales (excepto quizás las pequeñas).

    – Alejandro C.

    17 de diciembre de 2010 a las 13:42

  • @Alexandre C. Las matrices multidimensionales son simples, útiles y eficientes. ¿Por qué querrías huir de ellos?

    – Shahbaz

    12 de septiembre de 2011 a las 12:22

  • @Shahbaz: no son simples, y si no tienes C99 tampoco son útiles ya que no pueden tener longitud variable.

    – Alejandro C.

    12 de septiembre de 2011 a las 17:58

  • Invertí la pregunta para que no confunda a los futuros lectores.

    – Shahbaz

    17 de octubre de 2013 a las 8:53

avatar de usuario
Shahbaz

voy a tratar de dibujar como

int array[10][6];

y

int **array2 = malloc(10 * sizeof *array2);
for (int i = 0; i < 10; ++i)
    array2[i] = malloc(6 * sizeof **array2);

como se ven en la memoria y como son diferentes (Y que no pueden ser echados el uno al otro)

array parece:

 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| | | | | | | | | | | | | ..............| | | (10*6 elements of type int)
 - - - - - - - - - - - - - - - - - - - - - -
< first row >< second row> ...

array2 parece:

 _ _ _ _ _ _ _ _ _ _ 
| | | | | | | | | | | (10 elements of type int *)
 - - - - - - - - - - 
 | |     ....      |     _ _ _ _ _ _
 | |                \-->| | | | | | | (6 elements of type int)
 | |                     - - - - - -
 | |
 | |      _ _ _ _ _ _
 |  \ -->| | | | | | | (6 elements of type int)
 |        - - - - - -
 |
 |
 |      _ _ _ _ _ _
  \ -->| | | | | | | (6 elements of type int)
        - - - - - -

Cuando tu dices array[x][y]se traduce en *((int *)array+x*6+y)

Mientras, cuando dices array2[x][y]se traduce en *(*(array2+x)+y) (Tenga en cuenta que para arrayesta fórmula también funciona (lea hasta el final de la publicación y luego los comentarios)).

Es decir, una matriz 2D estática es, de hecho, una matriz 1D con filas en una sola línea. El índice se calcula mediante la fórmula row * number_of_columns_in_one_row + column.

Sin embargo, una matriz 2d dinámica es solo una matriz 1d de punteros. Luego, cada puntero se asigna dinámicamente para apuntar a otra matriz 1d. En verdad, ese puntero podría ser cualquier cosa. Podría ser NULL, o apuntando a una sola variable, o apuntando a otra matriz. Y cada uno de esos punteros se configura individualmente, por lo que pueden tener diferentes naturalezas.

Si necesita pasar el puntero de array en algún lugar, no puedes enviarlo a int ** (imagina lo que pasaría. El int valores de las celdas de array se interpretan como punteros y se desreferencian -> ¡Bam! ¡Fallo de segmentación!). Sin embargo, puedes pensar en array como una matriz 1d de int [6]s; que es una matriz 1d de elementos, con tipo int [6]. Para escribir eso, dices

int (*p)[6] = array;

  • Si array se asigna en la memoria tal como usted ha descrito cómo funciona algo como esto ¿seguirá funcionando? puedo entender eso array[x][y] se traduce a *(((int *)array)+x*6+y)pero ¿por qué *(*(array + i) + j) ¿seguirá funcionando?

    – Kohányi Róbert

    6 de septiembre de 2018 a las 7:20

  • @KohányiRóbert, Ese es un punto excelente. Y, de hecho, para una matriz multidimensional (no dinámica) (array en este caso), los dos son equivalentes. Debes prestar atención al tipo de array en la expresión para entenderla. Primero, observe que en *(((int *)array)+x*6+y)primero eché array para int *. Esto esencialmente significa x*6+y es un índice de una matriz de ints.

    – Shahbaz

    18/09/2018 a las 14:55

  • Ahora cuando lo hagas *(*(array + i) + j))no cambias el tipo de array. ¿Cuál es el tipo de array? Es int (*)[6]. ¿Cuál es el sizeof ¿de eso? Es sizeof(int) * 6. Ahora *(array + i) entonces se convierte en lo mismo que (int[6])((int *)array + i*6) (¿tiene sentido?). Indexar eso con j se convierte en *((int *)array + i*6 + j).

    – Shahbaz

    18/09/2018 a las 14:55


  • Es int *p[6] = array; tambien valido? ¿Los paréntesis son importantes para el compilador?

    – Rohan

    18 de abril de 2020 a las 9:53


  • @Rohan, los paréntesis importan. int *p[6] es una matriz de 6 punteros. int (*p)[6] es un puntero a una matriz de 6 enteros. Esto es bastante similar a los punteros de función. int *f() y int (*f)() son cosas diferentes.

    – Shahbaz

    22 de abril de 2020 a las 2:53


avatar de usuario
steve jesop

En C, un arreglo bidimensional es un matriz de matrices.

Necesita un puntero a matriz para referirse a él, no un doble puntero:

char array[2][6] = {"hello", "hai"};
char (*p)[6] = array;
//char **x = array;  // doesn't compile.

Para que un puntero doble se refiera a “datos bidimensionales”, debe referirse al primer elemento de un matriz de punteros. Pero una matriz bidimensional en C (matriz de matrices) no es lo mismo que una matriz de punteros, y si solo define una matriz 2-D, entonces no existe una matriz de punteros correspondiente.

La única similitud entre los dos es el [][] sintaxis utilizada para acceder a los datos: los datos en sí están estructurados de manera bastante diferente.

avatar de usuario
R.. GitHub DEJAR DE AYUDAR A ICE

Hacer una matriz de punteros a cada fila para obtener un objeto que “parece” una matriz multidimensional de tamaño variable es una opción de diseño costosa por el bien del azúcar sintáctico. no lo hagas

La forma correcta de hacer una matriz multidimensional de tamaño variable es algo como:

if (w > SIZE_MAX/sizeof *m/h) goto error;
m = malloc(w * h * sizeof *m);
if (!m) goto error;
...
m[y*w+x] = foo;

Si quieres que “se vea bonito” entonces puedes escribir m[y][x]debería estar usando un lenguaje diferente, tal vez C++.

  • puede usar matrices de longitud variable para permitir que el compilador haga el cálculo de compensación por usted: int (*foo)[cols] = malloc(sizeof *foo * rows) hace posible el uso de la familiar foo[i][j] sintaxis;

    – Cristóbal

    17 de diciembre de 2010 a las 16:57

  • @Christoph: De hecho, si tiene un compilador C99, esto funciona. Sin embargo, debe organizarse para pasar las dimensiones correctamente a cualquier llamada de función a la que pase la matriz.

    – R.. GitHub DEJA DE AYUDAR A ICE

    17 de diciembre de 2010 a las 17:23

avatar de usuario
relajarse

Tener puntero a puntero significa que cada fila (o columna, si prefiere pensarlo de esa manera) puede tener una longitud diferente de las otras filas/columnas.

También puede representar una matriz 2D con solo un puntero al elemento de inicio y un número entero que especifica la cantidad de elementos por fila/columna:

void matrix_set(double *first, size_t row_size, size_t x, size_t y, double value)
{
  first[y * row_size + x] = value;
}

Comencemos hablando del código legal. Lo que ha escrito (suponiendo un carácter delante de cada declaración) no se compilará, por varias razones: tiene demasiados inicializadores (seis caracteres para arr[0]y su tamaño es 5), y por supuesto, char** p no tiene un tipo compatible con char arr[2][5]. Corrigiendo estos problemas, obtenemos:

char arr[2][6] = { "hello", "hai" };
char (*p)[6] = arr;

Sin ningún doble puntero. Si desea acceder a caracteres individuales en lo anterior, debe especificar el elemento del que provienen:

char* pc = *arr;

funcionaría, si quisiera acceder a los caracteres del primer elemento en arr.

C++ no tiene arreglos bidimensionales. La primera definición anterior define una matriz[2] o matriz[6] de char. La conversión implícita de matriz a puntero da como resultado un puntero a matriz[6] de char. Después de eso, por supuesto, no hay conversión de matriz a puntero, porque ya no tiene una matriz.

avatar de usuario
linconcinco

Siempre hay un desacoplamiento del lenguaje a la representación.

Hasta cierto punto, C es casi disendio.

Tome el ejemplo anterior, estamos tratando de asignar o transformar una matriz 2D en otra forma,

#include <stdio.h> 
  
int main() 
{ 
        char array[2][6] = {"hello", "hai"};
        int h, i;
        for (h = 0; h < 2; h++) 
                for (i = 0; i < 6; i++) 
                        printf("%c\n", *(*(array+h) + i));
        char (*p)[6] = array;
        for (h = 0; h < 2; h++) 
                for (i = 0; i < 6; i++) 
                        printf("%c\n", *(*(p+h) + i));
        char **x = array;
        for (h = 0; h < 2; h++) 
                        printf("%c\n", *(x+h));
} 

Y la salida,

h
e
l
l
o

h
a
i



h
e
l
l
o

h
a
i



h
i

Hoy en día, los compiladores son tan inteligentes que probablemente solo advertirán en lugar de fallar, es decir

main.c:14:13: warning: initialization from incompatible pointer type [enabled by default]
  char **x = array;

En este punto, deberíamos ser capaces de entender el doble puntero. no es matriz doble.

El primero h es desde helloel segundo i es desde hai. Observe que la distancia es de 8 bytes, igual a tamaño de un puntero.

Además, también podemos hacer,

char *y[2];
for (h = 0; h < 2; h++) 
        y[h] = array[h];
for (h = 0; h < 2; h++)
        printf("%s\n", y[h]);
for (h = 0; h < 2; h++)
        for (i = 0; i < 6; i++)
                printf("%c\n", *(*(p+h) + i));

Pero esta tarea no es una declaración de una sola línea.

Y la salida,

hello
hai
h
e
l
l
o

h
a
i

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad