[ Foro de Pascal ]

centinela????

20-Jul-2010 19:54
oscar gomez
16 Respuestas

Hola profesor Nacho cabanes y colaboradores.
Tengo una gran duda con los registros centinelas cuando se esta trabajando con arrays.
Tengo informacion de los estudiantes de una universidad( no sabemos cuantos)y necesito codificar a traves del siguinete seudocodigo en pascal.

el vector b[11] ,en la primera posicion contendra el codigo de estudiante y las restantes 10 posiciones son notas por materia.
necesito entonces que por pantalla me pida el codigo de un estudiante y seguidamente las 10 notas correspondientes a sus materias cursadas y asi me siga pidiendo datos de estudiantes y sus notas hasta que el valor centinela para el codigo sea igual a cero.

en seudocodigo seria asi:

leer vector b[11]
n=0
mientras b[1]<> 0 haga
 inicio
   n=n+1
   s=0
   mp=0
   para i=1 hasta 10 haga
     instrucciones...
   fin para
   lea vector b[11]
 fin mientras

como podria leer el vector b[11] en pascal teniendo en cuenta el valor centinela para el codigo ( while b[1]<>0 do...)es lo que no entiendo como se haria.si podeis ayudarme mil gracias


21-Jul-2010 00:04
Antonio P.G.

Hola.

No entiendo muy bien la pregunta. ¿Cómo es el vector?

¡Ciao!


21-Jul-2010 09:29
oscar gomez

Gracias Antonio por preocuparte por mi duda.
Mira en ese seudocodigo si notais tengo inicialmente la lectura de un vector de 10 posiciones ok hasta ahi ningun problema el problema o mi pregunta es que necesito leer otro vector de 11 posiciones que son datos para cada uno de los estudiantes ( no sabemos cuantos), la primera posicion corresponde al codigo del estudiante ( ejem: 001 , o podria ser el dni... como se desee) y las restantes 10 posiciones son las notas obtenidas en 10 materias. segun el seudocodigo se ve que se hace lectura de dicho vector utilizando como registro centinela el valor de codigo del estudiante, por eso tenemos en el seudocodigo:
 leer vector b[11]
 n=0
 mientras b[1] <> 0
   instrucciones...
   leer vector b[11]
   fin mientras

es decir por pantalla quiero que utilizando el concepto de registro centinela leyendo los datos del vector b[11],asi porejemplo:
escriba el codigo del estudiante:
111
escriba las 10 notas de este estudiante:
2.5
3.3
4.2
3.0
4.5
2.8
3.2
4.1
3.9
4.8

escriba el codigo del estudiante:
112
escriba las 10 notas de este estudiante:
...
...
escriba el codigo del estudiante:
113
escriba las 10 notas de este estudiante:
...
...
escriba el codigo del estudiante:
0
como digitamos cero saldriamos del while dado que hemos digitado para el registro centinela un valor cero, recordais que en b[1] se almacena el codigo del estudiante dado que b es un vector definido de 11 posiciones b[11]

ENTONCES COMO HAGO PARA LA LECTURA DEL VECTOR B TENIENDO EN CUENTA SU REGISTRO CENTINELA B[1] QUE CORRESPONDE AL CODIGO?

Y PARA OBTENER EL LISTADO AL FINAL DE LA LECTURA DE DATOS DE TODOS LOS ESTUDIANTES QUE SE HAYAN DIGITADO COMO PODRIA DEFINIR UNA MATRIZ PARA DEFINIR LOS RESULTADOS QUE SE PIDEN PARA EL LISTADO DADO QUE NO SE SABE CUANTOS ALUMNOS SE VAN A DIGITAR, PUES COMO NO SE CUANTOS QUE DIMENSIONES PODRIA DARLE A LA MATRIZ CUANDO SE DEFINA ESTA?

ES DECIR QUIERO QUE EN PANTALLA SE MUESTRE POREJ:

CODIGO  PROMEDIO SEMESTRAL  MATERIAS PERDIDAS
 111          3.1                                             2
 112          2.8                                             1
 113          4.1                                             0

como podria definir una matriz sin saber de antemano el numero de estudiantes?
mil gracias y como veis no es un ejercicio sencillo pues tiene mucho concepto y si tu y el profesor Nacho cabanes nos dan una ayuda estoy seguro que a muchos les quedara claro.el ejercicio fue tomado de un libro americano con problemas bastante interesantes y en el estaba dada la solucion en seudocodigo.
mil gracias por sus ayudas.


21-Jul-2010 12:22
Antonio P.G.

Vamos a ver. Lo que yo entiendo es lo siguiente:

