Subsections

4 Διάλεξη Τέταρτη - 16 Δεκεμβρίου 2011

4.1 Μεταβλητές τύπου STRING

Μια μεταβλητή τύπου STRING στην qbasic, που δηλώνεται π.χ.

DIM s AS STRING
είναι μια μεταβλητή της οποίας οι τιμές είναι «λέξεις» όπως οι
"abcdef", "abcd 1234", "(*/()*)*@)", "".
Μια τέτοια μεταβλητή έχει ένα μήκος, δηλ. το πόσα γράμματα περιέχει (τα γράμματα δεν είναι απαραίτητα γράμματα της αλφαβήτου αλλά μπορούν και να είναι άλλα σύμβολα που είτε εμφανίζονται στο πληκτρολόγιο του υπολογιστή είτε όχι). Για να υπολογίσουμε το μήκος ενός STRING s στην qbasic χρησιμοποιούμε τη συνάρτηση βιβλιοθήκης LEN(s). Έτσι LEN("abc") είναι 3, LEN("ab cd") είναι 5 και LEN("") είναι 0 (το "" είναι αυτό που ονομάζουμε κενή λέξη, δεν περιέχει δηλ. κανένα χαρακτήρα).

Στο παρακάτω πρόγραμμα δείχνουμε πώς μπορούμε να διαβάσουμε ένα STRING από το χρήστη.



   1 ' This program demonstrates how the computer
   2 ' reads a string variable from the user
   3 CLS
   4 DIM s AS STRING
   5 DIM x AS INTEGER
   6 
   7 ' Prompt the user to give a number and a string,
   8 ' in the same line, separated by a comma 
   9 PRINT "Give x, s:";
  10 ' read the number and the string
  11 INPUT x, s
  12 
  13 ' Show x and s. Observe that leading and trailing spaces are
  14 ' removed from s
  15 PRINT "x="; x; ", s=["; s; "]"
  16 ' Show also the lenth of s
  17 PRINT "Length of s="; LEN(s)

Το αρχείο l4/readstr.bas


Το πρόγραμμα αυτό είναι πολύ απλό αλλά αξίζει να το τρέξει κανείς και να παρατηρήσει ορισμένα πράγματα. Στη γραμμή 11 διαβάζουμε από το χρήστη ένα αριθμό x και ένα STRING s στην ίδια γραμμή. Ο υπολογιστής περιμένει ότι αυτά θα είναι διαχωρισμένα από ένα κόμμα. Παρατηρείστε επίσης (τρέχοντας το πρόγραμμα) ότι αν δώσετε κάτι σαν

32, abcd efg
(ένα αριθμό 32, κόμμα, μερικά κενά, μετά κάποια γράμματα και τέλος κάμποσα κενά πριν πατήσετε το enter) τότε το STRING που διαβάζει ο υπολογιστής είναι το "abcd efg". Ο υπολογιστής δηλ. «τρώει» τους κενούς χαρακτήρες πριν το a και μετά το g. Το STRING Που διαβάσαμε το τυπώνουμε στη γραμμή 15, ανάμεσα στους χαρακτήρες [ και ] ώστε να βλέπουμε ακριβώς από που αρχίζει και πού τελειώνει.

Αυτό είναι σημαντικό να το έχουμε υπόψιν μας. Για παράδειγμα, αυτό μας εμποδίζει να δώσουμε ένα STRING ως input το οποίο να περιέχει κόμμα (δοκιμάστε το). Ένας τρόπος να το κάνουμε αυτό είναι με την εντολή LINE INPUT που είναι ένα είδος INPUT ειδικά για STRING και το οποίο διαβάζει ολόκληρη τη γραμμή που θα δώσει ο χρήστης, μέχρι το enter, ό,τι κι αν αυτή περιέχει. Για παράδειγμα γράψτε και δοκιμάστε το ακόλουθο πρόγραμμα:

CLS
DIM s AS STRING
LINE INPUT s
PRINT "["; s ; "]"
Θα δείτε ότι θα διαβαστεί ακριβώς ό,τι κι αν πατήσετε μέχρι να πατήσετε το enter.

