2011-01-09 25 views
10

¿Cómo se supone que debo usar asignaciones dinámicas de memoria para matrices?Uso de la asignación de memoria dinámica para matrices

Por ejemplo, aquí es la siguiente matriz en la que leí las palabras individuales de un archivo .txt y guardarlos palabra por palabra de la matriz:

Código:

char words[1000][15]; 

Aquí define el número 1000 de palabras la matriz puede guardar y cada palabra puede comprender de no más de 15 caracteres.

Ahora quiero que ese programa asigne dinámicamente la memoria para el número de palabras que cuenta. Por ejemplo, un archivo .txt puede contener palabras mayores que 1000. Ahora quiero que el programa cuente el número de palabras y asigne la memoria en consecuencia.

Como no podemos usar una variable en lugar de [1000], estoy completamente en blanco sobre cómo implementar mi lógica. Por favor, ayúdame en este sentido.

Respuesta

17

Se utiliza punteros.

Específicamente, usa un puntero a una dirección, y usando una función de biblioteca c estándar llama, le pide al sistema operativo que expanda el montón para permitirle almacenar lo que necesita.

Ahora, podría rechazar, que deberá manejar.

La siguiente pregunta es: ¿cómo se solicita una matriz 2D? Bueno, solicite una serie de punteros y luego expanda cada puntero.

Como ejemplo, considere esto:

int i = 0; 
char** words; 
words = malloc((num_words)*sizeof(char*)); 

if (words == NULL) 
{ 
    /* we have a problem */ 
    printf("Error: out of memory.\n"); 
    return; 
} 

for (i=0; i<num_words; i++) 
{ 
    words[i] = malloc((word_size+1)*sizeof(char)); 
    if (words[i] == NULL) 
    { 
     /* problem */ 
     break; 
    } 
} 

if (i != num_words) 
{ 
    /* it didn't allocate */ 
} 

Esto se obtiene una matriz de dos dimensiones, donde cada elemento words[i] puede tener un tamaño diferente, puede determinar en tiempo de ejecución, así como el número de palabras es.

Tendrá que free() toda la memoria resultante mediante un bucle sobre la matriz cuando haya terminado con él:

for (i = 0; i < num_words; i++) 
{ 
    free(words[i]); 
} 

free(words); 

Si no, vamos a crear una pérdida de memoria.

También podría usar calloc. La diferencia está en convención y efecto de llamada: calloc inicializa toda la memoria en 0, mientras que malloc no.

Si necesita cambiar el tamaño en tiempo de ejecución, use realloc.


también, importante, Cuidado con el word_size + 1 que he utilizado. Las cadenas en C tienen terminación cero y esto requiere un carácter adicional que debe tener en cuenta. Para asegurarme de que recuerdo esto, generalmente establezco el tamaño de la variable word_size en cualquier tamaño de la palabra (la longitud de la cadena como espero) y dejo explícitamente el +1 en el malloc para el cero. Entonces sé que el búfer asignado puede tomar una cadena de word_size caracteres. No hacer esto también está bien, solo lo hago porque me gusta explicar explícitamente el cero de una manera obvia.

También hay una desventaja en este enfoque: he visto explícitamente esto como un error enviado recientemente. Aviso que escribí (word_size+1)*sizeof(type) - imagine sin embargo que había escrito word_size*sizeof(type)+1. Para sizeof(type)=1, estas son la misma cosa, pero Windows usa wchar_t con mucha frecuencia, y en este caso reservará un byte para su último cero en lugar de dos, y son elementos terminados en cero del tipo type, no solo cero bytes. Esto significa que se sobrepasará en lectura y escritura.  

Adición: hazlo como quieras, solo ten cuidado con esos terminadores cero si vas a pasar el búfer a algo que depende de ellos.

+0

Tu terminología parece un poco confusa aquí. Esperaría que num_words == 2 implica que debería haber dos palabras y palabras [0] y las palabras [1] las contienen. Debería entonces malloc (num_words * sizeof (char *)). –

+0

@Sam tienes razón. Creo que lo dije con respecto al +1 para dar cuenta del cero terminador. Reparar :) –

+0

¿De dónde viene la variable 'num_words'? –

1

Si tiene la intención de utilizar C++, STL es muy útil para una asignación dinámica y es muy fácil. Puede utilizar std :: vector ..

+0

yo no entiendo. std :: vector ??? Soy un principiante que usa la Programación C en Windows. Amablemente explícame un poco más. – Rafay

+0

Entonces olvídese de STL si está programando en C. Siga el enlace de John Boker – Mahesh

