practica final del curso de lenguaje de programacion

10
PRACTICA FINAL DEL CURSO DE LENGUAJE DE PROGRAMACION 2015-I Procedimiento 1.- Traducir el documento en forma correcta los párrafos correspondientes en el orden que se presenta, debe tener en cuenta que hay segmentos de programas que van a formar un programa que permitirá crear un archivo de acceso directo 2.- El programa completo aparece desde la página 6, copie y ejecute el programa en forma correcta, modifique la presentación, observe al final la ejecución, en la ejecución del programa deberá presentar todos los casos que presenta el menú del programa. Los archivos de acceso directo se diferencia de los archivos secuenciales y no se puede ver el contenido de la misma forma que los secuenciales sino a través de la ejecución misma del programa. 3.-Hacer un listado de las órdenes del fortran que aparecen en el programa y escriba las definiciones de estas sentencias A Database: Student Records In this section we combine the elegance of Fortran 90 derived types with direct access files to build a program toillustratethe basic principles of setting up, displaying, and updating a database. Suppose we want to set up a database of student records (by record we mean the information relating to each student). For simplicity let's record each student's name (including initials), and one integer mark (in practice this is more likely to be an array of marks). The obvious vehicle for this is a derived type,similartothatdefined intheprevious section: TYPE StudentRecord CHARACTER (NameLen) Name INTEGER Mark END TYPE StudentRecord We need a collection of subroutines to read and write variables of this type to and from a direct access file. The program template follows. Details of the subroutines are filled in below. For ease of presentation the subroutines are internal. This also makes it easier for you to run and develop the program. Consequently, the file is opened once, at the beginning of the program, and closed only at the end. In a real application, the subroutines would probably be in a module, with some global declarations, such as the type definition, the file name, etc. In that case, each subroutine which handlesthefile should open and closeit. The program outlineis: PROGRAM Student_Records IMPLICIT NONE INTEGER, PARAMETER :: NameLen = 20 TYPE StudentRecord CHARACTER (NameLen) Name INTEGER Mark END TYPE StudentRecord TYPE (StudentRecord) Student INTEGER EOF, RecLen, RecNo LOGICAL IsThere CHARACTER (NameLen) FileName

Upload: gabriel-ward

Post on 10-Sep-2015

219 views

Category:

Documents


3 download

DESCRIPTION

practica

TRANSCRIPT

PRACTICA FINAL DEL CURSO DE LENGUAJE DE PROGRAMACION2015-IProcedimiento1.- Traducir el documento en forma correcta los prrafos correspondientes en el orden que se presenta, debe tener en cuenta que hay segmentos de programas que van a formar un programa que permitir crear un archivo de acceso directo2.- El programa completo aparece desde la pgina 6, copie y ejecute el programa en forma correcta, modifique la presentacin, observe al final la ejecucin, en la ejecucin del programa deber presentar todos los casos que presenta el men del programa.Los archivos de acceso directo se diferencia de los archivos secuenciales y no se puede ver el contenido de la misma forma que los secuenciales sino a travs de la ejecucin misma del programa.3.-Hacer un listado de las rdenes del fortran que aparecen en el programa y escriba las definiciones de estas sentenciasA Database: Student RecordsIn this section we combine the elegance of Fortran 90 derived types with direct access files to build a program toillustratethe basic principles of setting up, displaying, and updating a database.Suppose we want to set up a database of student records (by record we mean the information relating to each student). For simplicity let's record each student's name (including initials), and one integer mark (in practice this is more likely to be an array of marks). The obvious vehicle for this is a derived type,similartothatdefined intheprevious section:TYPE StudentRecordCHARACTER (NameLen) NameINTEGER MarkEND TYPE StudentRecordWe need a collection of subroutines to read and write variables of this type to and from a direct access file. The program template follows. Details of the subroutines are filled in below. For ease of presentation the subroutines are internal. This also makes it easier for you to run and develop the program. Consequently, the file is opened once, at the beginning of the program, and closed only at the end. In a real application, the subroutines would probably be in a module, with some global declarations, such as the type definition, the file name, etc. In that case, each subroutine which handlesthefile should open and closeit.The program outlineis:PROGRAM Student_RecordsIMPLICIT NONEINTEGER, PARAMETER :: NameLen = 20TYPE StudentRecordCHARACTER (NameLen) NameINTEGER MarkEND TYPE StudentRecordTYPE (StudentRecord) StudentINTEGER EOF, RecLen, RecNoLOGICAL IsThereCHARACTER (NameLen) FileNameCHARACTER AnsCHARACTER (7) FileStatusCHARACTER (*), PARAMETER :: NameChars = &" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"INQUIRE (IOLENGTH = RecLen) StudentWRITE (*, "('File name: ')", ADVANCE = "NO")READ*, FileNameINQUIRE (FILE = FileName, EXIST = IsThere)IF (IsThere) THENWRITE (*, "('File already exists. Erase and recreate (Y/N)? ')", &ADVANCE = "NO")READ*, AnsIF (Ans == "Y") THENFileStatus = "REPLACE" ! erase and start againELSEFileStatus = "OLD" ! update existing fileEND IFELSEFileStatus = "NEW" ! it isn't there, so create itEND IFOPEN (1, FILE = FileName, STATUS = FileStatus, &ACCESS = 'DIRECT', RECL = RecLen)Ans = "" ! make sure we get startedDO WHILE (Ans /= "Q")PRINT*PRINT*, "A: Add new records"PRINT*, "D: Display all records"PRINT*, "Q: Quit"PRINT*, "U: Update existing records"PRINT*WRITE (*, "('Enter option and press ENTER: ')", ADVANCE = "NO")READ*, AnsSELECT CASE (Ans)CASE ("A", "a")CALL AddRecordsCASE ("D", "d")CALL DisplayRecordsCASE ("U", "u")CALL UpDateEND SELECTEND DOCLOSE (1)CONTAINSSUBROUTINE AddRecords...SUBROUTINE DisplayRecords...SUBROUTINE ReadIntCon( Num )...SUBROUTINE StripBlanks( Str )...SUBROUTINE UpDate...END