Ας δούμε τώρα το πώς μπορούμε να χειριστούμε τα εσωτερικά γράμματα ενός STRING. Ως παράδειγμα χρησιμοποιούμε το παρακάτω πρόγραμμα που σκοπό έχει να διαβάσει ένα STRING από το χρήστη και να το τυπώσει με τα γράμματά του ανάποδα (πρώτο γράμμα τυπώνεται το τελευταίο, δεύτερο γράμμα τυπώνεται το προτελευταίο κλπ).



   1 ' This program reads a string (text) from the user
   2 ' and prints it in reverse
   3 CLS
   4 DIM s AS STRING
   5 DIM t AS STRING
   6 DIM i, l AS INTEGER
   7 
   8 ' Read the string from the user
   9 INPUT "Give s: "; s
  10 
  11 ' Compute the length of the string (how many letters it contains)
  12 l = LEN(s)
  13 
  14 ' set t initially to be the empty string
  15 t = ""
  16 
  17 ' The next loop appends the letters of the string s to t,
  18 ' one at a time and starting from the last letter of s 
  19 FOR i = l TO 1 STEP -1
  20  t = t + MID$(s, i, 1)
  21  ' if you want to see the string t as it gets larger and larger then
  22  ' uncomment the following line
  23  'PRINT "["; t; "]"
  24 NEXT
  25 
  26 ' Now show t, the string s reversed
  27 PRINT t

Το αρχείο l4/revstr.bas


Στις γραμμές 4-6 δηλώνουμε τις μεταβλητές μας και στη γραμμή 9 διαβάζουμε από το χρήστη ένα STRING s του οποίου το μήκος υπολογίζουμε στη μεταβλητή l στη γραμμή 12. Θέτουμε έπειτα το STRING t στην αρχική τιμή "", δηλ. στην κενή λέξη (μήκος 0).

