2010-02-01 18 views
6
int **a = malloc2d(M, N) // dynamically allocates a 2D array 

¿Cuál es el propósito de tener int ** a vice int * a. Entiendo que los punteros son necesarios para la asignación dinámica, pero ¿por qué tener un puntero a un puntero?¿Por qué tener un puntero a un puntero (int ** a)?

Para una matriz de 3 dimensiones habría que ser:

int ***a 

?

+2

Sí lo haría, 3 matrices de dimensión es donde empieza a obtener una Un poco complicado, después de las matrices de 3 dimensiones mi cabeza empieza a doler y trato de encontrar otra forma de almacenar mis datos. – Craig

+0

Una matriz de 3 dimensiones es como almacenar información en una caja compartimentada, por lo que si tiene una caja de 10x10x10, y cada 1x1x1 almacena una información, puede almacenar 1000 piezas de información. Pero como dije después de tres punteros, es posible que desee ver otra forma de almacenar los datos. Un ejemplo de uso de matriz 3D sería una imagen, digamos un mapa de bits de 1024x1024, y en cada uno de los píxeles en la imagen que desee almacenar un valor R, G, B podría tener una matriz de 1024x1024x3, lo que significa que posición en la cuadrícula 1024x1024 puede almacenar [0] [1] y [2] cantidad de datos. – Craig

Respuesta

8

Necesita un puntero a un puntero por varias razones.

En el ejemplo que proporcionó, se utiliza un puntero doble para almacenar la matriz 2D.

Una matriz 2D en C se trata como una matriz 1D cuyos elementos son 1D matrices (las filas).

Por ejemplo, una matriz de 4x3 de T (donde "T" es algún tipo de datos) puede ser declarada por: "mat T [4] [3]", y descrito por la esquema siguiente:

     +-----+-----+-----+ 
    mat == mat[0] ---> | a00 | a01 | a02 | 
         +-----+-----+-----+ 
         +-----+-----+-----+ 
     mat[1] ---> | a10 | a11 | a12 | 
         +-----+-----+-----+ 
         +-----+-----+-----+ 
     mat[2] ---> | a20 | a21 | a22 | 
         +-----+-----+-----+ 
         +-----+-----+-----+ 
     mat[3] ---> | a30 | a31 | a32 | 
         +-----+-----+-----+ 

Otra situación es cuando pasa un puntero a una función y desea que esa función asigne ese puntero. Para ello, debe la dirección de la variable puntero, por lo tanto, un puntero a un puntero

void make_foofoo(int** change) { 
    *change = malloc(4); 
} 
1

Ayuda a hacer una fotografía. Imagine una matriz unidimensional, donde cada elemento contiene un puntero. Cada uno de esos indicadores apunta a otra matriz unidimensional. malloc2d no es una función de biblioteca estándar, pero supongo que devuelve una matriz bidimensional construida de esa manera.

1

Puede usar esto para crear una matriz de 2 dimensiones, como una matriz matemática o un tablero de ajedrez. Así que puede almacenar una tabla de datos prácticamente.

1

Una matriz C normal es un puntero a un bloque de memoria.

Una matriz 2D es un puntero a una lista de punteros a cada fila de la matriz.

por lo que, puntero a un puntero.

2

Sólo por el bien de la diversión, aquí hay un ejemplo *****:

  1. que tienen una textura 3D (una textura volumétrica) - 3 dimensiones, por lo tanto ***
  2. cada voxel en la textura tiene un color (*)
  3. está animado la textura, tiene un frameCount en el tiempo (*)

Por lo tanto, tendríamos tex [2] [3] [10] [2] [10] ...el cual es:

  1. de coordenadas en 3D 2,3,10
  2. de color 2 (verde)
  3. marco 10

Para pasar un ejemplo de datos con la capacidad de modificarlo, que' Necesito pasar un int****** ... ¡diversión! xD

(y por eso me gusta estructura de clases y ....)

0

para que sólo tenga pasar el tamaño de un puntero (con mayor frecuencia 32 o 64 bits) en lugar de objetos enteros.

7

En C, un puntero al tipo T apunta a una ubicación donde se almacenan algunos datos del tipo T. Para mantener las cosas concretas, voy a hablar sobre T = int a continuación.

El uso más simple de un puntero podría ser la de apuntar a un valor:

int a = 42; 
int *pa = &a; 

Ahora, *pa y a son ambos el mismo, e igual a 42. Además, *pa y pa[0] son tanto equivalentes: así, por ejemplo, se puede hacer:

