[C con Clase] Array de cadenas de caracteres y p aso de paráme tros en C.

srd4121 en njit.edu srd4121 en njit.edu
Dom Dic 14 12:23:00 CET 2008


Hola Carlos,

Mensaje citado por: gmh2000 <helder1986 en gmail.com>:

> Steven, yo no entiendo que Rolando quiera decir que su código es
> incorrecto, sino que se le olvidó reservar memoria para la nueva cadena.

Lo siento, pero el mismo Rolando lo dijo, y cito textualmente:

"Lo único que le veo mal es que estas volviendo a declarar el arreglo PCHAR11* 
file_names.string_pointers ahí el PCHAR11* es innecesario."

Ahora bien, releyendo lo que dije, veo que sí puedes pensar que yo estaba 
diciendo que el código de Rolando estaba mal, pero no era eso lo que quería 
decir. Simplemente, dije lo mismo que Rolando, pero me expresé de otra manera, 
acerca de la declaración del campo 'string_pointers' que tú hiciste. Es decir, 
deberías haber hecho esto:

PCHAR11 string_pointers;

que viene a ser lo mismo que hacer esto,

char (*string_pointers)[11];

Si declaras 'string_pointers' como un puntero a 'PCHAR11', entonces tienes que 
crear memoria para 'string_pointers' al igual que memoria para la lista de 
punteros a 'char[11]'. Es decir, tienes un doble puntero a un array
que viene a ser lo siguiente.

PCHAR11 *string_pointers;

es equivalente a:

char (**string_pointers)[11];

Por esta razón, Rolando te dice que es innecesario, porque tienes otro nivel 
de indirección que no te sirva para nada excepto "amargarte la vida".

> Si está mal corrígenos, pues yo también lo veo bien para mi caso, en el
> que casi todas las cadenas son de 10 caracteres (más el /0), y ninguna

Si sabes que 11 es la longitud máxima, entonces adelante con esta idea de 
crear un array dinámico a un array "estático". La otra posibilidad que te di 
era para que tuvieras mayor control acerca de las cantidadesde cada cadena.

> mide más de 10. A partir de ahí reescribo el código comentándolo según
> lo aprendido. Por favor, si tengo algún concepto incorrecto díganmelo.
> Ahí va:
> 
> 
> typedef char (*PCHAR11)[11];
> 
> struct string_list
> {
>   PCHAR11* string_pointers;

Como hemos dicho, deberías declarar este campo así:

PCHAR11 string_pointers;

>   unsigned int number_of_strings;
> } file_names;
> 
> 
> ... add_cadena()
> {
> 
> /* Ahora necesitamos un "índice" más a la cadena que vamos a añadir.
> Incrementamos memoria para poder almacenar este puntero a cadena de 11
> */
> 
> file_names.string_pointers = (PCHAR11*)
> realloc(file_names.string_pointers, ++file_names.number_of_strings *
> sizeof(PCHAR11) );
> 

Esto no es correcto. Estamos creando memoria para una lista (como un array) de 
cadenas. Esto es,

file_names.string_pointers = (PCHAR11) realloc(file_names.string_pointers,
++file_names.number_of_strings * sizeof(CHAR11) );

He aquí la razón de definir 'CHAR11'.


Si no se trata de un array tan grande, entonces puedes usar esta solución. Eso 
sí, ten presente que estás creando un solo bloque de múltiplos de 11 bytes. Es 
decir, cada vez que agregas una cadena, el sistema operativo tiene que 
encontrar un solo bloque contiguo de 11 bytes más que la cantidad original. Si 
quieres expresar lo que ocurre algebraicamente, tenemos esta cantidad total:

11*n,  donde 'n' es la cantidad de cadenas

Sé que hoy en día los SS.OO. disponen de mucha memoria, pero intenta tener las 
cantidades presentes. La otra ventaja de la solución que te di es que puedes 
reducir la cantidad de bloques al crear la memoria dinámicamente, ya que cada 
petición de memoria es independiente a las otras. Es más fácil encontrar 
bloques de memoria de cantidades pequeñas de cantidades más grandes.

> 
> /* Reservamos memoria para la nueva cadena de caracteres, esto es,
> desreferenciamos la antigua dirección de memoria a un espacio que esté
> vacío (lo gestiona el sistema operativo). */
> file_names.string_pointers[file_names.number_of_strings - 1] = (char *)
> malloc(11 * sizeof(char));
> 

Esto sería correcto, para la solución que yo te di, pero como estás usando un 
puntero a un array, esta sentencia ya no es necesaria.

> /* Nota: no hago tu strlen(szNombre)+1 porque no me vale la pena el
> conste computacional de calcular la longitud vs memoria desperdiciada
> */
> 
> /* Ahora sólo quedaría copiar la nueva cadena */
> strcpy(file_names.string_pointers[file_names.number_of_strings - 1],
> "nueva_cadena");

Aconsejo usar 'strncpy()' para no sobrepasar los límites del array de 11 
caracteres. Incluso podrías usar 'memcpy()' para copiar 10 caracteres y luego 
agregar el carácter nulo al final explícitamente.

> 
> }
> 
> 
> __________
> Haber si eso ya está bien. No lo puedo probar yo mismo en mi compilador
> porque los fines de semana voy para mi pueblo y aquí no tengo el
> tinglado necesario.
> 

¿No tenéis ordeñador en el pueblo? :P  Lo siento, no pude resistir la 
tentación de escribir este chiste tan malo :)


Bueno, espero que lo anterior aclare un poco las cosas.

Steven





Más información sobre la lista de distribución Cconclase