- Tenemos un número indeterminado de alumnos.
- Cada uno tiene su código.
- Cada alumno tiene diez notas.

Un detalle es que con los tipos reales hay problemas a la hora de comparar; quiero decir que las operaciones relacionales ">" y "<" sí funcionan, es decir, se puede saber si un real es mayor o menor que otro, pero no se puede saber si un real es igual a otro, y por tanto, si es diferente tampoco.

Yo, personalmente, hice hace tiempo varios programas de este tipo, y hay varias formas de abordar el tema de qué tipo de datos utilizar. Pondré 3 de ellos que se me ocurren (en estos conocemos el número de alumnos).

1. Crear un array tan largo como el número de alumnos. Cada casilla o posición del array contiene un registro. El registro contiene un nombre o identificación de tipo string, y por otro lado también contiene un array de tipo real de 10 casillas de longitud.

2. Crear un array tan largo como el número de alumnos. Cada casilla es un array de 11 posiciones (este es como el que has planteado tú, más o menos). Ahora bien, el tipo de datos es INTEGER. De esta forma, el código del alumno es integer y también las notas. ¿Que las notas las quieres con dos decimales? No pasa nada, luego, después de las operacione, divides entre 100. Este se puede plantear como:

..a) type
......tipo_vec_alumno = array [1..11] of integer;
......tipo_vec_clase = array [1..Nalumnos] of tipo_vec_alumno;

..b) type
......tipo_matr_clase = array [1..Nalumnos,1..11] of integer;

3. Lo mismo que el anterior, pero en vez de usar el tipo integer, utilizar el tipo string. Puedes construir un procedimiento para transformar strings que representen números en tipos reales e integer. Ahora, si esto te parece complicado (que lo es más de lo que parece), existe ya un procedimiento que hace esto:

Val (s : string; var v; var code : integer);

Aquí, "s" es el string con que se le alimenta. "v" es el número en tipo integer o real que te devuelve. "code" es un número, que es cero si ha habido éxito, y otro número si se ha producido error.

Personalmente, me quedo con el primero, porque creo que es el más estructurado, aunque el segundo es más fácil de manejar.

Por último, trato el tema de lo del número indeterminado de alumnos. Se puede hacer de dos maneras:

..a) Haciendo un array lo suficientemente grande como para asegurarnos que no tendremos problemas de espacio a la hora de meter a los alumnos (pero podríamos tener problemas de escasez memoria).

..b) Usando listas. Entrar en listas es un poco más complicado, ya que hay que tener la mayoría del resto de cosas bien claras (sobretodo los registros). Sin embargo, es más sencillo de lo que parece.

Espero haber sido de ayuda. Si aún no hay algo claro sigue preguntando, por favor, que ahora estoy de vacaciones y tengo un poco más de tiempo.

¡Ciao!


21-Jul-2010 15:37
oscar gomez

Gracias antonio nuevamente.
Mira lo que me aconsejas en tu mensaje es correcto pero miremoslo en codigo, para explicarte que necesito ademas de las recomendaciones que me diste:
tengo el programa de esta forma, utilizando la opcion del vector b[10] como integer para no complicarme por ahora en el tema de registros o estructuras y el codigo (cod)como una variable:

program libro_americano;
uses crt;
var a:array[1..10] of integer;
   b:array[1..10] of integer;
   i,nc,mp,n,cod:integer;
 s,promsemestral:real;

 begin
 clrscr;
 writeln;
{lleno el vector de criditaje de cada materia}
 for i:= 1 to 10 do
   begin
   writeln(' valor del creditaje de la materia ',i, ':');
   readln(a[i]);
   end;
{realizo la sumatoria total de creditos del vector a}
 nc:=0;
 for i:=1 to 10 do
   nc:=nc+a[i];

 n:=0;
 {en esta parte es donde te pregunto como hacer?)
writeln('escriba el codigo del estudiante:');
 readln(cod);/aqui lo leo como una var no como un comp de vector
   while cod<>0 do
     begin
       writeln('digite las diez notas de este estudiante:');
       for i:=1 to 10 do
       readln(b[i]);
       n:=n+1;
       s:=0;
       mp:=0;
       for i:=1 to 10 do
       begin
         s:=s+a[i]*b[i];
         if b[i]<3  then
           mp:=mp+1;
         end;
       promsemestral:=s/nc;
       writeln('codigo  promedio semestral    mat_perdidas ');
       writeln(cod:2,'    ',promsemestral:0:2,'      ',mp );
       writeln;
       writeln('escriba el codigo del estudiante:');
       readln(cod);
       end;

     end.