*pa += 1; /* a is 43 */ 
pa[0] += 1; /* a is 44 */ 
a += 1; /* a is 45 */ 

De hecho, el compilador de C se traduce pa[0] a *(pa+0) automáticamente.

Un puntero puede apuntar a un lugar que se encuentra dentro de una secuencia de datos:

int arr[] = { 1, 2, 3 }; /* 3 ints */ 
int *parr = arr; /* points to 1 */ 

Ahora, nuestra memoria es el siguiente:

  +---+---+---+ 
     arr: | 1 | 2 | 3 | 
      +---+---+---+ 
+------+  | 
| parr | ----+ 
+------+ 

parr es un puntero que apunta a la primera elemento de arr en la imagen de arriba. Por cierto, parr también tiene una caja alrededor, porque tenemos que almacenar el objeto parr en algún lugar de la memoria. El valor de parr es la dirección del primer elemento de arr.

Ahora, podemos usar parr acceder a los elementos de arr:

arr[0] == parr[0]; /* true */ 
parr[1]++; /* make arr[1] equal to 3 */ 

Por lo tanto, el puntero puede ser utilizado para significar "señalo a la primera de n elementos en una tienda contigua de algunos objetos" . Por supuesto, uno tiene que saber cuántos objetos hay para que funcione este esquema: pero una vez que lo recordamos, es una forma extremadamente conveniente de acceder a la memoria en C.

Se puede hacer que el puntero apunte dinámicamente asignado la memoria, así:

#include <stdlib.h> 
size_t n; 
/* now, obtain a value in n at runtime */ 
int *p = malloc(n * sizeof *p); 

Si la llamada tiene éxito malloc() anterior, p ahora apunta a la primera de un área contigua asignado durante 10 s int. Podemos usar p[0] a través de p[n-1] en nuestro programa ahora.

Probablemente conozca la mayoría o la totalidad de las anteriores :-), pero aun así, lo anterior ayuda a comprender lo que voy a decir a continuación.

¿Recuerda que dijimos que un puntero puede apuntar a una secuencia contigua de objetos del mismo tipo? El "mismo tipo" puede ser otro tipo de puntero también.

#include <stdlib.h> 
int **pp; 
pp = malloc(3 * sizeof *pp); 

Ahora, pp apunta a un int *. Volviendo a nuestra imagen anterior:

  +------+------+------+ 
      |  |  |  | 
      +------+------+------+ 
+------+  | 
| pp | ----+ 
+------+ 

Y cada una de las 3 cajas es una int *, que puede señalar al primer elemento de una secuencia contigua de int s:

for (i=0; i < 3; ++i) 
    pp[i] = malloc((i + 1) * sizeof *ppi[i]); 

Aquí, asignamos espacio para un int en pp[0], 2 en pp[1], y 3 en pp[3]:

   +------+   +---+ 
pp -------->|  |-------->| | 
      +------+   +---+---+ 
      |  |-------->| | | 
      +------+   +---+---+---+ 
      |  |-------->| | | | 
      +------+   +---+---+---+ 

Así, pp[0] es un puntero a uno int, y int es el único int en un bloque dinámicamente asignado de int s. En otras palabras, pp[0][0] es int, y apunta a la casilla superior "ancho-3" arriba. Del mismo modo, pp[1][0] y pp[1][1] son ambos válidos y son los dos cuadros debajo del cuadro pp[0][0].

El uso más común de puntero a puntero es crear una "matriz" de 2 dimensiones en tiempo de ejecución:

int **data; 
size_t i; 
data = malloc(n * sizeof *data); 
for (i=0; i < n; ++i) 
    data[i] = malloc(m * sizeof *data[i]); 

Ahora, suponiendo que todas malloc() s éxito, data[0] ... data[n-1] son válidos los valores int * , cada uno apunta a una longitud separada m objetos contiguos int.

Pero, como mostré anteriormente, un puntero al puntero no necesita tener el mismo "número de elementos" en cada una de sus "filas". El ejemplo más obvio es argv in main().

Por ahora, como se puede adivinar, un puntero "3 niveles de profundidad", como int ***p; está bien y puede ser útil en C.

+0

'int * pa = &42;' parece incorrecto, ¿no debería ser 'int * pa = & a'? – Hasturkun

+0

Por supuesto. No puedo creer que cometí ese error. ¡Gracias! –

Cuestiones relacionadas