2010-08-27 16 views
8

¿Cómo puedo definir una matriz 2D utilizando malloc? (digamos 10X20).definiendo una matriz 2D con malloc y modificándola

En segundo lugar, ¿puedo aumentar el número de filas o cols sin crear una nueva matriz aumentada y copiar todos los datos a la misma?

por ejemplo, ¿cómo asigno la memoria para que la matriz sea 10x30 o 15x20?

gracias!

+2

¿Has probado algo? – cthom06

+0

comp.lang.c Preguntas frecuentes sobre preguntas frecuentes 6.16 - [¿Cómo puedo asignar dinámicamente una matriz multidimensional?] (Http://c-faq.com/malloc/realloc.html) y 7.29 - [Habiendo asignado dinámicamente una matriz, ¿puedo cambiar su tamaño?] (http://c-faq.com/aryptr/dynmuldimary.html) – schot

Respuesta

9

10x30:

int(*array)[30] = malloc((sizeof *array) * 10); 

15x20:

int(*array)[20] = malloc((sizeof *array) * 15); 

Cambiar el tamaño de 20x25:

int(*array2)[25] = realloc(array, (sizeof *array2) * 20); 

La dimensión exterior (10, 15, 20) se puede determinar en tiempo de ejecución, ya que no es necesario como parte de los cálculos de índice por parte del compilador. La dimensión interna (30, 20, 25) debe conocerse en tiempo de compilación. Espero eso ayude.

Tenga en cuenta que a diferencia de las soluciones de matriz-de-puntos, éste puede ser manejado como un solo bloque de memoria, ya que asigna todo en un solo trozo de memoria como un conjunto de bienes declarados:

memcpy(somewhere, array2, sizeof(int) * 20 * 25); // (sizeof *array2) * 20 

Sin embargo, en última instancia depende de tu uso.


Dado que algunas personas tienen dificultades para comprender las acciones tomadas por una operación de índice de array, vamos a lo que Clang nos da una expresión de índice en el siguiente código

int main() { 
    int(*array)[10] = malloc((sizeof *array) * 5); 
    array[4][9] = 0; 

    int(*array1)[10][5] = malloc((sizeof *array1) * 20); 
    array1[19][9][4] = 0; 
} 

Es un buen compilador, lo que puede imprimir su AST de una manera fácilmente legible

// array[4][9] = 0; 
    (BinaryOperator 0xba62cc0 <line:5:3, col:17> 'int' '=' 
    (ArraySubscriptExpr 0xba62c80 <col:3, col:13> 'int' 
     (ImplicitCastExpr 0xba62c60 <col:3, col:10> 'int *' <ArrayToPointerDecay> 
     (ArraySubscriptExpr 0xba62c20 <col:3, col:10> 'int [10]' 
      (DeclRefExpr 0xba62bdc <col:3> 'int (*)[10]' Var='array' 0xba62a00) 
      (IntegerLiteral 0xba62c00 <col:9> 'int' 4))) 
     (IntegerLiteral 0xba62c40 <col:12> 'int' 9)) 
    (IntegerLiteral 0xba62ca0 <col:17> 'int' 0)) 

    // array1[19][9][4] = 0; 
    (BinaryOperator 0xba630b8 <line:8:3, col:22> 'int' '=' 
    (ArraySubscriptExpr 0xba63078 <col:3, col:18> 'int' 
     (ImplicitCastExpr 0xba63058 <col:3, col:15> 'int *' <ArrayToPointerDecay> 
     (ArraySubscriptExpr 0xba63018 <col:3, col:15> 'int [5]' 
      (ImplicitCastExpr 0xba62ff8 <col:3, col:12> 'int (*)[5]' <ArrayToPointerDecay> 
      (ArraySubscriptExpr 0xba62fa0 <col:3, col:12> 'int [10][5]' 
       (DeclRefExpr 0xba62f5c <col:3> 'int (*)[10][5]' Var='array1' 0xba62db0) 
       (IntegerLiteral 0xba62f80 <col:10> 'int' 19))) 
      (IntegerLiteral 0xba62fc0 <col:14> 'int' 9))) 
     (IntegerLiteral 0xba63038 <col:17> 'int' 4)) 
    (IntegerLiteral 0xba63098 <col:22> 'int' 0))) 

Tenga en cuenta que cada expresión subíndice toma un puntero, añade el valor del índice, una nd produce el elemento direccionado. Si ese subelemento es una matriz, se descompone en un puntero a su primer elemento. Esto realmente no es realmente diferente de los pasos realizados por un array declarado

int main() { 
    int array[5][10] = { }; 
    array[4][9] = 1; 
} 

Los rendimientos de un AST muy similares, con sólo la expresión más interno primero se decayó a un puntero a su primer elemento