bien asi como lo tengo me funciona perfecto pero lo que se quiere es que el codigo del estudiante,(que como veis esta definido como una variable ) sea parte de un vector de 11 posiciones (b[11]) donde la primera posicion de este vector sea el codigo y las restantes 10 sean sus respectivas notass. lo que te pido por favor es que conservando la estructura del programa donde el codigo de estudiante sea el valor centinela y que  si dicho codigo es diferente de cero me pida las 10 notas, pero que tanto codigo y las 10 notas se posicionen en el vector b[11]????

es decir
lea b[11]
mientras b[1]<> 0 do
 instrucciones
 ....
 lea b[11]
fin mientras

como veis es la forma cuando la condicion del while es un valor centinela ,solo que no se como en codigo podria leer ese codigo b[1] y dentro del while pedir los datos nuevamente ( como vector). pues como te puedes dar cuenta primero se pide el codigo b[1] y si es diferente de cero entra por el while, no olvidar que no se saben cuantos estudiantes se procesaran.

mil gracias antonio estare esta tarde pendiente de tu ayuda.


21-Jul-2010 20:01
Antonio P.G.

Hola de nuevo.

Pues a ver, por lo que yo entiendo, haría lo siguiente: cogería el vector "b" y lo redefiniría.

b : array [0..10] of integer;

Así el vector mide 11 casillas. En la posición cero almacenamos el código. Haríamos una asignación tras pedir el código, es decir, justo después del begin del while escribiría

"b[0]:= cod;"

Y así tienes almacenado el código en la posición cero.

De esta forma además no hace falta correr los índices de los bucles; seguirán yendo de 1 a 10.

Espero que esa fuese la respuesta que buscabas.
¡Ciao!


22-Jul-2010 12:48
oscar gomez

Hola antonio gracias por tus respuestas y ayuda.
mira lo que me planteas esta correcto pero imaginate que ahora lo que deseo hacer es un listado por pantalla de los estudiantes que se ingresen (codigos y las 10 notas),bien lo modifique simplemente agregando despues del fin del while con dos for; uno que va desde j:=1 to n do(siendo n el numero de alumnos ingresados que voy almacenando en una variable contador ,n dado que no sabemos el numero de alumnos por anticipado)y otro for anidado que iria desde for i:=1 to 11 do ,pero claro hay un problema dado que el me guarda en el vector b[11 ] el ultimo valor de codigo que pregunto en el interior del while, como podria hacerlo antonio para que me muestre un listado de todos los alumnos con sus respectivos codigos y notas , una vez haya entrado por teclado un codigo 0 lo cual haria que no se cumpliera el while. yo lo tengo asi en codigo , que me aconsejas o que modificarias?


program libro_americano;
uses crt;
var a:array[1..10] of integer;
   b:array[1..11] of integer;
   i,j,nc,mp,n,cod:integer;
   s,promsemestral:real;

