Array de cadenas por teclado en C

Iniciado por Raymond Carver, 11 Junio 2014, 19:27 PM

0 Miembros y 1 Visitante están viendo este tema.

Raymond Carver

Hola, soy un principiante de programación en C (no se nada de C++) y ya me hacía falta conseguir un foro para poder despejar dudas. Les ruego tengan paciencia.

La cuestión es que aprendí a hacer arrays de cadenas pero no logro que me las tome por teclado usando un solo array de caracteres, y de echo es bastante curioso el resultado que me da.

Pongo el caso en que la salida es la esperada, usando tres arrays para capturar las cadenas:
#include <stdio.h>

int main()
{char *a[2];
char letra0[50];
char letra1[50];
char letra2[50];

a[0]=gets(letra0);

a[1]=gets(letra1);

a[2]=gets(letra2);

printf("a[0]=%s  \n",a[0]);
printf("a[1]=%s  \n",a[1]);
printf("a[2]=%s  \n",a[2]);
}


Compilo, le ingreso como datos "cadena0", "cadena1", "cadena2", y como resultado obtengo:
a[0]=cadena0
a[1]=cadena1
a[2]=cadena2
Lo cual es perfectamente lo esperado.

Ahora en cambio uso solo el array "letra" para capturar el ingreso, de esta forma:
#include <stdio.h>

int main()
{char *a[2];
char letra[50];

a[0]=gets(letra);

a[1]=gets(letra);

a[2]=gets(letra);

printf("a[0]=%s  \n",a[0]);
printf("a[1]=%s  \n",a[1]);
printf("a[2]=%s  \n",a[2]);
}

Ahora compilo, le ingreso los mismo que en el caso anterior, pero el resultado es:
a[0]=cadena2
a[1]=cadena2
a[2]=cadena2
O sea, en todas las posiciones de a me asignó el último ingreso. Realmente me desconcierta. Si hubiese copiado el primer ingreso, tal vez sospecharía que el problema es con el gets (de echo lo probé con scanf y pasa lo mismo), pero ¿¿¿el último??? O sea, no entiendo como al pedir el último dato, haciendo a[2]=gets(letra) puede ser que a lo que toma desde el teclado lo asigne a los tres a sin llamar a la asignación.

Desde ya muchas gracias al que me ayude.

JorgeEMX

Es normal, ya que lo que está guardando gets es lo último que escribiste. En todo caso, deberías usar arreglos multidimensionales:


#include <stdio.h>

int main()
{
        char letra[2][100];

        gets(letra[0]);

        gets(letra[1]);

        gets(letra[2]);

        printf("letra[0]=%s  \n",letra[0]);
        printf("letra[1]=%s  \n",letra[1]);
        printf("letra[2]=%s  \n",letra[2]);
}

Raymond Carver

#2
Claro, así también lo podría haber pensado, pero yo quería hacerlo con un array de cadenas y un array de caracteres.

O sea, no entiendo por qué en la forma en que lo hice no lo toma. Por ejemplo, cuando hago:

1- a[0]=gets(letra);

2- a[1]=gets(letra);

En 1, ¿no estaría tomando la entrada del teclado, y asignándosela a a[0]?
Haciendo letra="cadena desde el teclado"
             a[0]=letra

En 2, ¿no tomaría una segunda entrada y asignándosela a a[1]?
Haciendo letra="nueva cadena desde el teclado"
             a[1]=letra

Acá lo modifiqué un poco a lo que había echo. Lo pruebo y me muestra correctamente los datos luego de cada pedido, pero mal al final. O sea, al principio pido que se escriba "cadena0", se asigna a letra, se asigna letra a a[0], y se muestran letra y cadena[0] correctamente. Se hace eso con las tres a. Pero al final cuando las imprime todas las muestra como "cadena2" a las tres (o sea, la última entrada escrita). No llego a entender por qué reescribe las dos primeras a.
#include <stdio.h>