// array[4][9] = 1; 
    (BinaryOperator 0xbf9f7e8 <line:5:3, col:17> 'int' '=' 
    (ArraySubscriptExpr 0xbf9f7a8 <col:3, col:13> 'int' 
     (ImplicitCastExpr 0xbf9f788 <col:3, col:10> 'int *' <ArrayToPointerDecay> 
     (ArraySubscriptExpr 0xbf9f748 <col:3, col:10> 'int [10]' 
      (ImplicitCastExpr 0xbf9f728 <col:3> 'int (*)[10]' <ArrayToPointerDecay> 
      (DeclRefExpr 0xbf9f6cc <col:3> 'int [5][10]' Var='array' 0xbfa81f0)) 
      (IntegerLiteral 0xbf9f6f0 <col:9> 'int' 4))) 
     (IntegerLiteral 0xbf9f768 <col:12> 'int' 9)) 
    (IntegerLiteral 0xbf9f7c8 <col:17> 'int' 1))) 
+0

Espera, estoy un poco confundido. ¿No es 'int (* array) [30]' un puntero a la matriz 30 de int? Y está asignando este puntero a una ubicación de 'sizeof (int) * 10' bytes grande. Esto significa que esta ubicación solo puede contener 10 ints. ¿Dónde ocurre la asignación para el resto de los bytes?Porque necesita 30x10 ints (300 ints). No sabía que poner el [] en la definición replicaría la ubicación asignada a las matrices ... ¿cómo funciona esto? –

+2

@Luca, sí, es un puntero a una matriz de 30 int. Pero 'sizeof * array' produce' sizeof (int [30]) 'que es' sizeof (int) * 30'. No sé a qué te refieres con "replicaría la ubicación asignada a las matrices". Déjame intentar explicarlo: el primer código simplemente asigna un buffer que tiene el tamaño 'sizeof (int [10] [30])' y hace que un puntero al punto 'int [30]' lo señale. A continuación, puede indexar en el rango de 'matriz [0..9] [0..29]'. –

+0

Ohhhhhh, listo :). Gracias por enseñarme algo nuevo. +1. –

0

en segundo lugar, puedo aumentar el número de filas o cols sin crear un nuevo aumento matriz y la copia de todos los datos a ella?

No, no puede cambiar el tamaño de una matriz. Lo que puedes hacer es usar punteros y realloc para hacerlo.

3
// first allocate the 20 rows, that contain pointers to int 
// (if the matrix contains int type values) 
int **a = malloc(20 * sizeof(int *)); 

// now loop for each row and allocate data for the actual values 
int i; 
for(i = 0; i < 20; i++) { 
    a[i] = malloc(10 * sizeof(int)); 
} 

Para aumentar el tamaño de la matriz se puede utilizar realloc aunque probablemente sería más fácil para regenerar la matriz de diferente tamaño y copiar los valores superiores.

+1

Esta imagen parece una explicación de C++. Tenga en cuenta que si esto explica el operador 'new' de C++, es incorrecto. 'new' crea una matriz * real * de matrices, que se verá como el primer diagrama (solo asignando 3 * 4 enteros, como matrices declaradas), pero no como el segundo diagrama (asignando 3 * 4 enteros y 4 punteros). Por supuesto, la descripción es correcta si se aplica a su código de bucle en lugar de 'new int [3] [4]'. –

+0

sí, en realidad quería hacer referencia solo al segundo diagrama, déjame deshacerme de él. –

5

Mientras malloc() no admite directamente matrices multidimensionales, hay soluciones, tales como:

int rows = 10; 
int cols = 30; 
int *array = malloc(rows * cols * sizeof(int)); 

// Element (5,6) 
int x = 5; 
int y = 6; 
int element = array [ x * cols + y ]; 

Si bien esto no es directamente una matriz 2D, funciona, y en mi opinión, es el más simple. Pero si desea utilizar la sintaxis [][] lugar, usted tiene que hacer punteros a punteros, por ejemplo:

int rows = 10; 
int cols = 30; 
// Rows 
int **array = malloc(rows * sizeof(int*)); 
// Cols 
int i; 
for(i = 0; i < rows; i++) 
    array[i] = malloc(cols * sizeof(int)); 

// Element (5,6) 
int x = 5; 
int y = 6; 
int element = array[x][y]; 
+0

+1 - Encuentro de esta manera mucho más simple y menos propenso a errores que la matriz de soluciones de matrices. – cake

+0

Creo que usaré su primer ejemplo, es mucho más simple. Gracias a ti y al resto por tus respuestas –

+0

mm solo una pregunta más, con el segundo ejemplo, ¿puedo crear una matriz sin cuadrados? como en java: arr [] [] = {1,2,3,4}, {1,2} ? –

0

matriz A es una matriz 2D 1D matrices de 1D. Como una matriz es simplemente un puntero, una matriz de matrices es una matriz de punteros. Por lo tanto, usa malloc para asignar una matriz de punteros (cada uno representando una columna), luego úsela de nuevo para asignar las matrices individuales (cada una representando una fila). Para ampliar/reducir la matriz, utilice realloc(reference). Aquí hay un código de ejemplo:

#include <stdlib.h> 
#include <stdio.h> 

int** alloc_matrix(int w, int h) { 
    int** matrix; 

    matrix = (int**) malloc(sizeof(int*) * h); 
    for(int i = 0; i < h; i++) { 
     matrix[i] = (int*) malloc(sizeof(int) * w); 
    } 

    return matrix; 
} 

