INFORMATICA CBI – 2015 Dictado : Ing. Juan Manuel Conti ARREGLOS EN PASCAL. Un arreglo en cualquier lenguaje de programación es una sucesión consecutiva de bytes en memoria. Los arreglos pueden representar: Matrices (de 2 ó más dimensiones). Vectores (de una sola dimensión). La cantidad de bytes que ocupa un arreglo depende del tipo de dato que almacene cada domicilio. Así un arreglo de 4 domicilios de tipo char ocupará 4 bytes, mientras que un arreglo de 4 domicilios de tipo double ocupará 32 bytes. Este es un dato muy a tener en cuenta cuando se dimensiona un arreglo a fin de no sobrecargar demasiado la memoria. La forma clásica de una matriz de m x n que nosotros representamos como: m [filas] n [columnas] en una computadora no existe: allí los arreglos son siempre lineales (no olvidar que la memoria es secuencial). La simulación a una matriz bidimensional se obtiene como (por ejemplo para una matriz M de 3 x 10): 1 10 11 Fila 1 20 Fila 2 30 Fila 3 La posición correspondiente para el elemento [2,4] vendría dada por la expresión: Offset para M[2,4] = PosInicio + [(Fila – 1) x DIM2] + (Col-1) Offset para M[2,4] = PosInicio + (2 – 1) x 10 + 3 Offset para M[2,4] = 13 Offset significa el desplazamiento desde PosIni. Por supuesto, hemos asumido que cada elemento del arreglo contiene un dato de tipo char o byte que solo ocupa 1 byte de memoria. En caso de que cada domicilio contuviera un dato de mayor longitud, por ejemplo de tipo Word, haríamos la siguiente modificación: Offset para M[2,4] = PosInicio + [(Fila – 1) x DIM2 + (Col - 1)] x Sizeof(Tipo) Clase Teórica Nro 9 Pág 1/14 INFORMATICA CBI – 2015 Dictado : Ing. Juan Manuel Conti Es posible obtener una expresión para 3 dimensiones, pero normalmente trabajaremos solo hasta 2. Declaración formal de un arreglo en Pascal. var Mat : array[DIM1,DIM2]of <Tipo>; En el cual DIM se especifica como un subrango de tipo ordinal que tiene un límite inferior y un límite superior: var Mat : array[1..4,1..5]of integer; Vect : array[1..100]of boolean; Letras: array[1..27]of char; etc. En realidad lo conveniente es crear un “alias” para los arreglos, mediante una declarativa type: const DIM1 = 4; DIM2 = 5; type TMat = array[1..DIM1,1..DIM2]of integer; TVect = array[1..100]of boolean; etc, Luego en el bloque var ponemos: var Mat : TMat; V1 : TVect; etc. El bloque type en realidad permite construir nuevos tipos de datos pero basados en los que ya se hallan predefinidos en el lenguaje. El límite inferior y superior de cada dimensión no tiene por qué arrancar siempre en 1 ni siquiera ser de tipo numérico. Las siguientes declarativas son perfectamente posibles: type TMat = array[‘A’..’Z’]of char; TVect = array[-10..-5]of double; En el primer caso la variable de control de lazo deberá ser de tipo char y moverse entre estos dos límites: var c : char; for c:=’A’ to ‘Z’ do ..... Cómo se accesa un domicilio de un arreglo. Los elementos de un arreglo pueden accesarse para leer o para escribir su contenido. La forma de hacerlo es: M[Fila,Col]:=....... Vect[i] :=..... Clase Teórica Nro 9 Pág 2/14 INFORMATICA CBI – 2015 Dictado : Ing. Juan Manuel Conti ó bien: if(Mat[i,j]=....) then ..... Para asignar por completo un arreglo: for i:=1 to DIM1 do for j:=1 to DIM2 do M[i,j]:=20+random(81); Para mostrarlo en pantalla: for i:=1 to DIM1 do begin for j:=1 to DIM2 do write(M[i,j]:4); writeln; end; Nótese que hemos utilizado la sentencia write( ) con formato para imprimir cada fila completa sobre el mismo renglón y encolumnando con 4 espacios. El writeln sólo, se emplea para bajar un renglón. Un caso particular de arreglos: las cadenas. Hasta ahora hemos estudiado un tipo individual de datos: los char o caracteres, que representan cualquier elemento de la tabla ASCII (American Standard Code Information Interchange) o Código Standard Americano para el Intercambio de Información. En esta tabla se hallan todos los caracteres alfabéticos, numéricos, de puntuación, caracteres especiales y caracteres de control. A nosotros sólo nos interesa los alfabéticos y numéricos. A cada caracter le es asignado un valor numérico único, por ejemplo: A B C .... a b c ... 65 66 67 0 1 2 48 49 50 97 98 99 { } [ 123 125 91 Así, al pulsar un caracter cualquiera del teclado, el mismo genera automáticamente alguno de estos códigos. Cuando muchos caracteres conforman palabras y texto, Pascal provee un tipo especial de dato que permite manejarlos de forma muy cómoda y sencilla: los datos de tipo string. Este tipo especial de dato se trata de un arreglo de char, aunque en su sintaxis no aparezca la declarativa array[...]of char. Su declarativa es la siguiente: var Texto : string; Frase : string[80]; Clase Teórica Nro 9 Pág 3/14 INFORMATICA CBI – 2015 Dictado : Ing. Juan Manuel Conti La primera (string), es la declarativa por defecto. Pascal asigna 255 espacios para almacenar caracteres. Si lo que vamos a manejar son cadenas pequeñas, podemos acotar la cantidad de domicilios colocando entre corchetes el espacio requerido. El domicilio 0 (cero) tiene un uso muy particular: Pascal almacena allí (en forma de equivalente char) la cantidad de caracteres que han ingresado a la cadena. De esta forma: Frase:=’Programación en Turbo Pascal’; que contiene 28 caracteres, se almacena como: 0 Pr og r a m a c i ó n en Turbo Pascal Equivalente char de la longitud de la cadena Cómo determinar la longitud de una cadena. Pascal provee una función específica: length( var string); Que retorna un entero equivalente a la cantidad de caracteres de la cadena. De esta manera: Longitud:=length(Frase) quedaría cargado con la magnitud 28. Cuándo emplear arreglos en un problema. Imaginemos que disponemos de una frase en la cual deseamos detectar la cantidad de vocales a, e, i, etc., presentes en la misma. type var TVoc = array[1..5]of integer; Voc : TVoc; Frase : string; i : integer; begin clrscr; highvideo; Frase:=’Esta es una frase breve de prueba’; for i:=1 to 5 do Voc[i]:=0; for i:=1 to lenght(Frase) do case Frase[i] of ‘a’,’A’ : Voc[1]:=Voc[1]+1; ‘e’,’E’ : Voc[2]:=Voc[2]+1; ‘i’,’I’ : Voc[3]:=Voc[3]+1; Clase Teórica Nro 9 Pág 4/14 INFORMATICA CBI – 2015 Dictado : Ing. Juan Manuel Conti ‘o’,’O’ : Voc[4]:=Voc[4]+1; ‘u’,’U’ : Voc[5]:=Voc[5]+1; end; for i:=1 to 5 do writeln(‘Vocal ‘,chr(64+i),’=’,Voc[i]); readkey; end. Aquí aparecen un par de cositas nuevas: una extensión de la instrucción case y una instrucción nueva: chr( ). La estructura case permite varias posibilidades. En una clase anterior la mostrábamos con un listado de constantes aisladas: case VarOrdinal of caso 1 : begin instrucciones 1; end; case 2 : begin instrucciones 2 ; end; case 3 : begin instrucciones 3; end; .......... case n : begin instrucciones n; end; end; También admite la siguiente sintaxis: case VarOrdinal of Valor1 .. Valor2 : begin instrucciones 1; end; Valor3 .. Valor4 : begin instrucciones 2; end; etc. end; en la cual cada opción se trata de un subrango, como las categorías en los deportes: case Edad of 5 .. 7 : writeln(‘categoría infantil’); 7 .. 10 : writeln(‘ categoría superjuvenil’); 10..13 : writeln(‘ ...................................’); etc. end; Otra sintaxis admitida es una especie de enumeración: case VarOrdinal of valor1,valor2,... : begin instrucciones 1; end; valor5,valor6,... : begin instrucciones 2; end; etc. end; Obviamente utilizaremos esta notación cuando los valores de cada opción NO SEAN CONSECUTIVOS, como en el caso de las vocales. Volviendo a nuestro problema con los arreglos de char, no hubo ninguna dificultad para referirnos a cada caracter almacenado en el arreglo, con la consabida notación: Clase Teórica Nro 9 Pág 5/14 INFORMATICA CBI – 2015 Dictado : Ing. Juan Manuel Conti Frase[ i ] IMPORTANTE: En un arreglo (matriz o vector) perteneciente a un determinado tipo, el contenido de cada domicilio goza de las mismas propiedades que un dato aislado perteneciente al mismo tipo. Por ejemplo: var n : integer; V : array[1..10]of integer; V[1], V[2], etc., gozan de las mismas propiedades que n, pues se trata de enteros: DIV división entera. MOD resto de una división entera. pred predecesor. succ sucesor. Otro ejemplo en el cual conviene utilizar arreglos es el siguiente: Convertir un número binario en su equivalente decimal. uses crt; type TBin = array[1..8]of byte; var NBin : TBin; NDec : integer; PesoDig : integer; i : byte; begin clrscr; highvideo; PesoDig:=128; NDec:=0; for i:=8 downto 1 do begin write('NBin ',i,'='); readln(NBin[i]); NDec:=NDec+NBin[i]*PesoDig; PesoDig:=PesoDig DIV 2; end; write('El binario ingresado fue '); for i:=8 downto 1 do write(NBin[i]); writeln; writeln('Su equivalente decimal es ',NDec); readkey; end. Clase Teórica Nro 9 Pág 6/14 INFORMATICA CBI – 2015 Dictado : Ing. Juan Manuel Conti Como en toda base de numeración los dígitos de mayor peso son los que están más a la izquierda, hemos trabajado con un lazo for decreciente (downto) de 8 hasta 1. Recuerde que los pesos binarios son: Pesos 128 64 32 16 8 4 2 1 --------------------------------------------------------------------------8 7 6 5 4 3 2 1 Posiciones En realidad a la primera posición es cero, pero a fin de no trabajar con potencias de 2, le llamaremos 1. Además recuerde que los dígitos binarios sólo pueden ser 1’s o 0’s. Imaginemos que ingresamos: 11001011 Para obtener su equivalente decimal tendríamos que hacer: 1x 128 + 1 x 64 + 0 x 32 + 0 x 16 + 1 x 8 + 0 x 4 + 1 x 2 + 1 x 1 o sea cada dígito por su correspondiente peso (como se vio en la primera clase). Esta sumatoria de productos se halla implementada dentro del lazo for. Analícela. Procedimientos y Arreglos. Este es el momento de ver otras de las aplicaciones de los parámetros por referencia: cuando un subprograma recibe un arreglo sobre el cual debe trabajar. (* --- INFORMATICA 2014 - Procedimientos y arreglos 01.pas ---Un procedimiento denominado CargarMatriz( ) recibirá como único parámetro una matriz de enteros de 10 x 15 y le asignará valores aleatorios en el rango 10, 50 mostrándola por pantalla en forma matricial. Este procedimiento también efectuará la suma de cada fila, y dicho resultado será mostrado a la derecha de la matriz (a continuación de cada fila). Como forma de verificación, vuelva a imprimir la matriz, pero esta vez desde el main( ), posterior a la invocación. NOTA: Al pasar la matriz como parámetro variable, TODO lo que se haga sobre ella subsistirá al finalizar la invocación. -------------------------------------------------------------------------------------------------------- *) uses crt; const DIM1 DIM2 type TMat var Mat i,j = = = : : 10; 15; array[1..DIM1,1..DIM2]of integer; TMat; integer; Clase Teórica Nro 9 Pág 7/14 INFORMATICA CBI – 2015 Dictado : Ing. Juan Manuel Conti { ---------------------------------------------------------------} procedure CargarMatriz( var M : TMat); var SumaFila : integer; i,j : integer; begin for i:=1 to DIM1 do begin SumaFila:=0; textcolor(WHITE); for j:=1 to DIM2 do begin M[i,j]:=10+random(41); SumaFila:=SumaFila+M[i,j]; write(M[i,j]:3); end; textcolor(LIGHTRED); writeln(SumaFila:6); end; end; { -------------------------------------------------------------- } begin (* main *) clrscr; randomize; CargarMatriz(Mat); readkey; textcolor(LIGHTGREEN); writeln('---------------------------------------------------'); textcolor(WHITE); for i:=1 to DIM1 do begin for j:=1 to DIM2 do write(Mat[i,j]:3); writeln; end; end. MUY IMPORTANTE: En la declarativa de parámetros formales de un subprograma, ya sea función o procedimiento, NO SE PERMITEN DECLARACIONES ESTRUCTURADAS, pero en cambio sí un tipo simple creado en la línea type. Por eso es que hemos declarado un tipo TMat que en realidad representa un dato estructurado: una matriz. (* --- INFORMATICA 2014 - Procedimientos y arreglos 02.pas ---La misma matriz anterior, pero ahora no sumaremos cada fila sino que simplemente la cargaremos, la mostraremos y desde el procedimiento se invocara una función de nombre SumarDiagonal( ) que la recibirá como parámetro por referencia y determinara la suma su diagonal principal (valor que retornara). Este valor será mostrado en pantalla desde el procedimiento CargarMatriz( ). --------------------------------------------------------------------------------------------------------- *) uses crt; const DIM = 10; type TMat = array[1..DIM,1..DIM]of integer; var Mat : TMat; Clase Teórica Nro 9 Pág 8/14 INFORMATICA CBI – 2015 Dictado : Ing. Juan Manuel Conti { ------------------------------------------------------------- } function SumarDiagonal(var M : TMat):integer; var SumaDiag : integer; i : integer; begin SumaDiag:=0; for i:=1 to DIM do SumaDiag:=SumaDiag+M[i,i]; SumarDiagonal:=SumaDiag; end; { ---------------------------------------------------------------} procedure CargarMatriz( var M : TMat); var i,j : integer; begin for i:=1 to DIM do begin for j:=1 to DIM do begin M[i,j]:=10+random(41); write(M[i,j]:3); end; writeln; end; writeln; writeln('SUMA DE LA DIAG PRINCIPAL : ',SumarDiagonal(M)); end; { -------------------------------------------------------------- } begin (* main *) clrscr; randomize; CargarMatriz(Mat); readkey; end. Este es un caso en el cual desde un subprograma se invoca los servicios de otro suprograma: desde el procedimiento CargarMatriz( ) se ha llamado a la función SumarDiagonal( ) la cual retorna a dicho procedimiento el valor solicitado: la suma de la diagonal principal. (* --- INFORMATICA 2014 - Procedimientos y arreglos 03.pas ---Un procedimiento denominado CargarMatriz( ) recibirá como parámetros una matriz de enteros de 10 x 15 y un valor dado. La matriz deberá ser cargada con valores aleatorios en el rango 100, 999 y mostrada por pantalla. Este procedimiento también encontrará el máximo valor almacenado (no lo mostrará por pantalla), pero si en cambio se mostrará desde el punto de invocación (en el main( )). --------------------------------------------------------------------------------------------------------- *) uses crt; const DIM1 = 10; DIM2 = 15; Clase Teórica Nro 9 Pág 9/14 INFORMATICA CBI – 2015 Dictado : Ing. Juan Manuel Conti type var TMat = array[1..DIM1,1..DIM2]of integer; Mat : TMat; Max : integer; { ------------------------------------------------------------- } procedure CargarMatriz( var M : TMat; var Max : integer); var i,j : integer; begin Max:=0; for i:=1 to DIM1 do begin for j:=1 to DIM2 do begin M[i,j]:=100+random(900); write(M[i,j]:4); if(M[i,j]>Max)then Max:=M[i,j]; end; writeln; end; end; { -------------------------------------------------------------- } begin (* main *) clrscr; randomize; CargarMatriz(Mat,Max); writeln(' ------------------------------------------------ '); writeln('MAXIMO : ',Max); readkey; end. Nótese que los dos parámetros del procedimiento han sido recibidos por referencia, lo cual indica que en el punto de invocación (main), se mantendrán todas las modificaciones que el procedure haga sobre la matriz y la variable pasadas. (* --- INFORMATICA 2014 - Procedimientos y arreglos 04.pas ---Un procedimiento denominado CargarMatriz( ) recibirá como parámetros una matriz de enteros de 10 x 15 y un vector dado, también de enteros. La matriz deberá ser cargada con valores aleatorios en el rango 100, 999 y mostrada por pantalla. Este procedimiento buscará todos los pares que hayan salido y lo almacenará en el vector recibido. Este vector será mostrado desde el main. ---------------------------------------------------------------------------------------------------------- *) uses crt; const DIM1 DIM2 type TMat TVect = = = = var : TMat; : TVect; : integer; Mat Vect i 10; 15; array[1..DIM1,1..DIM2]of integer; array[1..DIM1*DIM2]of integer; Clase Teórica Nro 9 Pág 10/14 INFORMATICA CBI – 2015 Dictado : Ing. Juan Manuel Conti { ------------------------------------------------------------- } procedure CargarMatriz( var M : TMat; var V : TVect ); var i,j,k : integer; begin for i:=1 to DIM1*DIM2 do V[i]:=0; k:=1; for i:=1 to DIM1 do begin for j:=1 to DIM2 do begin M[i,j]:=100+random(900); write(M[i,j]:4); if(M[i,j] MOD 2 =0)then begin V[k]:=M[i,j]; k:=k+1; end; end; writeln; end; end; { -------------------------------------------------------------- } begin (* main *) clrscr; randomize; CargarMatriz(Mat,Vect); writeln(' ------------------------------------------------ '); i:=1; while(Vect[i]<>0)do begin write(Vect[i]:4); i:=i+1; end; readkey; end. Ahora a nuestro famoso procedimiento CargarMatriz( ) le agregaremos más generalidad estableciendo que los limites de los aleatorios ingresen como parámetros. También estableceremos que solamente formarán parte de la matriz aquellas magnitudes cuyo dígito central sea 5. Para ello nos valdremos de los operadores DIV y MOD. Finalmente este procedimiento rescatará en un vector todos aquellos valores de la matriz cuya suma de dígitos sea igual a 12. He aquí los códigos: (* --- INFORMATICA 2014 - Procedimientos y arreglos 05.pas ---Un procedimiento denominado CargarMatriz( ) recibirá como parámetros una matriz de enteros de 10 x 15, un vector de enteros y dos enteros simples. La matriz deberá ser cargada con valores aleatorios en el rango establecido por los enteros simples, pero con la condición de que todos los valores posean el digito central igual a 5. También deberá mostrarla por pantalla. Este procedimiento detectara también todos aquellos valores cuya suma de dígitos sea igual a 12 y los cargara en el vector. Este vector será mostrado desde el main. -------------------------------------------------------- *) Clase Teórica Nro 9 Pág 11/14 INFORMATICA CBI – 2015 Dictado : Ing. Juan Manuel Conti uses crt; const DIM1 DIM2 type TMat TVect = = = = var : TMat; : TVect; : integer; Mat Vect i 10; 15; array[1..DIM1,1..DIM2]of integer; array[1..DIM2]of integer; { ------------------------------------------------------------- } procedure CargarMatriz( var M : TMat; var V : TVect; Linf : integer; Lsup : integer ); var i,j,k : integer; Dig1 : integer; Dig2 : integer; Dig3 : integer; begin for i:=1 to DIM1*DIM2 do V[i]:=0; k:=1; for i:=1 to DIM1 do begin for j:=1 to DIM2 do begin repeat M[i,j]:=100+random(900); Dig1:= M[i,j] MOD 10; Dig2:=(M[i,j] DIV 10) MOD 10; Dig3:= M[i,j] DIV 100; until(Dig2=5); write(M[i,j]:4); if(Dig1+Dig2+Dig3 = 12)then begin V[k]:=M[i,j]; k:=k+1; end; end; writeln; end; end; { -------------------------------------------------------------- } begin (* main *) clrscr; randomize; CargarMatriz(Mat,Vect,100,900); writeln(' ------------------------------------------------ '); i:=1; while(Vect[i]<>0)do begin write(Vect[i]:4); i:=i+1; end; readkey; end. Clase Teórica Nro 9 Pág 12/14 INFORMATICA CBI – 2015 Dictado : Ing. Juan Manuel Conti (* --- INFORMATICA 2014 - Procedimientos y arreglos 06.pas ---Un procedimiento denominado CargarMatriz( ) recibirá como parámetros una matriz de enteros de 10 x 15, dos enteros simples (Linf y Lsup) y otros dos parámetros adicionales. La matriz deberá ser cargada con valores aleatorios en el rango establecido por Linf y Lsup. También deberá mostrarla por pantalla. Este procedimiento detectara también cual de todas las filas posee suma máxima y cual fue esa suma, valores que retornara a través de los dos parámetros adicionales. ----------------------------------------------------------------------------------------------------------- *) uses crt; const DIM1 DIM2 type TMat var = 10; = 15; = array[1..DIM1,1..DIM2]of integer; Mat FilaSumaMax SumaMaxima i : : : : TMat; integer; integer; integer; { ------------------------------------------------------------- } procedure CargarMatriz( var M : TMat; var FilaSumaMaxima : integer; var SumaMaxima : integer; Linf : integer; Lsup : integer ); var i,j : integer; SumaParcial : integer; { suma parcial para cada fila } begin SumaMaxima:=0; for i:=1 to DIM1 do begin SumaParcial:=0; for j:=1 to DIM2 do begin M[i,j]:=Linf+random(Lsup-Linf); SumaParcial:=SumaParcial+M[i,j]; write(M[i,j]:4); end; writeln; if(SumaParcial>SumaMaxima)then begin SumaMaxima:=SumaParcial; FilaSumaMaxima:=i; end; end; end; { -------------------------------------------------------------- } begin (* main *) clrscr; randomize; CargarMatriz(Mat,FilaSumaMax,SumaMaxima,100,900); writeln('-------------------------------------------------'); writeln('SUMA MAXIMA : ',SumaMaxima); Clase Teórica Nro 9 Pág 13/14 INFORMATICA CBI – 2015 Dictado : Ing. Juan Manuel Conti writeln('FILA P/SUMA MAXIMA : ',FilaSumaMax); readkey; end. Clase Teórica Nro 9 Pág 14/14