[ Foro de C ]

Dudas de los 5 primeros temas

19-Jan-2012 09:28
Carlos García
5 Respuestas

Buenos días,

En primer lugar, mil gracias por el manual de C. He estado buscando y buscando para ver que aprender, y sin duda, es el más divertido y más didáctico de todos los que he encontrado.

Llevo 15 días con la programación, así que soy un novato con todas las de la ley, y como buen novato, tengo un porrón de dudas. Espero no agoviaros con ellas, y de antemano, muchísimas gracias por la ayuda que me podáis prestar.

Disculpad por el macro código que voy a pegar, pero así resumo las dudas que tengo de los 5 primeros temas.

1 Me da un error al construir los structs anidados. ¿Sabríais decirme qué estoy haciendo mal?
2 A la hora de en un gets o en un scanf, no sé como se hace para que tome el dato sin teclear nada, bien para avandonar un programa pulsando simplemente intro, o bien como es en este caso, a la hora de modificar un dato (case 4), poder pulsar intro y que no modifique nada.
3 Este punto no sé si será por mi compilador, o que realmente no sé hacerlo. A la hora de mostrar 25 datos en patnalla (como intento hacer en el case 2) he probado usando getchar, scanf, gets... y no doy con la solución. ¿Qué es lo que se me está escapando? Porque siempre, con todas ellas, solo me aparece la información relativa al último printf.
4 Le he estado dando vueltas a como eliminar la información de una canción, y por lo tanto que todas las introducidas posteriormente se muevan una hacia atrás, y no soy capaz de hacerlo. ¿Podríais decirme como hacerlo?

Lo dicho, 1000 gracias por vuestra ayuda.


El megacódigo:

#include <stdio.h>
#include <string.h>
struct
{
int minutos;
int segundos;
}
tiempo;
struct
{
char artista[20], titulo[30];
struct tiempo duracion;
float peso;
}
cancion[100];
int existeartista= 0;
int existecancion= 0;
int numerocancion=0;
char textotemporal[40];
int i, opcion;
main() {
do
{
printf("Pulse 1 para introucir una nueva cancion.\n");
printf("Pulse 2, para ver la informacion de las canciones.\n");
printf("Pulse 3 para buscar la informacion de un artista o cancion en concreto.\n");
printf("Pulse 4 para modificar la informacion de una cancion.|n");
printf("Pulse 5 para salir.\n");
gets(textotemporal);
sscanf(textotemporal, "%d", &opcion);
switch(opcion)
{
case 1:
if (numerocancion<100)
{
printf("Introduzca el artista.\n");
gets(cancion[numerocancion].artista);
printf("Introduzca el titulo de la cancion.\n");
gets(cancion[numerocancion].titulo);
do
{
printf("Introduzca los minutos de la canción.\n");
gets(textotemporal);
sscanf(textotemporal, "%d", &cancion[numerocancion].duracion.minutos);
}
while (cancion[numerocancion].duracion.minutos<0);
do
{
printf("Y los segundos de la canción.\n");
gets(textotemporal);
sscanf(textotemporal, "%d", &cancion[numerocancion].duracion.segundos);
}
while (cancion[numerocancion].duracion.segundos<0);
do
{
printf("Introduzca el peso de la cancion en megabites.\n");
gets(textotemporal);
sscanf(textotemporal, "%2.2f", &cancion[numerocancion].peso);
}
while (cancion[numerocancion].peso<0);
numerocancion++;
}
else printf("¡Ha alcanzado el limite de almacenamiento!\n");
break;
case 2:
for (i=0; i<=numerocancion; i++)
{
printf("La cancion numero %d se titula: %s, es de %s, dura unos %d minutos y unos %d segundos, y pesa %2.2f megas.\n", i, cancion[i].titulo, cancion[i].artista, cancion[i].duracion.minutos, cancion[i].duracion.segundos, cancion[i].peso);
if ((--i)%25 == 0) gets(textotemporal); /* para que se pause hasta que teclee algo y pase a los siguientes 25 datos */
}
break;
case 3:
printf("Introduzca el titulo de la cancion o el artista a buscar.\n");
gets(textotemporal);
for (i=0; i<=numerocancion; i++)
{
if (strstr (cancion[numerocancion].artista, textotemporal) != NULL)
{
printf("La cancion seleccionada es %s, de %s. Dura unos %d minutos y %d segundos, y pesa unos %2.2f megas.\n", cancion[numerocancion].titulo, cancion[numerocancion].artista, cancion[numerocancion].duracion.minutos, cancion[numerocancion].duracion.segundos, cancion[numerocancion].peso);
existeartista++;
}
else if (strstr (cancion[numerocancion].titulo, textotemporal) != NULL)
{
printf("La cancion seleccionada es %s, de %s. Dura unos %d minutos y %d segundos, y pesa unos %2.2f megas.\n", cancion[numerocancion].titulo, cancion[numerocancion].artista, cancion[numerocancion].duracion.minutos, cancion[numerocancion].duracion.segundos, cancion[numerocancion].peso);
existecancion++;
}
if (existeartista == 0 && existecancion == 0) printf("¡No existen coincidencias!|n");
}
getchar;
break;
case 4:
printf("Introduzca el numero de la cancion a modificar.\n");
gets(textotemporal);
sscanf(textotemporal, "%d", &numerocancion);
printf("Introduzca el artista.\n");
gets(cancion[numerocancion].artista);
printf("Introduzca el titulo de la cancion.\n");
gets(cancion[numerocancion].titulo);
do
{
printf("Introduzca los minutos de la canción.\n");
gets(textotemporal);
sscanf(textotemporal, "%d", &cancion[numerocancion].duracion.minutos);
}
while (cancion[numerocancion].duracion.minutos<0);
do
{
printf("Y los segundos de la canción.\n");
gets(textotemporal);
sscanf(textotemporal, "%d", &cancion[numerocancion].duracion.segundos);

}
while (cancion[numerocancion].duracion.segundos<0);
do
{
printf("Introduzca el peso de la cancion en megabites.\n");
gets(textotemporal);
sscanf(textotemporal, "%2.2f", &cancion[numerocancion].peso);
}
while (cancion[numerocancion].peso<0);
break;
case 5:
printf("Gracias por usar el programa.\n");
break;
default: printf("¡Opcion no valida!\n");
break;
}
}
while (opcion != 5);
}


