matriz leer imprimir funciones caracteres cadenas cadena arreglo c arrays char

leer - matriz de caracteres en c



AsignaciĆ³n de memoria para la matriz de caracteres (5)

¿Cómo puedo anunciar la matriz y luego definir su tamaño?

No; ''anúncialo'' cuando sepas qué tamaño necesita ser. No puedes usarlo antes de todos modos.

En C99 y posteriores, puede definir variables cuando sea necesario, en cualquier lugar de un bloque de instrucciones. También puede usar VLA (arrays de longitud variable) donde el tamaño no se conoce hasta el tiempo de ejecución. No cree matrices enormes como VLA (por ejemplo, 1 MiB o más), pero ajuste el límite para adaptarse a su máquina y los prejuicios); utilice la asignación de memoria dinámica después de todo.

Si está atascado con el estándar arcaico C89 / C90, entonces solo puede definir variables al inicio de un bloque, y las matrices tienen tamaños conocidos en tiempo de compilación, por lo que debe utilizar la asignación de memoria dinámica - malloc() , free() etc.

Tengo un gran problema con el lenguaje C cuando se trata de cadenas, char * o lo que sea ... Entonces, en este caso particular, tengo un gran problema. Quiero crear una matriz de caracteres y aún no sé qué tamaño tendrá. Quiero escribir algo como esto:

char test[];

Pero, después de eso, cuando sepa cuántos elementos habrá, quiero escribir algo como esto:

char test[num_of_elements];

aunque sé que está mal y que no podría hacer eso. Entonces, ¿cómo puedo hacer esto? ¿Cómo puedo anunciar la matriz y luego definir su tamaño?


Hay dos formas de resolver este problema.

Método n. ° 1: use un tamaño máximo para definir su matriz. Así es como se ve el código:

char test[max_size];

Luego necesita realizar un seguimiento de cuántos elementos se han agotado realmente. Esto se usa comúnmente en algún código de red de la vieja escuela.

Método n. ° 2: use memoria dinámica. Tenga en cuenta que hay un poco de un problema de rendimiento aquí (potencialmente) ya que tiene que preguntar al sistema operativo cada vez por un pedazo de memoria. Ya hay una respuesta aquí que te muestra cómo hacer esto. Solo asegúrese de llamar a free () una vez que haya terminado de usar su matriz.


Primero declara un puntero a un "char". Luego solicite (al sistema) espacio para almacenar su número requerido de valores usando malloc y luego agregue elementos a esta "matriz".

char * test; int num_of_elements = 99; test = malloc(sizeof(char) * num_of_elements); //test points to first array elament test[0] = 11; test[1] = 22; //etc


Según su (i) cadena de herramientas y (ii) cómo y cuándo conocerá el tamaño, tiene la opción de utilizar (a) Arrays de longitud variable o (b) funciones de Asignación dinámica de memoria.

if (tool-chain admite C99 y posterior) o (usted sabrá la longitud de la matriz en tiempo de ejecución) use Array de longitud variable

if (cadena de herramientas antigua) o (si desea la flexibilidad de asignar y liberar la memoria) utilice la función de asignación de memoria dinámica

aquí hay muestras

1 matriz de longitud variable

void f(int m, char C[m][m]) { char test[m]; : }

o

2 usando la función Dynamic Allocation Memory

