Sie sind auf Seite 1von 8

PRACTICA FINAL DEL CURSO DE LENGUAJE DE PROGRAMACION

2015-I

Procedimiento
1.- 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 directo
2.- 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 sentencias

A Database: Student Records


InthissectionwecombinetheeleganceofFortran90derivedtypeswithdirect
accessfilestobuildaprogramtoillustratethebasicprinciplesofsettingup,
displaying,andupdatingadatabase.
Supposewewanttosetupadatabaseofstudentrecords(by record wemeanthe
information relating to each student). For simplicity let's record each
student'sname(includinginitials),andoneintegermark(inpracticethisis
morelikelytobeanarrayofmarks).Theobviousvehicleforthisisaderived
type,similartothatdefinedintheprevioussection:
TYPE StudentRecord
CHARACTER (NameLen) Name
INTEGER Mark
END TYPE StudentRecord
Weneedacollectionofsubroutinestoreadandwritevariablesofthistypeto
and from a direct access file. The program template follows. Details of the
subroutinesarefilledinbelow.Foreaseofpresentationthesubroutinesare
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
closedonlyattheend.Inarealapplication,thesubroutineswouldprobablybe
in a module, with some global declarations, such as the type definition, the
filename,etc.Inthatcase,eachsubroutinewhichhandlesthefileshouldopen
andcloseit.
Theprogramoutlineis:
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
CHARACTER Ans
CHARACTER (7) FileStatus
CHARACTER (*), PARAMETER :: NameChars = &
" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
INQUIRE (IOLENGTH = RecLen) Student
WRITE (*, "('File name: ')", ADVANCE = "NO")
READ*, FileName
INQUIRE (FILE = FileName, EXIST = IsThere)
IF (IsThere) THEN
WRITE (*, "('File already exists. Erase and recreate (Y/N)? ')", &

ADVANCE = "NO")
READ*, Ans
IF (Ans == "Y") THEN
FileStatus = "REPLACE" ! erase and start again
ELSE
FileStatus = "OLD" ! update existing file
END IF
ELSE
FileStatus = "NEW" ! it isn't there, so create it
END IF
OPEN (1, FILE = FileName, STATUS = FileStatus, &
ACCESS = 'DIRECT', RECL = RecLen)
Ans = "" ! make sure we get started
DO 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*, Ans
SELECT CASE (Ans)
CASE ("A", "a")
CALL AddRecords
CASE ("D", "d")
CALL DisplayRecords
CASE ("U", "u")
CALL UpDate
END SELECT
END DO
CLOSE (1)
CONTAINS
SUBROUTINE AddRecords
...
SUBROUTINE DisplayRecords
...
SUBROUTINE ReadIntCon( Num )
...
SUBROUTINE StripBlanks( Str )
...
SUBROUTINE UpDate
...
END
ThelengthofthecomponentName ofStudentRecord isdeclaredasanamedconstant
NameLen becausethisvalueisusedinanumberofotherdeclarations.
Thebasicvariableintheprogramis Student,oftype StudentRecord.An INQUIRE
statementdeterminesitsrecordlengthforthesubsequentOPEN statement.
Theuserisaskedforthefilenameofthedatabase.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,updatedorcreated,afterwhichthefileisopened.Ifthevalueof
STATUS has been correctly set, the OPEN must succeed; otherwise you need to
caterforerrorrecoverywiththeIOSTAT and/orERR specifiers.
Next,amenuispresented.Theidealconstructforthisis DO WHILE.Theuser
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
loweroruppercase.Sinceotherresponseswillberequiredintheprogram,it
makes sense to write a function to convert the response to uppercase, say,
beforetestingit.Itriedtoincludesuchafunction,