20-Jan-2012 11:18
Nacho Cabanes (+84)

Veamos...

En primer lugar, algunas recomendaciones:

- En vez de colocar un megacódigo, intenta que sea el fragmento más pequeño posible que muestre el error (pero a la vez, que compile, para que sea fácil de probar).

- Usa espacios en vez de tabulaciones. Así no se descuadrará si cambias de un editor a otro, y se leerá "casi bien" si lo incluyes en el foro.

- Si haces referencia a algún texto (sea mi manual o sea otro), lo ideal es que digas de qué texto hablas: página web, versión del manual, etc. Supondré que hablas de mi manual de C, en su última versión "pública", la 0.90.

- Indica siempre el entorno de desarrollo que utilizas (compilador, sistema operativo, editor o IDE). Ayuda a filtrar los problemas. Yo probaré con el GCC que incluye Linux, en una versión reciente (4.5.2).


Ahora vamos con las primeras soluciones...  ;-)

- Lo de que pulses Intro y no te tome nada se suele deber a que estás mezclando scanf y gets para leer números y cadenas. Cuando lees un número con %d, el "Intro" que pulsas después queda en el buffer del teclado. Si luego intentas leer una cadena, toma ese "Intro" pendiente y la cadena queda vacía.

Hay trucos como hacer

scanf("%d%c", &numero);

Mira la página 72 del manual (versión 0.90) para más detalles.


- El struct anidado está mal: mira con detalle el ejemplo de la página 88 (versión 0.90): si quieres crear un nuevo tipo de datos, el nombre se pone delante de las llaves, no detrás:

struct tiempo
{
 int minutos;
 int segundos;
};

porque con eso creas un nuevo tipo de datos llamado "struct tiempo", en vez de

struct
{
 int minutos;
 int segundos;
} tiempo;

que crea una variable llamada tiempo.


Soluciona esos dos y seguimos...  ;-)


21-Jan-2012 07:08
Carlos García

Buenas,