int main()
{char *a[2];
char letra[50];

puts("Ingrese cadena0:");
a[0]=gets(letra);
puts(letra);
printf("a[0]=%s \n\n",a[0]);

puts("Ingrese cadena1:");
a[1]=gets(letra);
puts(letra);
printf("a[1]=%s \n\n",a[1]);

puts("Ingrese cadena2:");
a[2]=gets(letra);
puts(letra);
printf("a[2]=%s \n\n",a[2]);

puts("Ahora mostramos todos los a");
printf("a[0]=%s  \n",a[0]);
printf("a[1]=%s  \n",a[1]);
printf("a[2]=%s  \n",a[2]);
}

JorgeEMX

Tiene que ver con el manejo de punteros, al final... los 3 punteros de "a" terminan apuntando al mismo valor de "letra".

leosansan

#4
Cita de: Raymond Carver en 11 Junio 2014, 21:04 PM
........................................

Acá lo modifiqué un poco a lo que había echo. Lo pruebo y me muestra correctamente los datos luego de cada pedido, pero mal al final. O sea, al principio pido que se escriba "cadena0", se asigna a letra, se asigna letra a a[0], y se muestran letra y cadena[0] correctamente. Se hace eso con las tres a. Pero al final cuando las imprime todas las muestra como "cadena2" a las tres (o sea, la última entrada escrita). No llego a entender por qué reescribe las dos primeras a.
...........................


Como tan acertadamente apunta JorgeEMX los tres  punteros "a" apuntan a la dirección de "letra" y a medida que introduces un nuevo valor de "letra" con gets estas "actualizando" la dirección, y por tanto el valor al que apuntan, de los punteros anteriores.

Lo veras mejor si imprimes el puntero del gets y los anteriores. De esa manera veras mejor como se actualizan cada vez que usas el gets los valores a los que apuntan  los punteros:

Código (cpp) [Seleccionar]
#include <stdio.h>

int main(){
 char *a[2];
 char letra[50];
 puts("Ingrese cadena0:");
 a[0]=gets(letra);
 printf("a[0]=%s  \n",a[0]);
 
 puts("Ingrese cadena1:");
 a[1]=gets(letra);
 printf("a[0]=%s  \n",a[0]);
 printf("a[1]=%s  \n",a[1]);

 puts("Ingrese cadena2:");
 a[2]=gets(letra);
 printf("a[0]=%s  \n",a[0]);
 printf("a[1]=%s  \n",a[1]);
 printf("a[2]=%s  \n",a[2]);
 return 0;
}


Citar
Ingrese cadena0:
111
a[0]=111
Ingrese cadena1:
222
a[0]=222
a[1]=222
Ingrese cadena2:
333
a[0]=333
a[1]=333
a[2]=333

Process returned 0 (0x0)

Como ves los valores se han ido actualizando en cada gets.

¡¡¡¡ Saluditos! ..... !!!!



Raymond Carver

Claro claro, ahora entiendo donde está el error. Cuando hago a[0]=gets(letra) no le estoy asignando al puntero el valor de "letra" (en este caso sería la cadena), sino que le estoy asignando su dirección de memoria. Son punteros, no guardan valores, guardan direcciones.

Son esas cosas que uno supuestamente ya sabe pero hasta que no se equivoca mil veces no se acostumbra a tener en cuenta.

¡Muchas gracias por ayudarme!

rir3760

Solo para redondear el tema:

1) Cuando se declara un array se indica el numero de elementos y se accede a ellos mediante los indices 0 .. N-1 ya que en C los indices inician en cero. Con esta declaración:
char *a[2];
Declaras un array de dos elementos y se accede a ellos mediante los indices 0 y 1, al utilizar en el programa "a[2]" este puede reventar (comportamiento no definido).

2) No tiene caso (ya que no hay validaciones) almacenar el valor de retorno de la función gets ya que esta retorna el argumento pasado o bien NULL en caso de error.

3) No se recomienda el uso de gets, si apenas empiezas tu aprendizaje del lenguaje C por favor lee el tema |Lo que no hay que hacer en C/C++. Nivel basico|.

Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language