FUNCTION ChToUpper( Ch )
! converts a single lowercase character to uppercase
! leaves all other characters unchanged
CHARACTER Ch, ChToUpper
ChToUpper = Ch
SELECT CASE (Ch)
CASE ( "a":"z" )
ChToUpper = CHAR( ICHAR(Ch) + ICHAR("A") - ICHAR("a") )
END SELECT
END FUNCTION ChToUpper
butabugintheFTN90compilercausedaruntimeerrorwhenitwasincludedin
thedatabaseprogram(althoughitransuccessfullyonitsowninatestprogram).
Whentheuserquits,thedatabasefileisclosed.
Nowforthesubroutines. AddRecords addsnewrecords,eitherattheendofan
existingdatabase,oratthebeginningofanewone.
SUBROUTINE AddRecords
RecNo = 0
EOF = 0 ! remember to initialize
DO WHILE (EOF == 0)
READ( 1, REC = RecNo+1, IOSTAT = EOF )
IF (EOF == 0) THEN ! read succeeded, so ...
RecNo = RecNo + 1 ! ... only increment RecNo here
END IF
END DO
RecNo = RecNo + 1 ! next record to write
Student = StudentRecord( "a", 0 ) ! satisfy DO WHILE
DO WHILE ((VERIFY( Student % Name, NameChars ) == 0))
PRINT*, "Name (any non-letter/non-blank to end): "
READ "(A20)", Student % Name
IF (VERIFY( Student % Name, NameChars ) == 0) THEN
PRINT*, "Mark: "
CALL ReadIntCon( Student % Mark )
WRITE (1, REC = RecNo) Student
RecNo = RecNo + 1
END IF
END DO
END SUBROUTINE AddRecords
Fortran90unfortunatelyhasnowayofdeterminingthenumberofrecordsina
file,otherthanbyreadingpastallofthem.ThefirstDO WHILE setsRecNo to
thenumberofrecordsinthefile.NotethataREAD withnoinputlistskipspast
arecord;thissavestime.
EOF must be initialized to zero on entry to the subroutine,because it is a
globalvariable,soitwillusuallyhaveanonzerovaluefromthelasttimethe
endoffilewasencountered.ThisprovidesagoodreasonfordeclaringEOF locally
toforceyoutoinitializeitcorrectly.
A DO WHILE loopacceptsstudents'namesfromthekeyboard.Inthisexample,it
isassumedthatnameswillconsistonlyoflettersorblanks(e.g.betweenthe
surnameandinitials).Soanycarcterotherthanaletterorablankwillend
theloop.VERIFY ensuresthatonlyagenuinenameiswrittentothefile.
RememberthatREAD* assumesthatastringwithoutdelimitersisterminatedbya
blank,soifyouwanttoreadblanksaspartofthestringyoumusteitherusea
formattedREAD orenclosethestringindelimiters.
BothcomponentsofStudent arewrittentorecordnumberRecNo bythesingleWRITE
statementafterwhichRecNo mustbeincremented.

Ifyoueverhavetowriteaprogramofthisnaturewhich other peoplewilluse,


you will son discover that most of your programming effort will go into
anticipating andtrapping their stupid mistakes.In particular,a crashmust be
avoidediftheusermakesaninvalidresponse.Theshortsubroutine ReadIntCon
makesuseoftheIOSTAT specifiertointerceptaREAD error:
SUBROUTINE ReadIntCon( Num )
INTEGER Err, Num
Err = 1 ! remember to initialize
DO WHILE (Err > 0)
READ (*, *, IOSTAT = Err) Num
IF (Err > 0) PRINT*, "Error in mark - re-enter"
END DO
END SUBROUTINE ReadIntCon
DisplayRecords usesaDO WHILE constructtoreadanddisplaythefilecontents.
TheendoffileisdetectedbytheIOSTAT specifier:
SUBROUTINE DisplayRecords
RecNo = 1
EOF = 0 ! remember to initialize
DO WHILE (EOF == 0)
READ (1, REC = RecNo, IOSTAT = EOF) Student
IF (EOF == 0) THEN
PRINT "(A20, I3)", Student ! READ succeeded
END IF
RecNo = RecNo + 1
END DO
END SUBROUTINE DisplayRecords
ThesubroutineUpDate takescareofupdatingastudent'srecord(inthisexample,
only his single mark may be changed, but obviouslythis can be extended to
correctingspellinginhisname,etc.):
SUBROUTINE UpDate
CHARACTER (NameLen) Item, Copy
LOGICAL Found
Found = .false.
EOF = 0 ! remember to initialize
PRINT*, "Update who?"
READ "(A20)", Item
CALL StripBlanks( Item )
RecNo = 1
DO WHILE (EOF == 0 .AND. .NOT. Found)
READ (1, IOSTAT = EOF, REC = RecNo) Student
IF (EOF == 0) THEN
Copy = Student % Name
CALL StripBlanks( Copy ) ! leave his name as is
IF (Item == Copy) THEN
Found = .true. ! found him
PRINT*, 'Found at recno', RecNo, ' Enter new mark:'
CALL ReadIntCon( Student % Mark ) ! new mark
WRITE (1, REC = RecNo) Student ! rewrite
ELSE
RecNo = RecNo + 1
END IF
END IF
END DO
IF (.NOT. Found) THEN
PRINT*, Item, ' not found'
END IF
END SUBROUTINE UpDate