The length of the component Name of StudentRecord is declared as a named constantNameLen becausethis valueis used in a number of otherdeclarations.The basic variable in the program is Student, of type StudentRecord. An INQUIRE statement determinesitsrecord lengthforthe subsequent OPEN statement.The user is asked for the file name of the database. Another INQUIRE statement determines whether or not the file exists. A value is set for the STATUS specifier in the OPEN statement, depending on whether the file is to be replaced, updated or created, after which the file is opened. If the value of STATUS has been correctly set, the OPEN must succeed; otherwise you need to cater for errorrecoverywiththe IOSTAT and/or ERR specifiers.Next, a menu is presented. The ideal construct for this is DO WHILE. The user enters a single letter response. A CASE construct selects the appropriate subroutine. An important point to note here is that the response may be in lower- or uppercase. Since other responses will be required in the program, it makes sense to write a function to convert the response to uppercase, say, before testing it. Itriedtoinclude such afunction,

FUNCTION ChToUpper( Ch )! converts a single lowercase character to uppercase! leaves all other characters unchangedCHARACTER Ch, ChToUpperChToUpper = ChSELECT CASE (Ch)CASE ( "a":"z" )ChToUpper = CHAR( ICHAR(Ch) + ICHAR("A") - ICHAR("a") )END SELECTEND FUNCTION ChToUpper

but a bug in the FTN90 compiler caused a run-time error when it was included in the database program (although itran successfully on itsown in atest program).When the userquits,the databasefileis closed.Now for the subroutines. AddRecords adds new records, either at the end of an existing database, or atthe beginning of a new one.

SUBROUTINE AddRecordsRecNo = 0EOF = 0 ! remember to initializeDO WHILE (EOF == 0)READ( 1, REC = RecNo+1, IOSTAT = EOF )IF (EOF == 0) THEN ! read succeeded, so ...RecNo = RecNo + 1 ! ... only increment RecNo hereEND IFEND DORecNo = RecNo + 1 ! next record to writeStudent = StudentRecord( "a", 0 ) ! satisfy DO WHILEDO WHILE ((VERIFY( Student % Name, NameChars ) == 0))PRINT*, "Name (any non-letter/non-blank to end): "READ "(A20)", Student % NameIF (VERIFY( Student % Name, NameChars ) == 0) THENPRINT*, "Mark: "CALL ReadIntCon( Student % Mark )WRITE (1, REC = RecNo) StudentRecNo = RecNo + 1END IFEND DOEND SUBROUTINE AddRecords

Fortran 90 unfortunately has no way of determining the number of records in a file, other than by reading past all of them. The first DO WHILE sets RecNo to the number of records in the file. Note that a READ with no inputlistskips past arecord;thissavestime.EOF must be initialized to zero on entry to the subroutine,because it is a global variable, so it will usually have a non-zero value from the lasttime the end-of-file was encountered. This provides a good reason for declaring EOF locally to force you toinitializeit correctly.A DO WHILE loop accepts students' names from the keyboard. In this example, it is assumed that names will consist only of letters or blanks (e.g. between the surname and initials). So any carcter other than a letter or a blank will end the loop. VERIFY ensures that only a genuine name is written tothefile.Remember that READ* assumes that a string without delimiters is terminated by a blank, so if you want to read blanks as part of the string you must either use a formatted READ or enclose the string in delimiters.Both components of Student are written to record number RecNo by the single WRITEstatementafter which RecNo must beincremented.If you ever have to write a program of this nature which other people will use, you will son discover that most of your programming effort will go into anticipating and trapping their stupid mistakes. In particular, a crash must be avoided if the user makes an invalid response. The short subroutine ReadIntCon makes use ofthe IOSTAT specifiertointercept a READ error:

