Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: kuhi en 24 Abril 2017, 21:34 pm



Título: El juego del ahorcado!
Publicado por: kuhi en 24 Abril 2017, 21:34 pm
Hola, estoy trabajando en hacer el juego del ahorcado, me lo piden como trabajo de final de curso de la introducción a la programación en C.

La idea es tener listas con palabras de cierta longitud (de letras), en este caso son 5 y 6 palabras de longitud.
Lo que quiero es que el usuario me diga con cuantas letras quiere jugar, y entonces el programa seleccione aleatoriamente una palabra.
Una vez se seleccione la palabra seguiría el juego (aquí he usado el "canario" printf para comprobar que realiza las acciones que yo quiero).

Bien, el problema que me da primero es de un overflow del array en su definición.
Luego ejecuta el programa con normalidad pero no saca ningún printf. Se queda pillado y me salta un dejó de funcionar.

Código:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int main()
{
char palabras5[100][5]={'CASCO','ZASKO','HOLAS','FAJOS'};
char palabras6[100][6]={'FAMAZO','FAROLA','FASETA','FAJOTE'};
int choice;

printf("Cuantas letras quieres usar?\n");
scanf("%i",choice);

if(choice==5)
{
srand(time(NULL));
{
int rand_num=rand()%6;
printf("%s\r\n",palabras5[rand_num]);
}
}
if(choice==6)
{
srand(time(NULL));
{
int rand_num=rand()%6;
printf("%s\r\n",palabras6[rand_num]);
}
}
}

Por favor, quiero aprender así que agradecería mucho que no me deis mas información de la necesaria, ya que quiero hacer el trabajo yo y solo consultar dudas puntuales. Darme más información de la que necesito sería contraproducente ya que no quiero que me hagan mi trabajo.

MUCHAS GRACIAS!!!!


Título: Re: El juego del ahorcado!
Publicado por: MAFUS en 24 Abril 2017, 22:08 pm
Vale, en otros lenguajes puede funcionar pero en C las cadenas no se declaran de esa forma. Repasa cadenas y caracteres sueltos.


Título: Re: El juego del ahorcado!
Publicado por: CalgaryCorpus en 24 Abril 2017, 22:44 pm
Los string literales usan doble comilla, e internamente usan 1 caracter adicional para guardar el final del string. Entonces lo que se ve asi  "hola" tiene en realidad 5 caracteres, no 4.


Título: Re: El juego del ahorcado!
Publicado por: kuhi en 25 Abril 2017, 19:04 pm
Hola, gracias otra vez @MAFUS :)

No encuentro el temario en mi libro de la universidad, le he escrito al profesor que me lo pase pero hasta el viernes no está (sólo trabaja Lunes y Viernes).
Lo digo porqué he buscado la información por google, según lo que he entendido, he modificado el código y el resultado es el siguiente:

Código:
int main()
{
char palabras5[100][5]={{"CASCO"},
{"ZASKO"},
{"HOLAS"},
{"FAJOS"}};
char palabras6[100][6]={{"FAMAZO"},
{"FAROLA"},
{"FASETA"},
{"FAJOTE"}};
int choice;

printf("Cuantas letras quieres usar?\n");
scanf("%i",choice);

if(choice==5)
{
srand(time(NULL));
{
int rand_num=rand()%6;
printf("%s\r\n",palabras5[rand_num]);
}
}
if(choice==6)
{
srand(time(NULL));
{
int rand_num=rand()%6;
printf("%s\r\n",palabras6[rand_num]);
}
}
}


Sigo teniendo el mismo error, introduzco las letras que quiero que tenga la palabra y se queda pillado el programa y pone dejó de funcionar. Por lo menos ahora no me da errores el compilador.
 
Debería usar 1 letra por cada espacio del array? Es decir: array[1][1] puede contener una cadena de caracteres o solo puede contener 1 letra?
Por lo que debería poner por ejemplo para la palabra casa:
array[100][0]=c
array[100][1]=a
array[100][2]=s
array[100][3]=a
array[100][4]=\0
Puede ser? Yo tenía entendido que de la forma que está puesta en el código ya se almacena así la cadena. Si no es así, debería usar un bucle para almacenar la palabra?

@CalgaryCorpus yo tengo entendido que los arrays se cuentan desde 0. Es decir:

cadena[4] contiene 5 posiciones:[0][1][2][3][4]
Del 0 al 3 va la palabra, en 4 es donde quedará el \0.

Si no es así corregidme por favor.

Muchas gracias a todos, de verdad <3