begin
 clrscr;
 for i:= 1 to 10 do
   begin
   writeln('entre valor del creditaje de la materia ',i, ':');
   readln(a[i]);
   end;

 nc:=0;
 for i:=1 to 10 do
   nc:=nc+a[i];


 n:=0;{variable para contar numero de alumnos}
 writeln('escriba el codigo del estudiante:');
 readln(b[1]);
   while b[1]<>0 do
     begin
       writeln(b[1]);
       n:=n+1;
       writeln('numero de estudiantes ingresados: ',n);
       writeln('digite las diez notas de  este estudiante:');
       for i:=2 to 11 do
       readln(b[i]);

   s:=0;
   mp:=0;
   for i:=1 to 10 do
     begin
       s:=s+a[i]*b[i+1];
       if b[i+1]<3  then
         mp:=mp+1;
       end;

     writeln('escriba el codigo del estudiante:');
     readln(b[1]);      /*** aqui estaria el problema antonio

   end;

 {codigo para mostrar el listado de los alumnos}

   writeln('*******************************');
       for j:=1 to n do
         begin
         for i:=1 to 11 do
 write(b[i],' ');
         end;

       readkey;
     end.

como te das cuenta el problema seria cuando dentro del while pido un nuevo alumno pues el lee ese codigo y lo almacena en b[1]
como puedo modifacarlo para que en el listado aparezca para cada alumno sus codigos y notas respectivas??

una segunda cosa antonio, como podria modificar para que me recibiera notas reales dado que el vector b esta definido como integer,tu me dijiste algo de dividir por 100 como seri porfa?
mil gracias por tu generosidad y tiempo.


22-Jul-2010 16:50
Antonio P.G.

A ver. Respondo por partes.

Primero, la última pregunta, lo de "dividir entre 100". Pues esto es que cuando el usuario introduzca los datos se le indique que los introduzca sin comas ni puntos. Así, en vez de introducir "8.54", el usuario introduciría "854". Entonces, se puede almacenar como un dato integer. Luego, al mostrar los resultados, en el propio "writeln" dividimos por 100. Ejemplo:

writeln ('El dato es: ',dato_integer/100 :0:2);

Segundo, lo que tú estás haciendo es leer varias veces un alumno. Es decir sólo tienes un vector (al que has llamado "b") al que le das unos valores, y cada vez que das una vuelta, le cambias los valores al vector. Es como si tuvieses el boletín de notas de un alumno y estuvieses escribiendo y borrando las notas constantemente. Pues bien, tu programa es unidimensional, pero tu problema es bidimensional; necesitas otra dimensión.

¿Cómo se soluciona esto? Con matrices. Crea una variable que sea "clase", por ejemplo.

var
..clase : array [1..N,0..10] of integer;

Donde "N" es una constante definida anteriormente, el número de alumnos. Ahora lo que tienes es una matriz de N filas por 11 columnas (o al revés, como se quiera). ¿La tercera nota del 5º alumno?

..clase[5,3]

Así, jugando con los contadores de los bucles podemos recorrer todas las notas de un alumno cuya posición en la lista de alumnos es la "a":

..for i:= 1 to 10 do
....writeln (clase[a,i]);

Eso por poner un ejemplo.

Por ello, cada vez que avances en el nº del alumno, modificas la primera coordenada, y cuando quieras avanzar en notas, modificas la segunda.

Recomendación: coger una hoja de papel cuadriculado de cuaderno y construir el programa con un ejemplo a la vez que se hacen las modificaciones con el lápiz, para ver esto de las matrices de dos dimensiones.

Espero haber acertado.
¡Ciao!


22-Jul-2010 18:40
oscar gomez

Gracias nuevamente y disculpa estar aun en lo mismo pero...
Mira lo que me dices es correcto pero solo para el codigo que es el unico campo que realmente se esta modificando por que los demas datos si que los esta almacenando (las notas) , en ejecucion para un ejemplo de dos estudiantes porejemplo:

1 2 2 2 2 2 2 2 2 2 2
en esta primera lectura esta el codigo del estudiante ( 1 ) y sus 10 notas ( 2 2 2 2 2 2 2 2 2 2)

bien al leer los datos del estudiante2 , con codigo porej 2 y sus  10 notas correspondientes:
3 3 4 3 4 3 2 4 3 5

al final el listado (para los dos estudiantes ingresados me sale asi:

2  2 2 2 2 2 2 2 2 2 2
2  3 3 4 3 4 3 2 4 3 5

como veis lo unico es que el codigo del primer estudiante si se modifico por el del segundo, pero si que se esta almacenando para cada estudiante en un vector b[11] pues si te fijas, yo dentro del while genero un contador n:=n+1 ( que inicializo en 0)que me va llevando el numero de alumnos introducidos, por eso es que hago para el listado:

for j:=1 to n do // para cada estudiante
 for i:=1 to 11 do
   write(b[i],' ');
 writeln;

lo que tu me sugieres de la matriz me obliga a definir un N PARA EL NUMERO DE ESTUDIANTES LO CUAL ESTARIA VARIANDO LAS ESPECIFICACIONES DEL PROGRAMA PUES NO OLVIDES QUE NO SABEMOS CUANTOS ESTUDIANTES HAY....y es ahi donde tengo el problema, por eso en el anterior codigo que te envie te colocaba a manera de comentario en **** que ahi estaba el problema en la lectura del codigo para la lectura de mas estudiantes . por favor dame en base a esto que te comento una orientacion para la solucion del mismo...mil gracias por tu amabilidad y tiempo


23-Jul-2010 14:01
Antonio P.G.

Hola Oscar.

He tomado el último código de programa que publicaste y lo he ejecutado. La salida no da igual que como tú indicas en el último mensaje. Por favor, si modificas el programa, ¿podrías poner el código que llevas construido? Así nos sería un poquillo más fácil.

Con respecto a lo de no conocer el número de estudiantes se solucionaba dándole a N un valor grande o mediante el uso de listas (de punteros), pero esto último es muy complicado.

Luego por la tarde le hecho otro vistazo al foro.

¡Ciao!


25-Jul-2010 18:27
oscar gomez

Hola antonio,gracias ante todo por tu atencion y ayuda.
Tienes razon solo me guarda los ultimos datos del estudiante,bueno supongo que no hay mas maneras de resolverlo si no como tu me indicas intentare mirar opciones ,sin embargo si tienes otra idea no dudes en indicarmela para tener alternativas mil gracias antonio


25-Jul-2010 20:43
Nacho Cabanes (+30)

Apoyo lo que te dice Antonio: la primera aproximación (sencilla, pero ineficiente) es usar un array de dos dimensiones, más grande que el número e estudiantes (que es indeterminado pero se puede estimar), de modo que en vez de

for j:=1 to n do // para cada estudiante
 for i:=1 to 11 do
   write(b[i],' ');
 writeln;

que escribe n veces los datos de un único estudiante, harías

for j:=1 to n do // para cada estudiante
 for i:=1 to 11 do
   write(b[j,i],' ');
 writeln;

y el array lo declararías con algo como

var b:array[1..100, 1..11] of integer;

Cuando todo esté entendido y funcione bien, la mejora es usar una lista enlazada en vez de un array, pero eso sólo tiene sentido si es un número MUY variable de alumnos; si es un número POCO variable (por ejemplo, entre 50 y 60) puede ser preferible un array de dos dimensiones como el anterior, en el que desperdicias algo de espacio a cambiar de simplificar mucho la solución.


26-Jul-2010 16:29
oscar gomez

Gracias por responderme y ayudarme.
Bien ahora como seria entonces la lectura del codigo y de las 10 notas de cada estudiante?, definiendo la matriz que me indicais:
var b:array[1..100, 1..11] of integer;
gracias por su ayuda


26-Jul-2010 21:33
Antonio P.G.

Hola.

Para la lectura tendrás que hacer lo mismo que para la (posterior) escritura: un bucle general para los alumnos y otro sub-bucle para las asignaturas y código, o como esto sea.

Los índices de la matriz variarán según el bucle; en el sub-bucle la coordenada derecha y en el principal la izquierda. Una pinta más o menos como ésta:

.......................
..bucle con i para alumnos
....(operaciones)
....bucle con j para CADA alumno
......asignación b[i,j]  (lectura/escritura)
....fin sub-bucle
..fin bucle principal
.......................

"Más o menos". Sin embargo, espero darte una idea.

¡Hasta luego!


27-Jul-2010 16:24
oscar gomez

Buenas tardes.
Antonio y Nacho C. mil gracias por su ayuda logre solucionar el programa tal y como me lo indicaban y me ejecuto correctamente muchas gracias por la atencion y ayuda prestada.


29-Jul-2010 23:16
oscar gomez

Bien la idea que me dais tu y antonio la comprendo pero eso haria que no pudiera controlar la entrada con valor centinela para el codigo de estudiante , pues ya no estaria controlado por un bucle while sino por un for dado que me sugieres un valor estimado para el numero de estudiantes ej: n:=5,entonces esa es mi gran duda que no he podido salir de ahi pues si estimo un valor para el numero de estudiantes no se tendria ya en cuenta la condicion para el registro centinela, es decir de un bucle como este:

leer datos del estudiante( codigo y sus 10 notas)
while codigo<>0 do //registro centinela
instrucciones...
leer datos del estudiantes
fin while

estaria pasando a un for i:0 1 to n do  //siendo ya n una constante definida que seria el valor estimado de alumnos.

no se profesor me queda ese vacio y gran duda de primero cambiar las condiciones del problema dado que se me pide que controle la entrada de alumnos segun valor registro centinela para el codigo ( cuando este valga 0 ó 999, terminar la entrada de datos).ayudame a entenderlo por favor si puedes esquematizarmelo en codigo podria quiza entenderlo mejor, mil gracias por tu tiempo y ayuda


30-Jul-2010 01:09
Antonio P.G.

Permíteme responder.

Lo que dices es cierto, pero se puede hacer otra cosa, utilizando while. En la condición, a parte de lo del "codigo <> 0", añade la condición de que "i>N", donde "i" es un contador iniciado en cero y que se incrementa en uno con cada vuelta, y "N" es el número máximo de alumnos a introducir.

Si el flujo del programa no entra de nuevo al bucle, será porque se ha introducido un cero, o porque hemos alcanzado el máximo. Podríamos entonces (después del bucle) comprobar si ha sido por la segunda razón y así enviar un mensaje al usuario en plan "Se ha llenado la lista", o algo por el estilo.

NOTA IMPORTANTE: en la condición de un bucle while, el operador AND es clave. A veces, uno se equivoca y suele poner OR.

Hasta luego.






(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.)