Anda di halaman 1dari 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
accessfilestobuildaprogramtoillustratethebasicprincipleofsettingup,
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

The length of the component Name of Student Record is declared as a named


constant
Name Len becausethisvalueisusedinanumberofotherdeclarations.
ThebasicvariableintheprogramisStudent,oftypeStudent Record.AnINQUIRE
statementdeterminesitsrecordlengthforthesubsequentOPEN statement.
Theuserisaskedforthefilenameofthedatabase.Another INQUIRE statement
determines whether or not the file exists. A value is set for the STATUS
specified 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 specifies.
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.Itridetoincludesuchafunction,

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
the database program (although iterant successfully on its own in a test
program).
Whentheuserquits,thedatabasefileisclosed.
Nowforthesubroutines. Add Records 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 setsRec No to
thenumberofrecordsinthefile.Notethata READ withnoinputlistskips
pastarecord;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).Soanycharacter otherthanaletterorablankwill
endtheloop.VERIFY ensuresthatonlyagenuinenameiswrittentothefile.
RememberthatREAD* assumesthatastringwithoutdelimitersisterminatedbya
blank,soifyouwanttoreadblanksaspartofthestringyoumusteitherusea
formattedREAD orenclosethestringindelimiters.
Both components of Student are written to record number Rec No by the single
WRITE
statementafterwhichRec No 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 Read In Con
makesuseoftheIOSTAT specifiedtointerceptaREAD 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

Display Records usesaDO WHILE constructtoreadanddisplaythefilecontents.


TheendoffileisdetectedbytheIOSTAT specified:

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

The subroutine Up Date takes care of updating a students record (in this
example,onlyhissinglemarkmaybechanged,butobviouslythiscanbeextended
tocorrectingspellinginhisname,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

Up Date asksforthenameofthestudentwhosemarkistobechanged,andthen
searchesforthatstudent.ThelogicalvariableFound willbesettoTRUE ifthe
studentisfound.Initially,itmustbesettoFALSE .Youmaybetemptedhereto
have an initialization expression in its declaration, e.g. LOGICAL :: Found =
.false.
However,thisautomaticallygivesLOGICAL theSAVE attribute,i.e.its value is retained
between calls to Up Date.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 are
removedbyStrip Blanks:

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 returns the length of Str. As blanks are removed 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, until
either a match is found, or the endoffile is reached. If a match is found
updatethemarkandrewritethatrecord.Ifnomatchisfound,reportso.More
sophisticatedsearchingproceduresarediscussedbelowyoucanbuildthemin
tothisprogramifyoulike.
Once Up Date hasfoundamatch,theuserentersthecorrectedmark,andthere
coderswritten.Youcaneasilyaddotherfeaturestothisbasicskeleton,e.g.
printingnamesandmarks,analyzingthemarks,deletinganame,etc.Youcould
alsoextendthedatabasetoincludeanarrayofmarks.
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

Anda mungkin juga menyukai