void somefunc(int n) { char *test; test = malloc (n * sizeof (char)); // check for test != null // use test free (test); }

se puede escribir usando VLA como

int n = 5; char test[n];


Declaración de matrices de caracteres estáticos (cadenas)

Cuando sepa (o tenga una idea razonable de qué tan grande debe ser su matriz, puede simplemente declarar una matriz de tamaño suficiente para manejar su entrada (es decir, si sus nombres no tienen más de 25 caracteres, entonces podría declarar el name[26] manera segura name[26] . Para las cadenas, siempre necesita al menos el number of chars to store + 1 (para el carácter de terminación nula).

Si puede haber unos pocos caracteres de más de 25, no hay nada de malo en declarar que la matriz contiene pocos bytes más de lo necesario para proteger contra la escritura accidental más allá del final de la matriz. Di name[32] .

Declaremos una matriz de 5-characters continuación y observemos cómo se almacena la información en la memoria.

char name[5] = {0}; /* always initialize your arrays */

La declaración anterior crea una matriz de 5-contiguous bytes en la pila para su uso. por ejemplo, puede visualizar los 5 bytes de memoria inicializados en cero de la siguiente manera:

+---+---+---+---+---+ name | 0 | 0 | 0 | 0 | 0 | +---+---+---+---+---+ / ''name'' holds the starting address for the block of memory that is the array (i.e. the address of the first element like: 0x7fff050bf3d0)

Nota: cuando se utiliza el name para contener una ''cadena de caracteres'', la cadena real no puede tener más de 4 caracteres, porque debe terminar una picadura con un carácter de terminación nula , que es el carácter nulo ''/0'' (o simplemente numérico) 0 , ambos son equivalentes)

Para almacenar información en name , puede hacerlo asignando caracteres uno por vez :

name[0] = ''J''; name[1] = ''o''; name[2] = ''h''; name[3] = ''n''; name[4] = 0; /* null-terminate. note: this was already done by initialization */

En memoria ahora tienes:

+---+---+---+---+---+ name | J | o | h | n | 0 | /* you actually have the ASCII value for */ +---+---+---+---+---+ /* each letter stored in the elements */

Por supuesto, nadie asigna un personaje a la vez de esta manera. Sus opciones son muchas, usando una de las funciones provistas por C, por ej. strcpy , strncpy , memcpy , o leyendo información de un flujo de archivos, o un descriptor de archivo con fgets , getline , o usando un loop simple y una index variable para hacer el asignación, o mediante el uso de una de las funciones de formateo de cadenas, por ejemplo, sprintf , etc ... Por ejemplo, puede lograr lo mismo con cualquiera de los siguientes:

/* direct copy */ strcpy (name, "John"); strncpy (name, "John", 5); memcpy (name, "John", sizeof "John"); /* include copy of the terminating char */ /* read from stdin into name */ printf ("Please enter a name (4 char max): "); scanf ("%[^/n]%*c", name);

Nota: arriba con strncpy , si NO has inicializado todos los elementos a 0 (el último de los cuales servirá como tu carácter de null-terminating , y luego strncpy (name, "John", 4); tendrías que terminar manualmente el cadena con name[4] = 0; contrario, no tendría una cadena válida (tendría una matriz de caracteres sin terminar que daría lugar a undefined behavior si utilizara el name donde se esperaba una cadena).

Si no comprende explícitamente esta PARADA , lea y comprenda qué es una null-terminated string y cómo difiere de una array of characters . En serio, deténgase ahora y vaya a aprender, es fundamental para C. (si no termina con un carácter de null-terminating , no es una cadena de caracteres).

¿Qué sucede si no sé cuántos caracteres necesito almacenar?

Asignaciones dinámicas de cadenas de caracteres

Cuando no sabe cuántos caracteres necesita almacenar (o, en general, cuántos de cualquier tipo de datos), el enfoque normal es declarar un puntero para escribir y luego asignar una cantidad de memoria razonablemente anticipada (solo en función de su mejor comprensión) de lo que está tratando), y luego reasignar para agregar memoria adicional según sea necesario . No tiene magia, es solo una forma diferente de decirle al compilador cómo administrar la memoria. Solo recuerde, cuando asigna la memoria, la posee. Usted es responsable de (1) preservar un puntero a la dirección inicial del bloque de memoria (para que pueda ser liberado más adelante); y (2) liberar la memoria cuando haya terminado con ella.

Un simple ejemplo ayudará. La mayoría de las funciones libres / asignación de memoria se declaran en stdlib.h .

char *name = NULL; /* declare a pointer, and initialize to NULL */ name = malloc (5 * sizeof *name); /* allocate a 5-byte block of memory for name */ if (!name) { /* validate memory was allocated -- every time */ fprintf (stderr, "error: name allocation failed, exiting./n"); exit (EXIT_FAILURE); } /* Now use name, just as you would the statically declared name above */ strncpy (name, "John", 5); printf (" name contains: %s/n", name); free (name); /* free memory when no longer needed. (if reusing name, set ''name = NULL;'') */

Nota: malloc NO inicializa el contenido de la memoria que asigna. Si desea inicializar su nuevo bloque de memoria con cero (como hicimos con la matriz estática), entonces use calloc lugar de malloc . También puede usar malloc y luego llamar a memset también.

¿Qué sucede si asigno memoria y luego necesito más?

Como se mencionó anteriormente sobre la memoria dinámica, el esquema general es asignar una cantidad anticipada razonable, luego realloc según sea necesario. Utiliza realloc para reasignar el bloque de memoria original creado por malloc . realloc esencialmente crea un nuevo bloque de memoria, copia la memoria de su antiguo bloque a la nueva, y luego libera el antiguo bloque de memoria. Dado que se libera el antiguo bloque de memoria, desea utilizar un puntero temporal para la reasignación. Si la reasignación falla, todavía tiene su bloque original de memoria disponible para usted.

Puede agregar la menor o la mayor cantidad de memoria que desee en cualquier llamada a realloc . El esquema estándar generalmente visto es comenzar con una asignación inicial, luego reasignar el doble de esa cantidad cada vez que se agota. (el medio que necesita para realizar un seguimiento de la cantidad de memoria asignada actualmente).

Para coser esto, terminemos con un ejemplo simple que simplemente lee una cadena de cualquier longitud como primer argumento del programa (use " comillas " si su cadena contiene espacios en blanco). A continuación, asignará espacio para contener la cadena, luego reasignará para agregar más texto al final de la cadena original. Finalmente, liberará toda la memoria en uso antes de salir:

#include <stdio.h> #include <stdlib.h> #include <string.h> int main (int argc, char **argv) { if (argc < 2) { /* validate input */ fprintf (stderr, "error: insufficient input. usage: %s /"name/"/n", argv[0]); return 1; } size_t len = strlen (argv[1]); /* length of input */ size_t sz_mem = len + 1; /* memory required */ char *name = malloc (sz_mem * sizeof *name); /* allocate memory for name */ if (!name) { /* validate memory created successfully or throw error */ fprintf (stderr, "error: virtual memory exhausted allocating ''name''/n"); return 1; } printf ("/n allocated %zu bytes of memory for ''name''/n", sz_mem); memset (name, 0, sz_mem); /* initialize memory to zero (optional) */ strncpy (name, argv[1], sz_mem); /* copy the null-terminator as well */ printf (" name: ''%s'' (begins at address: %p)/n", name, name); /* realloc - make name twice as big */ void *tmp = realloc (name, 2 * sz_mem); /* use a temporary pointer */ if (!tmp) { /* check realloc succeeded */ fprintf (stderr, "error: virtual memory exhausted, realloc ''name''/n"); return 1; } memset (tmp + sz_mem, 0, sz_mem * sizeof *name); /* zero new memory */ name = tmp; /* assign new block to name */ sz_mem += sz_mem; /* update current allocation size */ printf (" reallocated ''name'' to %zu bytes/n", sz_mem); strncat (name, " reallocated", sizeof " reallocated"); printf ("/n final name : ''%s''/n/n", name); free (name); return 0; }

Uso / Salida

$ ./bin/arraybasics "John Q. Public" allocated 15 bytes of memory for ''name'' name: ''John Q. Public'' (begins at address: 0xf17010) reallocated ''name'' to 30 bytes final name : ''John Q. Public reallocated''

Comprobación de memoria

Cuando asigna dinámicamente memoria, depende de usted validar que está utilizando la memoria correctamente y que rastrea y libera toda la memoria que asigna. Use un corrector de errores de memoria como valgrind para mejorar el uso correcto de la memoria. (No hay excusa para no hacerlo, es muy fácil de hacer) Simplemente escriba valgrind yourprogramexe

$ valgrind ./bin/arraybasics "John Q. Public" ==19613== Memcheck, a memory error detector ==19613== Copyright (C) 2002-2012, and GNU GPL''d, by Julian Seward et al. ==19613== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info ==19613== Command: ./bin/arraybasics John/ Q./ Public ==19613== allocated 15 bytes of memory for ''name'' name: ''John Q. Public'' (begins at address: 0x51e0040) reallocated ''name'' to 30 bytes final name : ''John Q. Public reallocated'' ==19613== ==19613== HEAP SUMMARY: ==19613== in use at exit: 0 bytes in 0 blocks ==19613== total heap usage: 2 allocs, 2 frees, 45 bytes allocated ==19613== ==19613== All heap blocks were freed -- no leaks are possible ==19613== ==19613== For counts of detected and suppressed errors, rerun with: -v ==19613== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

En la salida, las siguientes líneas son de particular importancia:

==19613== HEAP SUMMARY: ==19613== in use at exit: 0 bytes in 0 blocks ==19613== total heap usage: 2 allocs, 2 frees, 45 bytes allocated

Esto le dice que toda la memoria asignada durante su programa se ha liberado correctamente. (asegúrese de cerrar todas las secuencias de archivos abiertas, también se asignan dinámicamente).

De igual importancia es el ERROR SUMMARY :

==19613== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

No hay errores en el uso de la memoria. Si intenta leer, escribir o liberar memoria desde una ubicación fuera de su bloque, o desde una ubicación unificada o que dejaría la memoria inalcanzable, esa información se mostrará como un error.

(Suprimido: 2 de 2 solo se relacionan con bibliotecas de depuración adicionales que no están presentes en mi sistema)

Esto terminó más tiempo de lo previsto, pero si ayuda, valió la pena. Buena suerte.