Título: Re: El juego del ahorcado!
Publicado por: MAFUS en 25 Abril 2017, 21:53 pm
Entrecomillando una cadena has dado un paso pero sigues teniendo un fallo.
Un poco de teoría: Los lenguajes de programación, al menos antes de la era de la programación orientada a objetos, tenían el problema de saber dónde termina una cadena de texto. Nosotros entendemos las palabras, pero la máquina no; para ella son sólo una secuencia de números en una sección de su memoria lineal. Pero ¿dónde termina?
Para resolver el problema los diseñadores pensaron en dos soluciones totalmente diferentes pero totalmente funcionales:
1. El tamaño de la cadena lo marcaba el primer byte de ésta. Como pro no se necesitaba calcular el tamaño pues ya lo daba la cadena misma; por contra una cadena no podía superar los 255 caracteres.
2. Marcar la cadena con un carácter especial que no será usado en otra situación. Como pro una cadena puede ser tan larga como el programador necesita; por contra el tamaño debe ser calculado programáticamente, hay un carácter que no puede ser usado en los textos y el auténtico tamaño del array de caracteres es un byte más largo a lo que el programador escribe, por ese mismo carácter.

C usa la segunda opción.
Cuando tu escribes una cadena de esta forma
Código:
"HOLA"
lo que C hace por debajo es
Código:
{'H', 'O', 'L', 'A', '\0}
es decir, prepara un array con las letras que le has dado entrecomilladas y agrega el carácter nulo, que vale 0 (cero) en decimal, para marcar el final de la cadena. Esa es la base de todas las funciones que trabajan con cadenas.

Por tanto cuándo defines un array para alojar una cadena y debes darle las dimensiones a mano piensa que debes sobredimensionar a 1 elemento más que el número de letras tiene la cadena.

Por tanto debes redimensionar tus arrays de palabras para poder alojar el carácter nulo.


Título: Re: El juego del ahorcado!
Publicado por: kuhi en 26 Abril 2017, 04:20 am
@MAFUS Hola MAFUS! Muchas gracias de nuevo, al final te voy a tener que pagar a ti el sueldo de mi profesor 😂😂😂
Entonces cuando pongo por ejemplo: array[4]=casa (escribo desde el móvil no me currare mucho las sintaxis en esta respuesta) el array es de 4 posiciones y no incluye el \0?
Yo pensaba que al poner como en el ejemplo array[4] se contaba desde 0 hasta 4, por lo que estoy indicando 4 posiciones pero ya va incluido el \0, lo que en realidad son 5 posiciones: 0,1,2,3,4
en la posición 4 iría el \0
Entonces tengo que dejarlo así?: {"ZASKO\0"}, y dejo igual la longitud [100][5]?
Muchas gracias <3
PD: hay alguna forma de dar honor o reputación o algo? Me gustaría devolverte la ayuda que me das!


Título: Re: El juego del ahorcado!
Publicado por: MAFUS en 26 Abril 2017, 11:16 am
Al entrecomillar una cadena el compilador ya pone automáticamente el caracter nulo pero deberás tenerlo en cuenta al dimensionar un array manualmente.

Sobre dimensionar los arrays.
Cuando le das un tamaño estás indicando el número máximo de elementos que va a contener pero  como la numeración del índice empieza en el 0  el índice sulerior será siempre el número usado para dimensionar menos 1.

Por ejemplo
miarray [4]

Los elementos serán:
#1: miarray[0]
#2: miarray[1]
#3: miarray[2]
#4: miarray[3]


Título: Re: El juego del ahorcado!
Publicado por: kuhi en 26 Abril 2017, 12:04 pm
Al entrecomillar una cadena el compilador ya pone automáticamente el caracter nulo pero deberás tenerlo en cuenta al dimensionar un array manualmente.

Sobre dimensionar los arrays.
Cuando le das un tamaño estás indicando el número máximo de elementos que va a contener pero  como la numeración del índice empieza en el 0  el índice sulerior será siempre el número usado para dimensionar menos 1.

Por ejemplo
miarray [4]

Los elementos serán:
#1: miarray[0]
#2: miarray[1]
#3: miarray[2]
#4: miarray[3]
Pero entonces no entiendo que hago mal, si ya se pone automáticamente el \0, no entiendo que está mal en el código... espacio si que tiene el array para las letras y para el \0...


Enviado desde mi iPhone utilizando Tapatalk


Título: Re: El juego del ahorcado!
Publicado por: MAFUS en 26 Abril 2017, 12:52 pm
Lo escribo desde el móvil así que voy a simplificar.
Tu dices:
char palabras[5] = "CASCO"
Ahora como está entrecomillado hay que pensar hay el carácter nulo.
Así que tu array queda
#1: palabras[0] = 'C'
#2: palabras[1] = 'A'
...
#5: palabras[4] = 'O'

Y fuera de los límites de array está el caracter nulo.

Esto es peligroso porqué el programa sí copia dicho caracter nulo pero no tiene un espacio reservado. Eso significa que otra vatiable que tenga asignada esa zona de memoria te sobreescribirá ese caracter nulo y si ese es un valor distinto a 0 las funciones encargadas de manejar cadenas no encontrarán el final de esta donde tu lo esperas. Que es lo que te pasa. Así como lo tienes una cadena machaca el caracter nulo de la anterior por tanto printf escribe toda la ristra de palabras que hay en el array.


Título: Re: El juego del ahorcado!
Publicado por: kuhi en 26 Abril 2017, 14:36 pm
Ahora lo entiendo, debería poner char palabras[6] = "CASCO" para que el 6 este reservado para el nulo entonces... cuando llegue a casa lo pruebo! @MAFUS muchísimas gracias!!! <3 se agradece que haya gente así ☺️


Enviado desde mi iPhone utilizando Tapatalk


Título: Re: El juego del ahorcado!
Publicado por: kuhi en 27 Abril 2017, 17:29 pm
Hola, me sigue sin funcionar.
He probado agrandando los arrays en 1 espacio.
El programa me pide cuantas letras quiero usar para jugar al juego del ahorcado, cuando le digo por ejemplo 5 letras (introduciendo: 5) me da error, me dice el programa dejó de funcionar. No entiendo que está fallando, diría que está mal el random... alguien detecta en que estoy fallando? Si fuera el random, me podríais corregir?
Muchas gracias!!!

Código:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int main()
{
char palabras5[100][6]={{"CASCO"},
{"ZASKO"},
{"HOLAS"},
{"FAJOS"}};
char palabras6[100][7]={{"FAMAZO"},
{"FAROLA"},
{"FASETA"},
{"FAJOTE"}};
int choice;

printf("Cuantas letras quieres usar?\n");
scanf("%i",choice);

if(choice==5)
{
srand(time(NULL));
{
int rand_num=rand()%6;
printf("%s\r\n",palabras5[rand_num]);
}
}
if(choice==6)
{
srand(time(NULL));
{
int rand_num=rand()%6;
printf("%s\r\n",palabras6[rand_num]);
}
}
}


Título: Re: El juego del ahorcado!
Publicado por: MAFUS en 27 Abril 2017, 18:11 pm
Siguen siendo problemas con la memoria. En este caso punteros y paso de argumentos por referencia, que no existe en C pero se emula.
Un poco de teoría:
La memoria de un ordenador el lineal y se accede a ella dando al controlador de memoria, que en verdad es un demultiplexor, un número entero sin signo del mismo tamaño en bits que el controlador puede aceptar.
Por otra parte la memoria la maneja el sistema operativo. Éste es el encargado de ofrecer una porción para que tu programa instale en ella su código y sus datos y, por razones de seguridad y para que no puedas interferir con otros programas y servicios del sistema, vigila que tu programa no salga de esa porción asignada.
C es un lenguaje de nivel medio y eso significa que es de tan bajo nivel que el programador puede indicarle qué posición de memoria exacta quiere leer o escribir pero al mismo tiempo es de tan alto nivel que tiene estructuras para no tener que vérselas con saltos manuales y puede encerrar regiones de código en funciones que hacen todo el trabajo de la pila por él.
Los punteros de C son los encargados de guardar las direcciones de memoria a las que queremos acceder.

[ Ya casi termino ]

Todos los argumentos de las funciones se pasan por valor. Eso quiere decir que el dato que recibe la función es una copia del original y por tanto toda modificación que se haga dentro de la función de ese dato sólo afecta a la función. Quien la ha llamado no notará que haya pasado nada.
Para poder cambiar dicho dato hay que pasar la dirección de memoria de éste, así lo que se ha copiado es dicha dirección por tanto dentro de la función está el mismo puntero y se puede acceder y cambiar el contenido de la memoria. Cambiando el contenido de la memoria dentro de la función también se cambia para todo el sistema, así lo que se haga dentro de la función también lo ven desde fuera. Por cierto, el operador que devuelve la dirección de memoria de un dato es el ampersand ( & ).

[Juntándolo todo y resolviendo el error]

La función scanf, para simplificar y en tu contexto, toma un dato del buffer de entrada del mismo formato que le has indicado en la cadena de argumentos, un entero, y lo deposita en la variable que le has indicado.
Pero la función espera un puntero a la variable, por lo que te he expuesto anteriormente, es decir una dirección de memoria válida dentro de tu programa. Al darle directamente choice le dices a scanf que el contenido de choice, vete a saber cuál es, es la dirección de memoria en la que debe depositar lo recogido desde el buffer de entrada. Cómo choice puede contener cualquier cosa lo más seguro es que sea tratado como una dirección de memoria que apunta a un lugar fuera del espacio de tu programa y el sistema operativo, para que no se causen males mayores, lo aborta inmediatamente.
Por tanto debes darle a scanf la dirección de memoria de choice para que ponga el dato en tu variable.
Así el código que debes poner es
Código:
scanf("%i", &choice);


Título: Re: El juego del ahorcado!
Publicado por: kuhi en 27 Abril 2017, 18:30 pm
Madre mía que error más tonto!!!! Muchas gracias no me puedo creer que se me haya pasado ponerle a un scanf el &... de lo primero que te enseñan 😂😂😂 cuando llegue a casa lo pruebo y comento.
muchas gracias otra vez @MAFUS!!! <3


Enviado desde mi iPhone utilizando Tapatalk