void realloc_matrix(int*** matrix, int new_w, int new_h) { 
    *matrix = (int**) realloc((void *)*matrix, sizeof(int*) * new_h); 

    for(int i = 0; i < new_h; i++) { 
     (*matrix)[i] = (int*) realloc((void *)(*matrix)[i], sizeof(int) * new_w); 
    } 
} 

int main(int argc, char* argv[]) { 
    // Allocating matrix 
    int** m = alloc_matrix(10, 15); 

    // Filling with some data 
    for(int y = 0; y < 15; y++) { 
     for(int x = 0; x < 10; x++) { 
      m[y][x] = y * x; // Notice the index is [y][x] - NOT [x][y]! 
     } 
    } 

    // Printing 
    for(int y = 0; y < 15; y++) { 
     for(int x = 0; x < 10; x++) { 
      printf("%d\t", m[y][x]); // Notice the index is [y][x] - NOT [x][y]! 
     } 
     printf("\n"); 
    } 

    // Reallocating 
    realloc_matrix(&m, 20, 10); 

    // Filling with some data 
    for(int y = 0; y < 10; y++) { 
     for(int x = 0; x < 20; x++) { 
      m[y][x] = y * x; // Notice the index is [y][x] - NOT [x][y]! 
     } 
    } 

    // Printing 
    for(int y = 0; y < 10; y++) { 
     for(int x = 0; x < 20; x++) { 
      printf("%d\t", m[y][x]); // Notice the index is [y][x] - NOT [x][y]! 
     } 
     printf("\n"); 
    } 
} 

Lo siento si tengo algo mal. Mi C-fu es un poco oxidado :)

0

En lugar de usar int[row][col], debería "envolver mejor su matriz" en una matriz unidimensional int[row*col].

Aquí es código de ejemplo:

#include <stdio.h> 
#include <stdlib.h> 

#define DET_MALLOC_FAIL -1 
#define DET_READ_FAIL -2 
#define DET_WRITE_FAIL -3 

typedef struct det_matrix_s { 
    double * vect; 
    size_t order; 
} det_matrix; 

void *det_sf_malloc(size_t dsize); 
det_matrix * det_matrix_new(size_t order); 
#define DET_MAT_ELEM(matr, i, j) \ 
    ((matr)->vect[((matr)->order * (i)) + (j)]) 
int det_matrix_read(det_matrix * matr, FILE * src); 
int det_matrix_write(det_matrix * matr, FILE * dest); 
void det_matrix_delete(det_matrix * matr); 

/** 
* Malloc wrapper 
*/ 
void * det_sf_malloc(size_t dsize) 
{ 
    void *data = malloc(dsize); 
    if(NULL == data){ 
     exit(DET_MALLOC_FAIL); 
    } 
    return (data); 
} 

/** 
* Allocates memory for a new matrix 
*/ 
det_matrix * det_matrix_new(size_t order) 
{ 
    det_matrix * res = det_sf_malloc(1 * sizeof(*res)); 
    double * vect = det_sf_malloc(order * order * sizeof(*vect)); 
    res->order = order; 
    res->vect = vect; 
    return (res); 
} 

/** 
* Reads matrix 
*/ 
int det_matrix_read(det_matrix * matr, FILE * src) 
{ 
    size_t i, j; 
    if(NULL == matr || NULL == src){ 
     return (DET_READ_FAIL); 
    } 
    for(i = 0; i < matr->order; ++i){ 
     for(j = 0; j < matr->order; ++j){ 
      if(stdin == src){ 
       fprintf(stdout, "mat[%d][%d] = ", i, j); 
      } 
      fscanf(src, "%lf", &DET_MAT_ELEM(matr, i, j)); 
     } 
    } 
    return (EXIT_SUCCESS); 
} 

/** 
* Writes matrix 
**/ 
int det_matrix_write(det_matrix * matr, FILE * dest) 
{ 
    size_t i, j; 
    if(NULL == matr || NULL == dest){ 
     return (DET_WRITE_FAIL); 
    } 
    for(i = 0; i < matr->order; ++i){ 
     for(j = 0; j < matr->order; ++j){ 
      fprintf(dest, "%5.2lf ", DET_MAT_ELEM(matr, i, j)); 
     } 
     fprintf(dest, "\n");  
    } 
    return (EXIT_SUCCESS); 
} 

/** 
* Free memory for matrix 
*/ 
void det_matrix_delete(det_matrix * matr) 
{ 
    free(matr->vect); 
    free(matr); 
} 

/** 
* Main 
*/ 
int main(int argc, char * argv[]) 
{ 
    det_matrix * mat = det_matrix_new(3); 
    det_matrix_read(mat, stdin); 
    det_matrix_write(mat, stdout); 
    det_matrix_delete(mat); 
    return (EXIT_SUCCESS); 
} 

Si reasignación es un problema, que pueden aparecer problemas. Y deberías usar la versión bidimensional.

Cuestiones relacionadas