Uso Windows XP SP3, y como compilador, el Dev_C++.
No entendí a qué te refieres con el tema de los espacios y las tabulaciones. Esto lo hice en el block de notas, pulsando intro siempre que acababa una orden, y separando también las llaves para poder contarlas mejor. Soy ciego, así que si puedes explicarte un poco mejor a ese respecto, te lo agradecería, para tratar de escribirlo como mejor os resulte visualmente.

Por otro lado, en efecto, estoy usando el manual: "Fundamentos de programación en C, por Nacho Cabanes" y su revisión 0.90. Creí que era el manual por el que se guiaba el foro, por eso no lo especifiqué claramente. Disculpas.

Y ya entrando en los temas que me dices:

El struct va como un tiro ahora. Antes lo había intentado poner como tú me indicas, pero el error que estaba cometiendo era no poner el ; tras la }. Y no veas si frustraba, porque me parecía que lo estaba haciendo bien, y no había modo de que funcionara.

Respecto al tema de scanf("%d%C", &variable); Entiendo que en este caso que planteaba, en el case 4, que es donde doy la posibilidad de modificar la información introducida, es equivalente al gets(textotemporal); sscanf(textotemoral "%d", &variable); ¿no?

Si no es así, no te entendí del todo bien. El %c que indicas, veo que es para absorver el intro; pero en este caso, no veo del todo como me podría ayudar para que si no desea modificar un dato concreto, bien sea el autor, el título, la duración o el peso; con pulsar intro se quede con la información original, y salga del "do while".

Un saludo, y 1000 gracias.


21-Jan-2012 10:40
bruno zelaia montero

Hola Carlos, lo primero que te aconsejaría es que te lo tomes con más calma, que procures hacer todos los ejercicios y sin prisas, por que? porque yo hice el mismo fallo y luego te das cuenta de que  no tienes las cosas claras y vas acumulando dudas, los ejercicios que pone están muy bien pensados para que aprendas.
Respecto a lo de absorber el intro, yo lo que suelo hacer es cuando pongo un scanf seguidamente pongo un getch() para que absorba el intro.
Respecto a lo último que dices te daré una pista, mirate strcmp que creo que te dará alguna idea ;)
Un saludo y ya dirás como te van las cosas...


22-Jan-2012 12:05
Nacho Cabanes (+84)

Carlos, como te dice Bruno, lo de usar %d%c (o un "getchar" después del "scanf") es para que absorba el Intro después de introducir un dato numérico o un "char", y la siguiente cadena que lees no la tome como vacía. No tiene nada que ver con modificar un dato concreto, sino con que lea correctamente.


Para no modificar un dato concreto cuando se pulsa intro, lees en dos pasos: primero en una variable auxiliar y luego, si no es un texto vacío, lo vuelcas a la cadena de destino:

En pseudocódigo sería

pedir nombreTemporal
si nombreTemporal no es cadena vacía
 nombrePersona = nombreTemporal

donde lo de "si no es cadena vacía" se implementa, como te ha dicho Bruno, usando un "strcmp", para comparar los valores de dos cadenas distintas.


Y ya que estamos, otra pista para tu siguiente duda: si quieres hacer una pausa tras mostrar 25 datos, la forma más sencilla suele ser llevar un contador, y si es múltiplo de 25, esperas a que se pulse una tecla (por ejemplo, con un "getchar"). Podría ser algo como

for (i=1; i<=numDatos; i++)
{
 escribirDato(i-1);
 if (i%25 == 0) getchar();
}


14-Feb-2012 10:40
Carlos García

Buenos días,

En primer lugar, agradeceros vuestras respuestas, a ver si al fin me puedo poner con el tema y lo descifro.

Y en segundo lugar, ofreceros mis disculpas por tantísimo tiempo sin responder. Me entró un virus al ordenador, me descargué varios antivirus, hice todo lo que pude y al final perdí cualquier forma de conectarme a internet, así que no quedó más remedio que formatear.

Con lo que entre que en el trabajo estas últimas semanas me han tenido a toque de corneta, y que no encontré todo lo necesario para formatear hasta la semana pasada, pues no he podido conectarme.

Lo dicho, 1000 gracias por vuestras respuestas, y a ver si vuelvo a poder sacar algo de tiempo para resolver las dudas que tenía.

Un saludo.






(No se puede continuar esta discusión porque tiene más de dos meses de antigüedad. Si tienes dudas parecidas, abre un nuevo hilo.)