UpDate asksforthenameofthestudentwhosemarkistobechanged,andthen
searchesforthatstudent.ThelogicalvariableFound willbesettoTRUEifthe
studentisfound.Initially,itmustbesettoFALSE.Youmaybetemptedheretohave
aninitializationexpressioninitsdeclaration,e.g.LOGICAL :: Found = .false.
However,thisautomaticallygivesLOGICAL theSAVE attribute,i.e.its value is retained
between calls to UpDate.Thiswouldgiveitthevalue TRUE onentryagainaftera
successfulsearch,makingitimpossibletoexecutetheDO WHILE.
Thenametobesearchedforisreadinto Item.Youmaywanttobuildinsome
embellishments here to facilitate getting an exact match with the name in
Student % Name.Forexample,allthecharactersinItem andStudent % Name could
be converted to uppercase before searching. In this example, all blanks
areremovedbyStripBlanks:
SUBROUTINE StripBlanks( Str )
CHARACTER (*) Str
INTEGER I
I=1
DO WHILE (I < LEN_TRIM( Str )) ! null str won't matter
IF (Str(I:I) == " ") THEN
Str(I:) = Str(I+1:) ! don't increase I yet
ELSE
I=I+1
END IF
END DO
END SUBROUTINE StripBlanks
Thereisonlyonesubtletyinthisroutine.Ifablankisfoundinposition I,
itisremovedwiththesubstringoperationStr(I:) = Str(I+1:)
However,I mustnotbeincremented,sinceanotherblankmighthavemovedupinto
position I.Itmustthereforebetestedagain.Onlywhenablankisnotfound
mayI besafelyincremented.
LEN_TRIM returnsthelengthofStr.Asblanksareremovedthisvaluewillofcourse
bereduced.Tokeepmatterssimple,thesearchingprocedureisthecrudestone
possiblereadeachrecordinthefilefromthebeginning,untileitheramatchis
found,ortheendoffileisreached.Ifamatchisfoundupdatethemarkand
rewrite that record. If no match is found, report so. More sophisticated
searchingproceduresarediscussedbelowyoucanbuildthemintothisprogramif
youlike.
Once UpDate hasfound a match,the user entersthe corrected mark, and
therecordisrewritten.Youcaneasilyaddotherfeaturestothisbasicskeleton,
e.g. printing names and marks, analysing the marks, deleting a name, etc.You
couldalsoextendthedatabasetoincludeanarrayofmarks.
Practicallytheonlydisadvantageofusingadirectaccessfile,asopposedtoa
textfile,isthattherecordlengthisfixed.Soifyouwantedtoallowforan
arrayof,say,20marks,therecordlengthmustbeincreased,eventhoughyou
mayneverusetheextraspace.Onewayoutistocreateanewdirectaccessfile
eachtimeanewsetofmarksisentered,withroomforonlyoneadditionalmark,
andtorenameitwiththeoriginalname.

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
CHARACTER Ans
CHARACTER (7) FileStatus
CHARACTER (*), PARAMETER :: NameChars ="
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

INQUIRE (IOLENGTH = RecLen) Student