SUBROUTINE ReadIntCon( Num )INTEGER Err, NumErr = 1 ! remember to initializeDO WHILE (Err > 0)READ (*, *, IOSTAT = Err) NumIF (Err > 0) PRINT*, "Error in mark - re-enter"END DOEND SUBROUTINE ReadIntCon

DisplayRecords uses a DO WHILE construct to read and display the file contents. The end-offileis detectedby theIOSTAT specifier:

SUBROUTINE DisplayRecordsRecNo = 1EOF = 0 ! remember to initializeDO WHILE (EOF == 0)READ (1, REC = RecNo, IOSTAT = EOF) StudentIF (EOF == 0) THENPRINT "(A20, I3)", Student ! READ succeededEND IFRecNo = RecNo + 1END DOEND SUBROUTINE DisplayRecords

The subroutine UpDate takes care of updating a student'srecord (in this example, only his single mark may be changed, but obviouslythis can be extended to correcting spellingin his name, etc.):

SUBROUTINE UpDateCHARACTER (NameLen) Item, CopyLOGICAL FoundFound = .false.EOF = 0 ! remember to initializePRINT*, "Update who?"READ "(A20)", ItemCALL StripBlanks( Item )RecNo = 1DO WHILE (EOF == 0 .AND. .NOT. Found)READ (1, IOSTAT = EOF, REC = RecNo) StudentIF (EOF == 0) THENCopy = Student % NameCALL StripBlanks( Copy ) ! leave his name as isIF (Item == Copy) THENFound = .true. ! found himPRINT*, 'Found at recno', RecNo, ' Enter new mark:'CALL ReadIntCon( Student % Mark ) ! new markWRITE (1, REC = RecNo) Student ! rewriteELSERecNo = RecNo + 1END IFEND IFEND DOIF (.NOT. Found) THENPRINT*, Item, ' not found'END IFEND SUBROUTINE UpDate

UpDate asks for the name of the student whose mark is to be changed, and then searches for that student. The logical variable Found will be set to TRUEif the student is found. Initially, it must be setto FALSE.You may betempted heretohave aninitialization expression inits declaration, e.g. LOGICAL :: Found = .false.However, this automatically gives LOGICAL the SAVE attribute, i.e. its value is retained between calls to UpDate. This would give it the value TRUE on entry again after a successful search, making itimpossibleto executethe DO WHILE.

The name to be searched for is read into Item. You may want to build in some embellishments here to facilitate getting an exact match with the name in Student % Name. For example, all the characters in Item and Student % Name could be converted to uppercase before searching. In this example, all blanks areremoved by StripBlanks:

SUBROUTINE StripBlanks( Str )CHARACTER (*) StrINTEGER II = 1DO WHILE (I < LEN_TRIM( Str )) ! null str won't matterIF (Str(I:I) == " ") THENStr(I:) = Str(I+1:) ! don't increase I yetELSEI = I + 1END IFEND DOEND SUBROUTINE StripBlanks

There is only one subtlety in this routine. If a blank is found in position I, it is removed with the substring operation Str(I:) = Str(I+1:)However, I must not be incremented, since another blank might have moved up into position I. It must therefore be tested again. Only when a blank is not found may I be safely incremented.LEN_TRIM returnsthelength of Str. As blanks areremoved this value will of course be reduced. To keep matters simple, the searching procedure is the crudest one possibleread each record in the file from the beginning, untileither a match is found, or the end-of-file is reached. If a match is found update the mark and rewrite that record. If no match is found, report so. More sophisticated searching procedures are discussed below you can buildthem intothis program if you like.Once UpDate hasfound a match,the user entersthe corrected mark, and therecordisrewritten. You can easily add other features to this basic skeleton, e.g. printing names and marks, analysing the marks, deleting a name, etc.You could also extend the databasetoinclude an array of marks.Practically the only disadvantage of using a direct access file, as opposed to a text file, is that the record length is fixed. So if you wanted to allow for an array of, say, 20 marks, the record length must be increased, even though you may never use the extra space. One way out is to create a new direct access file each time a new set of marks is entered, with room for only one additional mark,and torename it withthe original name.