0
char ** words = malloc(1000 * sizeof(char *)); 
int i; 
for(i = 0 ; i < 1000 ; i++) 
    *(words+i) = malloc(sizeof(char) * 15); 

//.... 
for(i = 0 ; i < 1000 ; i++) 
    free(*(words+i)); 

free(words); 
+1

. Necesita agregar una ubicación de memoria extra a char para mantener '\ 0' al final. ¿No es así? – Mahesh

7

Mientras que Ninefingers proporcionó an answer using an array of pointers, también puede usar una matriz de matrices, siempre que el tamaño del conjunto interno sea una expresión constante. El código para esto es más simple.

char (*words)[15]; // 'words' is pointer to char[15] 
words = malloc (num_words * sizeof(char[15]); 

// to access character i of word w 
words[w][i]; 

free(words); 
+0

¿Esta variable 'num_words' que veo en todas partes significa que tenemos que dar una longitud a la matriz y que simplemente estamos asignando memoria a cada elemento a través de malloc? ¿No estamos ampliando dinámicamente el tamaño de la matriz solo con cada elemento? –

1

Si el 15 en su ejemplo es variable, utilice una de las respuestas disponibles (de Ninefingers o John Boker o Muggen). Si el 1000 es variable, utilice realloc:

words = malloc(1000 * sizeof(char*)); 
// ... read 1000 words 
if (++num_words > 1000) 
{ 
    char** more_words = realloc(words, 2000 * sizeof(char*)); 
    if (more_words) {printf("Too bad");} 
    else {words = more_words;} 
} 

En mi código anterior, la constante 2000 es una simplificación; se debe añadir otra variable capacity para soportar más de 2000 palabras:

if (++num_words > capacity) 
{ 
    // ... realloc 
    ++capacity; // will reallocate 1000+ words each time; will be very slow 
    // capacity += 1000; // less reallocations, some memory wasted 
    // capacity *= 2; // less reallocations but more memory wasted 
} 
0

En C moderna (C99) tiene una opción adicional, las matrices de longitud variable, VLA, como la que:

char myWord[N]; 

En En principio, también podría hacer tal cosa en dos dimensiones, pero si sus tamaños son demasiado grandes, puede arriesgarse a un desbordamiento de pila. En su caso lo más fácil sería utilizar un puntero a una matriz tal y usar malloc/realloc a cambiar su tamaño:

typedef char Word[wordlen]; 
size_t m = 100000; 

Word* words = malloc(m * sizeof(Word)); 
/* initialize words[0]... words[m-1] here */ 
for (size_t i = 0; i < m; ++i) words[i][0] = '\0'; 

/* array is too small? */ 
m *= 2; 
void *p = realloc(words, m*sizeof(Word)); 
if (p) words = p; 
else { 
/* error handling */ 
} 
. 
free(words); 

Este código debe trabajar (módulo errores tipográficos) si wordlen es una constante o una variable, siempre y cuando mantengas todo dentro de una función.Si desea colocar en una función que debe declarar su función algo así como

void myWordFunc(size_t wordlen, size_t m, char words[m][wordlen]); 

es decir, los parámetros de longitud deben llegar primero en ser conocido por la declaración de words.

1

Si está trabajando en C:

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

#define WORD_LEN 15 

int resizeArray(char (**wordList)[WORD_LEN], size_t *currentSize, size_t extent) 
{ 
    int result = 1; 
    char (*tmp)[WORD_LEN] = realloc(*wordList, 
           (*currentSize + extent) * sizeof **wordList); 
    if (tmp) 
    { 
    *currentSize += extent; 
    *wordList = tmp; 
    } 
    else 
    result = 0; 

    return result; 
} 

int main(void) 
{ 
    char *data[] = {"This", "is", "a", "test", 
        "of", "the", "Emergency", 
        "Broadcast", "System", NULL}; 
    size_t i = 0, j; 
    char (*words)[WORD_LEN] = NULL; 
    size_t currentSize = 0; 

    for (i = 0; data[i] != NULL; i++) 
    { 
    if (currentSize <= i) 
    { 
     if (!resizeArray(&words, &currentSize, 5)) 
     { 
     fprintf(stderr, "Could not resize words\n"); 
     break; 
     } 
    } 
    strcpy(words[i], data[i]); 
    } 

    printf("current array size: %lu\n", (unsigned long) currentSize); 
    printf("copied %lu words\n", (unsigned long) i); 

    for (j = 0; j < i; j++) 
    { 
    printf("wordlist[%lu] = \"%s\"\n", (unsigned long) j, words[j]); 
    } 

    free(words); 

    return 0; 
} 
Cuestiones relacionadas