[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