PROGRAM Student_RecordsIMPLICIT NONEINTEGER, PARAMETER :: NameLen = 20TYPE StudentRecordCHARACTER (NameLen) NameINTEGER MarkEND TYPE StudentRecordTYPE (StudentRecord) StudentINTEGER EOF, RecLen, RecNoLOGICAL IsThereCHARACTER (NameLen) FileNameCHARACTER AnsCHARACTER (7) FileStatusCHARACTER (*), PARAMETER :: NameChars =" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"INQUIRE (IOLENGTH = RecLen) StudentWRITE (*, "('File name: ')", ADVANCE = "NO")READ*, FileNameINQUIRE (FILE = FileName, EXIST = IsThere)IF (IsThere) THENWRITE (*, "('File already exists. Erase and recreate (Y/N)? ')",ADVANCE = "NO")READ*, AnsIF (Ans == "Y") THENFileStatus = "REPLACE" ! erase and start againELSEFileStatus = "OLD" ! update existing fileEND IFELSEFileStatus = "NEW" ! it isn't there, so create itEND IFOPEN (1,FILE = FileName, STATUS = FileStatus,ACCESS = 'DIRECT', RECL = RecLen)Ans = "" ! make sure we get startedDO WHILE (Ans /= "Q")PRINT*PRINT*, "A: Add new records"PRINT*, "D: Display all records"PRINT*, "Q: Quit"PRINT*, "U: Update existing records"PRINT*WRITE (*, "('Enter option and press ENTER: ')", ADVANCE = "NO")READ*, AnsSELECT CASE (Ans)CASE ("A", "a")CALL AddRecordsCASE ("D", "d")CALL DisplayRecordsCASE ("U", "u")CALL UpDateEND SELECTEND DOCLOSE (1)CONTAINS

SUBROUTINE AddRecordsRecNo = 0EOF = 0 ! remember to initializeDO WHILE (EOF == 0)READ( 1, REC = RecNo+1, IOSTAT = EOF )IF (EOF == 0) THEN ! read succeeded, so ...RecNo = RecNo + 1 ! ... only increment RecNo hereEND IFEND DORecNo = RecNo + 1 ! next record to writeStudent = StudentRecord( "a", 0 ) ! satisfy DO WHILEDO WHILE ((VERIFY( Student % Name, NameChars ) == 0))PRINT*, "Name (any non-letter/non-blank to end): "READ "(A20)", Student % NameIF (VERIFY( Student % Name, NameChars ) == 0) THENPRINT*, "Mark: "CALL ReadIntCon( Student % Mark )WRITE (1, REC = RecNo) StudentRecNo = RecNo + 1END IFEND DOEND SUBROUTINE AddRecords

SUBROUTINE DisplayRecordsRecNo = 1EOF = 0 ! remember to initializeDO WHILE (EOF == 0)READ (1, REC = RecNo, IOSTAT = EOF) StudentIF (EOF == 0) THENPRINT "(A20, I3)", Student ! READ succeededEND IFRecNo = RecNo + 1END DOEND SUBROUTINE DisplayRecords

SUBROUTINE ReadIntCon( Num )INTEGER Err, NumErr = 1 ! remember to initializeDO WHILE (Err > 0)READ (*, *, IOSTAT = Err) NumIF (Err > 0) PRINT*, "Error in mark - re-enter"END DOEND SUBROUTINE ReadIntCon

SUBROUTINE StripBlanks( Str )INTEGER ICHARACTER (NameLen) StrI = 1DO WHILE (I < LEN_TRIM( Str )) ! null str won't matterIF (Str(I:I) == " ") THENStr(I:) = Str(I+1:) ! don't increase I yetELSEI = I + 1END IFEND DOEND SUBROUTINE StripBlanks

SUBROUTINE UpDateCHARACTER (NameLen) Item, CopyLOGICAL FoundFound = .false.EOF = 0 ! remember to initializePRINT*, "Update who?"READ "(A20)", ItemCALL StripBlanks( Item )RecNo = 1DO WHILE (EOF == 0 .AND. .NOT. Found)READ (1, IOSTAT = EOF, REC = RecNo) StudentIF (EOF == 0) THENCopy = Student % NameCALL StripBlanks( Copy ) ! leave his name as isIF (Item == Copy) THENFound = .true. ! found himPRINT*, 'Found at recno', RecNo, ' Enter new mark:'CALL ReadIntCon( Student % Mark ) ! new markWRITE (1, REC = RecNo) Student ! rewriteELSERecNo = RecNo + 1END IFEND IFEND DOIF (.NOT. Found) THENPRINT*, Item, ' not found'END IFEND SUBROUTINE UpDate

END PROGRAM STUDENT_RECORDS