[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
Sab Dic 13 12:21:52 CET 2008


Hola gmh,

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

> Steven, te agradezco mucho tan cuidada respuesta. Ya sólo se me quedan
> un par de cables sueltos. Esto es:
> 

De nada; para eso estamos. Veamos las dudas.

> PRIMERO:
> ¿Las constantes no se guardan en memoria como las variables? En algún
> lado tienen que guardarse, ¿no?

Esto depende. Si el compilador lo ve oportuno o necesario, entonces sí trata 
las constantes definidas como variables y por tanto ocupan memoria. Sin 
embargo, si el compilador decide que la constante definida no merece ocupar 
memoria entonces simplemente copia el valor de la constante "in situ" donde se 
necesite. Por ejemplo,

const int NPORDEFECTO = 10;
const int NMAX = 25;

int main()
{
  int *lista[NMAX];

  lista[0] = &NPORDEFECTO;

  return 0;
}

Aquí, el compilador sí trataría la constante, 'NPORDEFECTO', como una 
variable, porque el programa requiere su dirección de memoria. Sin embargo, el 
compilador seguramente tratará la constante, 'NMAX', como una constante, sin 
crear ni mantener memoria para ella. El resultado sería algo así,

const int NPORDEFECTO = 10;

int main()
{
  int *lista[25];

  lista[0] = &NPORDEFECTO;

  return 0;
}

> ¿szNombre = szNombre[0]? No es más bien: szNombre = &szNombre[0] y
> quizás también ¿*szNombre = szNombre[0]?
> 

Cierto, pero no estaba usando C++ estrictamente al escribir:

Dirección
de Memoria   Tipo   Nombre   Valor
---------------------------------------
0x33DDAA00   char   ----     'J'     // szNombre = szNombre[0]

Sólo quería expresar que la cadena, 'szNombre', realmente no existe como tal; 
sólo está el primer carácter del array.

Efectivamente, en C++, escribiríamos algo así,

szNombre == &szNombre[0]

o incluso,

*szNombre == szNombre[0]

pero creo que esto es algo trivial, que no merece mayores explicaciones.

> 
> SEGUNDO:
> He hecho uso de las soluciones que me habeis planteado tanto Rolando
> como tú que, aunque no lo veo completamente claro, supongo que son
> equivalentes en cuanto a la cantidad de memoria reservada.
> 
> Código Rolando, simplificado (no del todo correcto por ello):
> typedef char (*PCHAR11)[11];
> 
> struct string_list
> {
>   PCHAR11* string_pointers; 
>   unsigned int number_of_strings;
> } file_names;
> 
> PCHAR11* Temp = (PCHAR11*)malloc(++file_names.number_of_strings *
> sizeof(PCHAR11));
> /* Antes de hacer lo siguiente añadiríamos la nueva cadena */
> file_names.string_pointers = Temp;
> 
> 

Bueno, Rolando te ha explicado en un su contestación que definir y 
usar 'PCHAR11' de esta manera no es correcto. En todo caso, podrías haber 
hecho esto,

typedef char CHAR11[11];
typedef CHAR11 *PCHAR11;
...
PCHAR11 string_pointers;  // = CHAR11 *string_pointers;

y luego,

PCHAR11 Temp = (PCHAR11) malloc( ++file_names.number_of_strings * sizeof
(CHAR11));

> 
> 
> Tu código (comento también un par de dudas):
> 
> /* En la siguiente línea no entiendo muy bien porqué hay que reservar
> memoria
>  ¿Hay que reservar "x" punteros a cadena? No lo veo muy claro */
> 
> file_names.pLista = (char **) realloc( file_names.pLista,
> ++file_names.number_of_strings*sizeof(char *) );

Correcto. Agrandamos el array dinámico de punteros y por tanto agrandamos la 
cantidad de cadenas a ser apuntadas.

> /* Obviamente tampoco entiendo porqué hay que hacer, en el caso de
> cuando tenemos,
>      por ejemplo, 4 cadenas: file_names.pLista = (char **) malloc(
> 4*sizeof(char *) ); */
> 

Creamos un array dinámico de 4 punteros.

> file_names.pLista[file_names.number_of_strings-1] = (char *) malloc(
> strlen(szNombre)+1 );
> 

Creamos un array dinámico para una cadena de caracteres, cuya dirección de 
memoria es guardada en el último elemento del array dinámico de punteros.


Para que entiendas mejor lo que estamos haciendo, intentaré explicártelo con 
algunos ejemplos "reales". Piensa en cualquier libro que hayas visto o tengas 
a mano. Verás que en las primeras páginas, encontrarás el índice o tabla de 
contenido. En esta lista, tenemos el título de cada capítulo y el número de la 
página donde empieza tal capítulo en el libro.

Nosotros, queremos hacer algo parecido. Tenemos un índice o "directorio" que 
es el array de punteros. Y para cada puntero, guardamos la dirección de 
memoria de cada cadena (el número de la página de cada capítulo).

Si lo prefieres, intentaré explicártelo visualmente:

+---------+
| pLista: |
+---------+
+---------+   +-----------+
|    0    |-->|  "Juan"   |
+---------+   +-----------+
|    1    |-->|  "Pepa"   |
+---------+   +-----------+
|    2    |-->| "Antonio" |
+---------+   +-----------+
|    3    |-->| "Noelia"  |
+---------+   +-----------+

Ahora queremos agregar otra cadena a nuestra lista. Tenemos que agregar otro 
elemento u otra entrada a la lista, y luego apuntar a la cadena que nos 
interesa.

+---------+
| pLista: |
+---------+
+---------+   +-----------+
|    0    |-->|  "Juan"   |
+---------+   +-----------+
|    1    |-->|  "Pepa"   |
+---------+   +-----------+
|    2    |-->| "Antonio" |
+---------+   +-----------+
|    3    |-->| "Noelia"  |
+---------+   +-----------+
|    4    |-->| "Víctor"  |
+---------+   +-----------+

Esto significa que necesitamos memoria cada vez que queramos agregar un nuevo 
elemento. En el caso que yo te di, también tenemos que crear memoria para 
guardar la cadena de caracteres.


Recuerda que un puntero no hace nada más que apuntar; de ahí su nombre. Esto 
implica que la información debe estar guardada en alguna parte en memoria. Si 
la cadena no existe en memoria, entonces tenemos que crear memoria para poder 
guardar la cadena en ella. A su vez, tenemos que crear memoria para nuestro 
array de punteros, para así apuntar a cada cadena.


Espero que todo esto aclare el tema.

Steven





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