Στην ανακύκλωση FOR (γραμμές 19-24) παίρνουμε τα γράμματα της λέξης s ένα-ένα, από το τελευταίο ως το πρώτο (παρατηρείστε ότι ο δείκτης i στο FOR κατεβαίνει από το l στο 1, χρησιμοποιώντας τη συνάρτηση MID$.

Η συνάρτηση MID$ παίρνει ως ορίσματα το STRING s, μια θέση i μέσα στο STRING (το i αυτό κυμαίνεται από 1 έως το μήκος του STRING) και ως τρίτο όρισμα ένα μήκος k (στο πρόγραμμα revstr.bas παραπάνω το k που χρησιμοποιούμε είναι ίσο με 1). Έτσι

MID$(s, i, k)
είναι εκείνη η λέξη που ξεκινά από το i-οστό γράμμα της λέξης s και έχει μήκος k. Έτσι στο πρόγραμμα revstr.bas παραπάνω η ποσότητα MID$(s, i, 1) είναι μια λέξη που αποτελείται από ακριβώς ένα γράμμα, το i-οστό γράμμα της λέξης s.

Ποιο ακριβώς είναι το νόημα της γραμμής 11 τότε; Κατ΄αρχήν, αν έχουμε δύο STRING x και y τότε η έκφραση

x+y
δεν είναι παρά το STRING που αρχίζει ως x και ακολουθείται από το y. Το σύμβολο (πράξη) δηλ. + όταν εφαρμόζεται σε λέξεις έχει το νόημα της συγκόλλησης (concatenation). Για παράδειγμα η εντολή
PRINT "abcd" + "efg"
τυπώνει
abcdefg
Η γραμμή 11 λοιπόν επαυξάνει τη λέξη t κατά το i-οστό γράμμα της λέξης s από τα δεξιά. Το αποτέλεσμα είναι ότι αν η λέξη s αποτελείται από τα γράμματα

\begin{displaymath}
s_1 s_2 \ldots s_{r-1} s_r
\end{displaymath}

τότε η μεταβλητή t παίρνει διαδοχικά τις τιμές

\begin{eqnarray*}
s_r\\
s_r s_{r-1}\\
\cdots\\
s_r s_{r-1} \ldots s_2\\
s_r s_{r-1} \ldots s_2 s_1
\end{eqnarray*}


και καταλήγει μετά από την τελευταία εκτέλεση του FOR ισούται με τη λέξη s αντεστραμμένη. Αν θέλετε μπορείτε να δείτε ακριβώς αυτή την πορεία της μεταβλητής t βγάζοντας τον πρώτο απόστροφο από τη γραμμή 23 (καθιστώντας την έτσι εκτελέσιμη).

Άσκηση 4.1   Γράψτε ένα πρόγραμμα που να διαβάζει μια λέξη από το χρήστη, έστω τη λέξη

\begin{displaymath}
w_1 w_2 \ldots w_n
\end{displaymath}

(τα $w_1, w_2, \ldots, w_n$ είναι τα γράμματα της λέξης) και φτιάχνει ένα STRING του που περιέχει τη λέξη αυτή ακολουθούμενη από την αντίστροφή της:

\begin{displaymath}
w_1 w_2 \ldots w_n w_n w_{n-1} \ldots w_2 w_1
\end{displaymath}

την οποία ακολούθως τυπώνει στην οθόνη.

4.2 Διάβασμα από και γράψιμο σε αρχεία στο δίσκο

Εδώ θα δούμε πώς μπορούμε να διαβάσουμε από αρχεία στο δίσκο και επίσης το πώς να γράψουμε σε αρχεία στο δίσκο.

Για αρχή, αντιγράψτε το αρχείο list.txt που βλέπετε παρακάτω στον κατάλογο (directory) όπου βρίσκεται το πρόγραμμα QBASIX.EXE στον υπολογιστή σας. Για να το κάνετε αυτό κάντε δεξί κλικ στο όνομα του αρχείου που φαίνεται ακριβώς κάτω από τα περιεχόμενά του παρακάτω και επιλέξτε Save ή Αποθήκευση.



   1 3
   2 Mihalis
   3 45
   4 Manolis
   5 54
   6 Yannis
   7 3

Το αρχείο l4/list.txt


Τα περιεχόμενα του αρχείου αυτού υποτίθεται ότι είναι τα ονόματα και οι ηλικίες κάποιων ατόμων. Στην πρώτη γραμμή του αρχείου είναι ο αριθμός 3 που υποδηλώνει ότι ακολουθούν οι πληροφορίες για 3 άτομα. Για κάθε άτομο υπάρχει μια γραμμή με το όνομά του που ακολουθείται από μια γραμμή που περιέχει ένα αριθμό, την ηλικία του.

Σκοπός του προγράμματος readf.bas που ακολουθεί είναι να διαβάσουμε αυτό το αρχείο και να τυπώσουμε στην οθόνη τα άτομα αυτά μαζί με τις ηλικίες τους.



   1 ' This program reads n name-age pairs from
   2 ' a text file on disk
   3 CLS
   4 
   5 ' Open the file with name "list.txt" to be read from,
   6 ' as file #1
   7 OPEN "list.txt" FOR INPUT AS #1
   8 
   9 DIM n AS INTEGER
  10 DIM i AS INTEGER
  11 
  12 ' Read n, the first number in the file
  13 ' This tells us how many name-age pairs will follow
  14 INPUT #1, n
  15 ' Show the value read from the file
  16 PRINT "n="; n
  17 
  18 ' Declare the arrays that will hold the data
  19 DIM nm(n) AS STRING
  20 DIM age(n) AS INTEGER
  21 
  22 ' Read the name-age pairs from the file #1
  23 ' The file contains one line per data item
  24 FOR i = 1 TO n
  25  INPUT #1, nm(i)
  26  INPUT #1, age(i)
  27 NEXT
  28 
  29 ' Print the data read
  30 FOR i = 1 TO n
  31  PRINT nm(i); age(i)
  32 NEXT
  33 
  34 ' Now close the file before the program ends
  35 CLOSE #1

Το αρχείο l4/readf.bas


Στη γραμμή 7 ανοίγουμε το αρχείο με όνομα list.txt για διάβασμα (FOR INPUT) ως αρχείο #1. Από δω και πέρα θα αναφερόμαστε σε αυτό το (ανοιχτό πλέον) αρχείο ως #1 και όχι με το όνομά του (list.txt) που το χρησιμοποιούμε μόνο μια φορά για να το ανοίξουμε. Αφού τελειώσουμε το διάβασμα του αρχείου το κλείνουμε στη γραμμή 35 (η οποία θα μπορούσε και να έχει τοποθετηθεί πριν από την ανακύκλωση FOR της γραμμής 30, που δεν έχει να κάνει τίποτε με το αρχείο).

Ο πιο πρόσφορος τρόπος να φανταζόμαστε το διάβασμα από το αρχείο είναι ότι είναι ακριβώς όπως το διάβασμα από το πληκτρολόγιο (το «χρήστη») αλλά αντί να περιμένουμε το χρήστη να μας γράψει στο πληκτρολόγιο διαβάζουμε τις γραμμές του αρχείου τη μια μετά την άλλη.

Έτσι, στη γραμμή 14 διαβάζουμε από το αρχείο #1 την ακέραια μεταβλητή n από την πρώτη γραμμή του αρχείου. Στη γραμμή 16 τυπώνουμε στην οθόνη τον αριθμό που διαβάσαμε.

Έχοντας διαβάσει τον αριθμό που βρίσκεται στην πρώτη γραμμή του αρχείου ξέρουμε πλέον πόσα ζεύγη (όνομα, ηλικία) ακολουθούν στο αρχείο και μπορούμε να δηλώσουμε στις γραμμές 19 και 20 τους πίνακες nm και age όπου θα αποθηκευτούν αυτά τα στοιχεία αφού διαβαστούν. Οι πληροφορίες αυτές διαβάζονται από το αρχείο στην ανακύκλωση FOR Των γραμμών 24-27. Στην ανακύκλωση FOR των γραμμών 30-32 τυπώνουμε τις πληροφορίες που διαβάσουμε στην οθόνη.

Η διαδικασία που ακολουθούμε για να γράψουμε σε ένα αρχείο είναι εντελώς ανάλογη: ανοίγουμε το αρχείο για γράψιμο και χρησιμοποιούμε την εντολή PRINT για να γράψουμε στο αρχείο όπως θα γράφαμε και στην οθόνη.



   1 ' This program shows how to write some text to a file
   2 CLS
   3 
   4 ' Open the file with name 'a-file' for writing as file #1
   5 OPEN "a-file" FOR OUTPUT AS #1
   6 
   7 DIM i AS INTEGER
   8 
   9 ' Print this text to be the first line in the file
  10 PRINT #1, "The numbers from 1 to 10 and their squares:"
  11 
  12 ' Print one line per number to the file #1, containing
  13 ' number i and its square
  14 FOR i = 1 TO 10
  15  PRINT #1, i, i * i
  16 NEXT
  17 
  18 ' Close the file now
  19 CLOSE #1
  20 
  21 ' Print this message to show that we're done
  22 PRINT "File is now closed"

Το αρχείο l4/writef.bas


Στη γραμμή 5 ανοίγουμε ένα αρχείο με όνομα a-file για γράψιμο ως αρχείο #1. Όταν ανοίγουμε ένα αρχείο για γράψιμο τότε αν αυτό το αρχείο δεν υπάρχει τότε αυτό δημιουργείται. Αν πρόκειται για υπαρκτό αρχείο τότε τα περιεχόμενά του εξαφανίζονται και το αρχείο είναι πλέον κενό, ό,τι κι αν είχε μέσα πριν.

Στη γραμμή 10 τυπώνουμε ένα ενημερωτκό μήνυμα με PRINT, όπως εάν τυπώναμε στην οθόνη, μόνο που τώρα γράφονται στο αρχείο #1. Στη συνέχεια στην ανακύκλωση FOR στις γραμμές 14-16 τυπώνουμε στο αρχείο τους αριθμούς από 1 έως 10 μαζί με τα τετράγωνά τους. Κλείνουμε το αρχείο στη γραμμή 19.

Άσκηση 4.2   Γράψτε ένα πρόγραμμα που θα διαβάζει ένα ακέραιο αριθμό n από το χρήστη και ακολούθως θα διαβάζει n πραγματικούς (SINGLE) αριθμούς τους οποίους θα γράφει σε ένα αρχείο, του οποίου το όνομα θα έχει δώσει ο χρήστης στην αρχή. Έτσι το αρχείο που θα φτιάχνει το πρόγραμμά σας θα μοιάζει κάπως έτσι
4
1.3
2
-1.5
100
Στο παράδειγμα αυτό ο αριθμός 4 στην πρώτη γραμμή του αρχείου προσδιορίζει ότι ακολουθούν 4 πραγματικοί αριθμοί στο αρχείο αυτό.

Γράψτε επίσης ένα άλλο πρόγραμμα το οποίο θα ανοίγει το αρχείο που έφτιαξε το πρώτο για διάβασμα, αφού προηγουμένως ρωτήσει το χρήστη για το όνομά του, και θα διαβάζει τα περιεχόμενά του τα οποία και θα τυπώνει στην οθόνη. Το δεύτερο αυτό πρόγραμμα θα πρέπει να διαβάζει πρώτα την πρώτη γραμμή του αρχείου η οποία θα του λέει πόσες γραμμές με πραγματικούς αριθμούς ακολουθούν ώστε να ξέρει πόσους αριθμούς έχει να διαβάσει.

Mihalis Kolountzakis 2013-08-16