WRITE (*, "('File name: ')", ADVANCE = "NO")
READ*, FileName
INQUIRE (FILE = FileName, EXIST = IsThere)
IF (IsThere) THEN
WRITE (*, "('File already exists. Erase and recreate (Y/N)? ')",ADVANCE = "NO")
READ*, Ans
IF (Ans == "Y") THEN
FileStatus = "REPLACE" ! erase and start again
ELSE
FileStatus = "OLD" ! update existing file
END IF
ELSE
FileStatus = "NEW" ! it isn't there, so create it
END IF
OPEN (1,FILE = FileName, STATUS = FileStatus,ACCESS = 'DIRECT', RECL = RecLen)
Ans = "" ! make sure we get started
DO 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*, Ans
SELECT CASE (Ans)
CASE ("A", "a")
CALL AddRecords
CASE ("D", "d")
CALL DisplayRecords
CASE ("U", "u")
CALL UpDate
END SELECT
END DO
CLOSE (1)
CONTAINS
SUBROUTINE AddRecords
RecNo = 0
EOF = 0 ! remember to initialize

DO WHILE (EOF == 0)
READ( 1, REC = RecNo+1, IOSTAT = EOF )
IF (EOF == 0) THEN ! read succeeded, so ...
RecNo = RecNo + 1 ! ... only increment RecNo here
END IF
END DO
RecNo = RecNo + 1 ! next record to write
Student = StudentRecord( "a", 0 ) ! satisfy DO WHILE
DO WHILE ((VERIFY( Student % Name, NameChars ) == 0))
PRINT*, "Name (any non-letter/non-blank to end): "
READ "(A20)", Student % Name
IF (VERIFY( Student % Name, NameChars ) == 0) THEN
PRINT*, "Mark: "
CALL ReadIntCon( Student % Mark )
WRITE (1, REC = RecNo) Student
RecNo = RecNo + 1
END IF
END DO
END SUBROUTINE AddRecords
SUBROUTINE DisplayRecords
RecNo = 1
EOF = 0 ! remember to initialize
DO WHILE (EOF == 0)
READ (1, REC = RecNo, IOSTAT = EOF) Student
IF (EOF == 0) THEN
PRINT "(A20, I3)", Student ! READ succeeded
END IF
RecNo = RecNo + 1
END DO
END SUBROUTINE DisplayRecords
SUBROUTINE ReadIntCon( Num )
INTEGER Err, Num
Err = 1 ! remember to initialize
DO WHILE (Err > 0)
READ (*, *, IOSTAT = Err) Num
IF (Err > 0) PRINT*, "Error in mark - re-enter"
END DO
END SUBROUTINE ReadIntCon
SUBROUTINE StripBlanks( Str )
INTEGER I
CHARACTER (NameLen) Str
I=1
DO WHILE (I < LEN_TRIM( Str )) ! null str won't matter
IF (Str(I:I) == " ") THEN
Str(I:) = Str(I+1:) ! don't increase I yet
ELSE
I=I+1
END IF
END DO
END SUBROUTINE StripBlanks
SUBROUTINE UpDate
CHARACTER (NameLen) Item, Copy

LOGICAL Found
Found = .false.
EOF = 0 ! remember to initialize
PRINT*, "Update who?"
READ "(A20)", Item
CALL StripBlanks( Item )
RecNo = 1
DO WHILE (EOF == 0 .AND. .NOT. Found)
READ (1, IOSTAT = EOF, REC = RecNo) Student
IF (EOF == 0) THEN
Copy = Student % Name
CALL StripBlanks( Copy ) ! leave his name as is
IF (Item == Copy) THEN
Found = .true. ! found him
PRINT*, 'Found at recno', RecNo, ' Enter new mark:'
CALL ReadIntCon( Student % Mark ) ! new mark
WRITE (1, REC = RecNo) Student ! rewrite
ELSE
RecNo = RecNo + 1
END IF
END IF
END DO
IF (.NOT. Found) THEN
PRINT*, Item, ' not found'
END IF
END SUBROUTINE UpDate
END PROGRAM STUDENT_RECORDS

Das könnte Ihnen auch gefallen