Λύσεις για τις ασκήσεις του lab5

Σχετικά έγγραφα
Βαθμός Σχόλια. lab6 PASS PASS. - Πολύ καλή δουλειά, αλλά προσπάθησε να κάνεις την άσκηση χρησιµοποιώντας συναρτήσεις από το string.

Sheet PASS 1426 PASS 1428 PASS. Page 1

ΕΡΓΑΣΤΗΡΙΟ 11 - Απαντήσεις

Παρακάτω δίνεται o σκελετός προγράμματος σε γλώσσα C. Σχολιάστε κάθε γραμμή του κώδικα.

lab14grades ΑΕΜ ΒΑΘΜΟΣ ΣΧΟΛΙΑ

Εισαγωγή στον Προγραμματισμό

2ο ΓΕΛ ΑΓ.ΔΗΜΗΤΡΙΟΥ ΑΕΠΠ ΘΕΟΔΟΣΙΟΥ ΔΙΟΝ ΠΡΟΣΟΧΗ ΣΤΑ ΠΑΡΑΚΑΤΩ

lab6grades ΑΕΜ ΒΑΘΜΟΣ ΣΧΟΛΙΑ Διαδικαστικά: Όλα οκ.

lab13grades 449 PASS 451 PASS PASS FAIL 1900 FAIL Page 1

lab13grades Άσκηση 2 -Σωστά απελευθερώνετε ολόκληρη τη λίστα και την κεφαλή

ΠΑΝΕΠΙΣΤΗΜΙΟ ΘΕΣΣΑΛΙΑΣ ΣΧΟΛΗ ΘΕΤΙΚΩΝ ΕΠΙΣΤΗΜΩΝ ΤΜΗΜΑ ΠΛΗΡΟΦΟΡΙΚΗΣ

ΠΑΝΕΠΙΣΤΗΜΙΟ ΘΕΣΣΑΛΙΑΣ ΣΧΟΛΗ ΘΕΤΙΚΩΝ ΕΠΙΣΤΗΜΩΝ ΤΜΗΜΑ ΠΛΗΡΟΦΟΡΙΚΗΣ

Προγραµµατισµός Ι ΕΡΓΑΣΤΗΡΙΟ 5 ΕΡΓΑΣΤΗΡΙΟ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ I, ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ

Sheet2 Α.Μ FAIL. οριακό PASS. - Έπρεπε να χρησιµοποιήσετε συναρτήσεις από τη string.h

FAIL PASS PASS οριακά

Εισαγωγή στην C. Μορφή Προγράµµατος σε γλώσσα C

ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ Η/Υ Ακαδημαϊκό έτος ΤΕΤΡΑΔΙΟ ΕΡΓΑΣΤΗΡΙΟΥ #4

ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΥΠΟΛΟΓΙΣΤΩΝ & ΥΠΟΛΟΓΙΣΤΙΚΗ ΦΥΣΙΚΗ

Χρησιμοποιείται για να αποφασίσει το πρόγραμμα αν θα κάνει κάτι σε ένα σημείο της εκτέλεσής του, εξετάζοντας αν ισχύει ή όχι μια συνθήκη.

Βαθμός Σχόλια. lab PASS 1194 PASS 1238 PASS 1239 PASS

Α. unsigned int Β. double. Γ. int. unsigned char x = 1; x = x + x ; x = x * x ; x = x ^ x ; printf("%u\n", x); Β. unsigned char

Κεφάλαιο 8.7. Πολυδιάστατοι Πίνακες (Διάλεξη 19)

Πίνακες. 1 Πίνακες. 30 Μαρτίου 2014

Ψευδοκώδικας. November 7, 2011

ΠΑΝΕΠΙΣΤΗΜΙΟ AΙΓΑIΟΥ & ΑΕΙ ΠΕΙΡΑΙΑ Τ.Τ. Τμήματα Ναυτιλίας και Επιχειρηματικών Υπηρεσιών & Μηχ. Αυτοματισμού ΤΕ. Εισαγωγή στη Python

Εισαγωγή στον Προγραμματισμό

Βαθμός Σχόλια. lab5 PASS PASS PASS PASS PASS. Οριακά PASS - Καλή δουλειά

Στη C++ υπάρχουν τρεις τύποι βρόχων: (a) while, (b) do while, και (c) for. Ακολουθεί η σύνταξη για κάθε μια:

Δομές Ακολουθίας- Επιλογής - Επανάληψης. Δομημένος Προγραμματισμός

Προγραμματισμός Η/Υ Ι (Χρήση της C) 6 η Θεωρία ΜΟΝΟΔΙΑΣΤΑΤΟΙ ΠΙΝΑΚΕΣ

ΕΝΤΟΛΕΣ ΕΠΑΝΑΛΗΨΗΣ. for (παράσταση_1; παράσταση_2; παράσταση_3) εντολή επόμενη εντολή

Προγραμματισμός Ι (ΗΥ120)

Γλώσσα Προγραμματισμού C

lab7grades -Σωστή χρήση της sprintf -Σωστά ανιχνεύετε τον χαρακτήρα που πρέπει να αφαιρέσετε. -Σωστή µεταφορά στοιχείων µια θέση αριστερά.

Προβλήματα, αλγόριθμοι, ψευδοκώδικας

ΕΡΓΑΣΤΗΡΙΟ 9: Συμβολοσειρές και Ορίσματα Γραμμής Εντολής

Βρόχοι. Εντολή επανάληψης. Το άθροισμα των αριθμών 1 5 υπολογίζεται με την εντολή. Πρόβλημα. Πώς θα υπολογίσουμε το άθροισμα των ακέραιων ;

ΤΕΜ-101 Εισαγωγή στους Η/Υ Εξεταστική Ιανουαρίου 2011 Θέματα Β

ΣΕΤ ΑΣΚΗΣΕΩΝ 1. Προθεσμία: Τετάρτη 9/11/2016, 21:00

Επανάληψη για τις Τελικές εξετάσεις. (Διάλεξη 24) ΕΠΛ 032: ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΜΕΘΟΔΩΝ ΕΠΙΛΥΣΗΣ ΠΡΟΒΛΗΜΑΤΩΝ

Διδάσκων: Κωνσταντίνος Κώστα Διαφάνειες: Δημήτρης Ζεϊναλιπούρ

lab10grades - Το αποτέλεσµα της τοµής θα έπρεπε να εµφανίζετε µέσα σε εισαγωγικά "Helo".

ΑΣΚΗΣΗ 2: ΔΟΜΗ ΠΡΟΓΡΑΜΜΑΤΟΣ C, ΧΕΙΡΙΣΜΟΣ ΜΕΤΑΒΛΗΤΩΝ ΚΑΙ ΣΥΝΑΡΤΗΣΕΙΣ ΕΙΣΟΔΟΥ ΚΑΙ ΕΞΟΔΟΥ

Αναφορά (1/2) Μπορούμε να ορίσουμε μια άλλη, ισοδύναμη αλλά ίσως πιο σύντομη, ονομασία για ποσότητα (μεταβλητή, σταθερή, συνάρτηση, κλπ.

Δείτε τώρα και πώς θα έπρεπε να ήταν το παραπάνω: Page 1

Δομή Προγράμματος C++, Χειρισμός Μεταβλητών και Συναρτήσεις Εισόδου - Εξόδου

Προγραµµατισµός Ι ΕΡΓΑΣΤΗΡΙΟ 5 ΕΡΓΑΣΤΗΡΙΟ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ I, ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ

Διάλεξη 2: Επανάληψη Προγραμματισμού Συμβολοσειρές (strings) Διδάσκων: Παναγιώτης Ανδρέου

ΕΡΓΑΣΤΗΡΙΟ 9: Συμβολοσειρές και Ορίσματα Γραμμής Εντολής

Προγραμματιστικό Περιβάλλον

ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΥΠΟΛΟΓΙΣΤΩΝ & ΥΠΟΛΟΓΙΣΤΙΚΗ ΦΥΣΙΚΗ

Προγραμματισμός Ι. Χαρακτήρες. Πανεπιστήμιο Πελοποννήσου Τμήμα Πληροφορικής & Τηλεπικοινωνιών

printf Οι κωδικοί (format codes) του printf για διάφορους τύπους δεδοµένων είναι:

Προγραμματισμός Ι. Δείκτες. Δημήτρης Μιχαήλ. Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

lab5 -Ο κώδικάς σου είναι σωστός αλλά από εδώ και στο εξής προσπάθησε να βάζεις σχόλια στην µορφή που ζητάει το φυλλάδιο

6. ΠΙΝΑΚΕΣ & ΑΛΦΑΡΙΘΜΗΤΙΚΑ

Εντολή Δεδομένα Περιεχόμενα μετά την εκτέλεση 1 read(x) 122 x= 2 read(a,b,c) a= b= c= 3 read(d,e)

Κεφάλαιο Αλφαριθμητικές Σειρές Χαρακτήρων (Strings) (Διάλεξη 20) 1) Strings στη C

4. ΒΡΟΧΟΙ ΕΠΑΝΑΛΗΨΗΣ (Α' μέρος: for)

ΣΕΤ ΑΣΚΗΣΕΩΝ 3. Προθεσµία: Πέµπτη 17/12/2015, 22:00

ΕΡΓΑΣΤΗΡΙΟ 3: Προγραμματιστικά Περιβάλλοντα και το Πρώτο Πρόγραμμα C

Εργαστηριακή Άσκηση 1

Η-Υ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ. Εργαστήριο 2 Εντολές Εισόδου/Εξόδου Τελεστές. Δρ. Γιώργος Λαμπρινίδης 23/10/2015 Η - Υ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ 1

Μεθόδων Επίλυσης Προβλημάτων

5. ΒΡΟΧΟΙ ΕΠΑΝΑΛΗΨΗΣ (Β' μέρος: while - do..while)

5ο σετ σημειώσεων - Δείκτες

ΣΕΤ ΑΣΚΗΣΕΩΝ 4. Προθεσμία: 17/1/14, 22:00

Πως θα αποθηκεύσει τη λίστα με τα ψώνια του και θα την ανακτήσει στο Σ/Μ; και πως θα προσθέσει στη λίστα του επιπλέον προϊόντα;

Γ7.5 Αλγόριθμοι Αναζήτησης. Γ Λυκείου Κατεύθυνσης

Προγραμματισμός Η/Υ (ΤΛ2007 )

ΑΝΑΠΤΥΞΗ ΕΦΑΡΜΟΓΩΝ Κεφάλαιο 3 ο

Η πρώτη παράμετρος είναι ένα αλφαριθμητικό μορφοποίησης

lab7 PASS -Δεν έχεις καθόλου σχόλια! Διάβασε το φυλλάδιο. PASS -Πολύ καλή εργασία µε σωστά και επεξηγηµατικά σχόλια. -Πρόσεξε την στοίχισή σου!

Γλώσσα Προγραμματισμού C. Προγραμματισμός HY: Γλώσσα Προγραμματισμού C. Γρήγορος Πίνακας Αναφοράς Σύνταξης. Εισήγηση #4. Επαναληπτικές δομές:

Δομές Επανάληψης. Εισαγωγή στη C++

Πατώντας την επιλογή αυτή, ανοίγει ένα παράθυρο που έχει την ίδια μορφή με αυτό που εμφανίζεται όταν δημιουργούμε μία μεταβλητή.

ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ Η/Υ Ακαδημαϊκό έτος ΤΕΤΡΑΔΙΟ ΕΡΓΑΣΤΗΡΙΟΥ #3

Δηλώσεις Εργαστηρίων

Η-Υ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ. Εργαστήριο 1 Εισαγωγή στη C. Σοφία Μπαλτζή s.mpaltzi@di.uoa.gr

Δομημένος Προγραμματισμός (ΤΛ1006)

Άσκηση 2: -Δεν παραδόθηκε. Το εµαιλ είχε λάθος θέµα. Έπρεπε να είναι CE120 lab6

ΑΝΤΙΓΡΑΦΗ ΑΡΧΕΙΟΥ ΣΕ ΔΙΣΚΕΤΑ ΑΝΤΙΓΡΑΦΗ ΑΡΧΕΙΟΥ ΑΠΟ ΔΙΣΚΕΤΑ. Από τον κατάλογο που εμφανίζεται επιλέγω: Αποστολή προς Δισκέτα (3,5)

lab2grades - Στη scanf υπολογίζετε τουλάχιστον 5 χαρακτήρες %5.2f προδιαγραφές που ζητούνται στην εκφώνηση. -

Προγραμματισμός Υπολογιστών & Υπολογιστική Φυσική

ΑΝΑΠΤΥΞΗ ΕΦΑΡΜΟΓΩΝ ομή Επανάληψης

ΦΥΛΛΑΔΙΟ ΕΡΓΑΣΤΗΡΙΟΥ 1

ΚΕΦΑΛΑΙΟ 9 ΒΑΣΙΚΕΣ ΕΝΤΟΛΕΣ

Προγραμματισμός Ι (ΗΥ120)

Προγραμματιστικές Ασκήσεις, Φυλλάδιο 1

Προγραµµατισµός Ι ΕΡΓΑΣΤΗΡΙΟ 2 ΕΡΓΑΣΤΗΡΙΟ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ I, ΑΚΑΔΗΜΑΪΚΟ ΕΤΟΣ

Οδηγίες για το CABRI - GEOMETRY II Μωυσιάδης Πολυχρόνης - Δόρτσιος Κώστας

Βαθμός Σχόλια. lab8. οριακά PASS 1194 PASS

lab2 -Στην printf να βάζεις \n έτσι ώστε να αλλάζει γραµµή όποτε σου εµφανίζει κάποιο µήνυµα.

Sheet1_2. - Δεν υπάρχουν σχόλια συναρτήσεων - Να χρησιµοποιείς πιο περιγραφικά ονόµατα µεταβλητών (και σίγουρα όχι απλούς χαρακτήρες όπως c, d) Page 1

3ο σετ σημειώσεων - Πίνακες, συμβολοσειρές, συναρτήσεις

Σκοπός. Εργαστήριο 6 Εντολές Επανάληψης Τα Εργαστηριακά Προγράμματα. Η δομή Επιλογής στη PASCAL. H δομή Επανάληψης στη PASCAL. Η εντολή επανάληψης for

EΒ ΟΜΑ Α 4 Η. οµές επανάληψης while και do while

ΠΑΝΕΠΙΣΤΗΜΙΟ ΘΕΣΣΑΛΙΑΣ ΣΧΟΛΗ ΘΕΤΙΚΩΝ ΕΠΙΣΤΗΜΩΝ ΤΜΗΜΑ ΠΛΗΡΟΦΟΡΙΚΗΣ

που θα δώσει αποτέλεσµα 48, λόγω της αριστερής προσεταιριστικότητας των τελεστών / και *, ενώ η επιθυµητή αντικατάσταση θα ήταν η

Transcript:

Εισαγωγή Λύσεις για τις ασκήσεις του lab5 Επειδή φάνηκε να υπάρχουν αρκετά προβλήματα σχετικά με τον τρόπο σκέψης για την επίλυση των προβλημάτων του lab5, θα συνοδεύσουμε τις λύσεις με αρκετές επεξηγήσεις, ειδικά για την άσκηση της Πέμπτης που μπορούσε να γίνει με πολλούς τρόπους. Μελετήστε τις ασκήσεις και απαντήσεις και των δύο τμημάτων, κι αν δεν είχατε καταφέρει να τις ολοκληρώσετε, προσπαθήστε ξανά. Άσκηση Πέμπτης SIZE Σε όλες τις αναφορές στο μέγεθος του πίνακα, δε δίνεται ένα συγκεκριμένο νούμερο, αλλά το πιο γενικό SIZE, διότι θέλουμε το πρόγραμμα να είναι γραμμένο με τέτοιο τρόπο ώστε να λειτουργεί σωστά ανεξαρτήτως του μεγέθους του πίνακα. Επομένως θα χρησιμοποιήσουμε #define για να ορίσουμε το SIZE με τρόπο που θα είναι εύκολο να αλλαχθεί. Επειδή τα αρχεία ελέγχου είναι γραμμένα για πίνακες των 10 ή 15 στοιχείων, επιλέγουμε μια από αυτές τις τιμές για τον ορισμό του SIZE. Αν θέλουμε να ελέγξουμε το πρόγραμμα για διαφορετικό μέγεθος πίνακα, θα αλλάξουμε απλά την τιμή του SIZE και θα ξανακάνουμε compile. #define SIZE 10 int main (int argc, char *argv[]) { int source[size], destination[size/2]; Παρατηρήσεις: Δεν ξεχνάμε ότι κατά σύμβαση, σταθερές και ονόματα ορισμένα με #define γράφονται με όλα τα γράμματα κεφαλαία. Η άσκηση δε φαίνεται να λύνει κάποιο πρόβλημα του πραγματικού κόσμου και ίσως αυτό μας κάνει να δυσκολευτούμε να βρούμε περιγραφικά ονόματα για τις μεταβλητές. Αλλά, η ίδια η εκφώνηση "προτείνει" source και destination. Είσοδος δεδομένων Ζητείται να διαβαστούν SIZE ακέραιοι, επομένως χρειαζόμαστε δομή επανάληψης. Εφόσον γνωρίζουμε τον πλήθος των επαναλήψεων, η πιο κατάλληλη δομή είναι for. Παρατηρήσεις Προσοχή να μη βγούμε από τα όρια του πίνακα. Το πρώτο στοιχείο του πίνακα βρίσκεται στη θέση 0 και το τελευταίο στη θέση SIZE-1 Μετατόπιση στοιχείων Το τέταρτο βήμα ζητά να αφαιρεθεί κάθε δεύτερο στοιχείο από τον πρώτο πίνακα, μετατοπίζοντας τα επόμενα στοιχεία αριστερά ώστε να "γεμίσουν" οι κενές θέσεις που δημιουργούνται, και να προστεθεί κάθε ένα από τα αφαιρεμένα στοιχεία στον πίνακα 2. Κάθε φορά που έχουμε ένα σύνθετο πρόβλημα, το σπάμε σε υποπροβλήματα:

> Εντοπισμός κάθε δεύτερου στοιχείου Δεδομένου ότι ξεκινάμε από τη θέση 1, τα στοιχεία που θέλουμε να αφαιρέσουμε είναι σε ζυγές θέσεις, επομένως ένας τρόπος να τα εντοπίσουμε είναι ελέγχοντας τη θέση τους. Εναλλακτικά, μπορούμε απλά να διατρέξουμε τον πίνακα αυξάνοντας κάθε φορά το μετρητή ανά δύο. Δείτε υλοποίηση και των δύο μεθόδων στην επόμενη ενότητα. > Μεταφορά στοιχείων στον πίνακα destination Ο πίνακας έχει μέγεθος SIZE/2 και θα μεταφέρουμε ακριβώς τόσα στοιχεία σε αυτόν. Πρέπει να προσέξουμε το μετρητή που θα χρησιμοποιήσουμε. Μπορούμε είτε να χρησιμοποιήσουμε ένα νέο μετρητή, ή να εκφράσουμε τις θέσεις σε σχέση με τον μετρητή που διατρέχει τον πίνακα source. Παραλλαγή 1: /* έλεγχος άρτιας/περιττής θέσης και χρήση νέου μετρητή */ for (i=1, j=0; i<size; i++) { if ( i%2 == 1) { destination[j] = source[i]; j++; Προσοχή Θέλουμε να αντιγράψουμε στο destination το 2ο, 4ο, 6ο κτλ. στοιχείο αλλά δεν πρέπει να ξεχνάμε πως η αρίθμηση θέσεων σε ένα πίνακα ξεκινά από το 0, επομένως μας ενδιαφέρουν οι μονές θέσεις 1, 3, 5, κτλ. Το i θα μπορούσε να ξεκινά κι από 0. Τότε απλά θα γινόταν μια επιπλέον επανάληψη, αλλά το τελικό αποτέλεσμα δε θα άλλαζε. Το j πρέπει να αυξάνεται μόνο όταν προστίθεται νέο στοιχείο στον πίνακα destination κι όχι μαζί με το i. Τα i και j σε αυτή την περίπτωση θα μπορούσαν να έχουν πιο περιγραφικά ονόματα: from και to αντίστοιχα. Παραλλαγή 2: /* Προσαύξηση i ανά δύο και υπολογισμός θέσεις στο destination με βάση τον υπάρχοντα μετρητή */ for (i=1; i<size; i+=2) { destination[i/2] = source[i]; > Γέμισμα κενών Για να γεμίσουν οι θέσεις που περιέχουν τα στοιχεία που αντιγράψαμε πρέπει να μετατοπίσουμε όλα τα επόμενα στοιχεία προς τα αριστερά:

σχήμα 1 * Μέθοδος 1 (πολύ εύκολη) Ο πιο απλός τρόπος είναι να κάνουμε τη μετατόπιση αφού έχουν αντιγραφεί όλα τα στοιχεία στον πίνακα destination, χρησιμοποιώντας ένα loop με δύο μετρητές: o ένας, ας τον πούμε from, θα διατρέχει τις θέσεις από τις οποίες θέλουμε να πάρουμε στοιχεία. Ο άλλος, ας τον πούμε to, θα διατρέχει τις θέσεις στις οποίες θέλουμε να βάλουμε στοιχεία: /* Αντιγραφή στο destination */ for (i=1; i<size; i++) { destination[i/2] = source[i]; /* Μετατόπιση στοιχείων αριστερά, αφότου ολοκληρωθεί η αντιγραφή στο destination */ for (from = 2, to = 1; from < SIZE; from+=2, to++) { source[to]=source[from]; *Μέθοδος 2 (λίγο πιο δύσκολη) Εναλλακτικά, μπορούμε να κάνουμε τη μετατόπιση αφότου έχουμε αντιγράψει όλα τα στοιχεία που θέλουμε στον πίνακα destination υπολογίζοντας την απόσταση που πρέπει να μετατοπιστεί κάθε στοιχείο. Δείτε το σχήμα 1. Τα βελάκια δείχνουν πού θέλουμε να μετατοπιστεί κάθε ένα στοιχείο. Παρατηρούμε πως η απόσταση μετατόπισης αυξάνεται κάθε φορά κατά ένα. Εδώ πρέπει να προσέξουμε ιδιαιτέρως τα όρια του πίνακα. Εφόσον προσπελαύνουμε το source[i+distance] θα πρέπει το i+distance να μη γίνει ποτέ μεγαλύτερο του SIZE-1. /* Αντιγραφή στο destination */ for (i=1; i<size; i++) { destination[i/2] = source[i]; /* Μετατόπιση στοιχείων αριστερά, αφότου ολοκληρωθεί η αντιγραφή στο destination */ for (i=1, distance=1; i+distance < SIZE; i++, distance++) { source[i]=source[i+distance]; *Μέθοδος 3 (αρκετά δύσκολη) Ένας άλλος, κλασικός τρόπος είναι κάθε φορά που αντιγράφεται ένα στοιχείο στον πίνακα destination και "ανοίγει" κενή θέση στον πίνακα source, να μετατοπίζουμε όλα τα υπόλοιπα στοιχεία μια θέση αριστερά. Τι ξέρουμε:

Το στοιχείο που βρίσκεται στη θέση i του πίνακα source αντιγράφηκε στο destination Η θέση i θεωρείται "άδεια" (προσοχή: ακόμη βρίσκεται εκεί ο αριθμός, αλλά δε θεωρείται έγκυρος) Τι θέλουμε: Θέλουμε κάθε στοιχείο από τη θέση i+1 και πέρα να πάει μια θέση αριστερά. Τι πρέπει να προσέξουμε: Να μη βγούμε εκτός ορίων πίνακα Πώς πρέπει να ανανεώνεται το i. Αυτό είναι ιδιαιτέρως σημαντικό. Δείτε το παρακάτω σχήμα : σχήμα 2 Ας υποθέσουμε ότι μόλις αντιγράψαμε το 6 στον πίνακα destination. Το i μας είναι 1. Αμέσως μετά, θέλουμε να μετατοπίσουμε μια θέση αριστερά όλα τα επόμενα στοιχεία (το 9 στη θέση 1, το 8 στη θέση 2 κ.ο.κ.): σχήμα 3 Παρατηρούμε πως το επόμενο στοιχείο που θα αντιγραφεί στον πίνακα destination, το 8, τώρα πια βρίσκεται στη θέση 2. Επομένως, το i για την επόμενη επανάληψη δεν πρέπει πια να αυξάνεται κατά 2, αλλά κατά 1. /* Μετατόπιση στοιχείων αριστερά, από τη θέση i+1 και πέρα, παράλληλα με την αντιγραφή στο dest. */ for (i=1, j=0; i<=size/2; i++) { destination[j] = source[i]; j++; for (k=i; k<size-1; k++) { source[k] = source[k+1]; Προσοχή: Το i πηγαίνει μόνο μέχρι και SIZE/2 γιατί μετά από κάθε αντιγραφή στο destination, μεταφέρουμε τα υπόλοιπα στοιχεία του source αριστερά, με αποτέλεσμα ο πίνακας source να μικραίνει κάθε φορά. Το εσωτερικό loop πρέπει να χρησιμοποιήσει διαφορετικό μετρητή από το i. Το εσωτερικό loop πηγαίνει μέχρι και SIZE-2. Αυτό οφείλεται στο ότι προσπελαύνουμε το

source[k+1]. Για να μείνουμε εντός ορίων πίνακα θα πρέπει το k+1 να πάρει το πολύ την τιμή SIZE-1. Γέμισμα με μηδενικά Αφού μετατοπιστούν τα στοιχεία, πρέπει να γεμίσουμε τις δεξιές θέσεις με μηδενικά. Αν χρησιμοποιήσουμε τη μέθοδο 3, αυτό είναι εύκολο. Αρκεί κάθε φορά να βάζουμε μηδέν στην τελευταία θέση του πίνακα, και με κάθε μετατόπιση (δηλαδή με κάθε εκτέλεση του εσωτερικού loop) θα μεταφέρεται κι αυτό αριστερά: /* Μετατόπιση στοιχείων αριστερά, από τη θέση i+1 και πέρα, παράλληλα με την αντιγραφή στο destination και γέμισμα των δεξιών θέσεων με μηδενικά */ for (i=1, j=0; i<=size/2; i++) { destination[j] = source[i]; j++; for (k=i; k<size-1; k++) { source[k] = source[k+1]; source[size-1] = 0; Αν χρησιμοποιήσουμε τη μέθοδο 1 ή 2, μπορούμε να εκμεταλλευτούμε τη γνώση ότι ο πίνακας έχει έγκυρα στοιχεία μέχρι και τη μέση ή μέχρι το distance του loop μετατόπισης. Αν χρησιμοποιήσουμε τη μέση, πρέπει να λάβουμε υπόψη ότι ο πίνακας μπορεί να έχει άρτιο ή περιττό μέγεθος και να γράψουμε τον κώδικά μας ώστε να δουλεύει σωστά και για τις δύο περιπτώσεις. Ένας γρήγορος τρόπος είναι υπολογίζοντας το άνω ακέραιο μέρος της πράξης SIZE/2.0. Η C παρέχει μια συνάρτηση γι' αυτό, με όνομα ceil. /* Μετατόπιση στοιχείων αριστερά, αφότου ολοκληρωθεί η αντιγραφή στο destination */ for (i=1, distance=1; i+distance < SIZE; i++, distance++) { source[i]=source[i+distance]; /* Γέμισμα πίνακα με μηδενικά */ for (i = ceil(size/2.0); i < SIZE; i++) { source[i]=0; Είναι σαφώς πιο απλό να εκμεταλλευτούμε την τιμή της μεταβλητής distance: /* Μετατόπιση στοιχείων αριστερά, αφότου ολοκληρωθεί η αντιγραφή στο destination */ for (i=1, distance=1; i+distance < SIZE; i++, distance++) { source[i]=source[i+distance]; /* Γέμισμα πίνακα με μηδενικά */ for (i = distance; i < SIZE; i++) { source[i]=0;

Έξοδος προγράμματος Τέλος, ζητείται να εκτυπωθούν τα περιεχόμενα του κάθε πίνακα, στην ίδια γραμμή, με ένα κενό ανάμεσα σε διαδοχικά στοιχεία, κι ένα χαρακτήρα αλλαγής γραμμής στο τέλος. for (i=0; i < SIZE; i++) { printf("%d ", source[i]); printf("\n"); Παρατήρηση: Έχουμε βάλει ένα χαρακτήρα κενό μετά το %d Άσκηση Παρασκευής SIZE Σε όλες τις αναφορές στο μέγεθος του πίνακα, δε δίνεται ένα συγκεκριμένο νούμερο, αλλά το πιο γενικό SIZE, διότι θέλουμε το πρόγραμμα να είναι γραμμένο με τέτοιο τρόπο ώστε να λειτουργεί σωστά ανεξαρτήτως του μεγέθους του πίνακα. Επομένως θα χρησιμοποιήσουμε #define για να ορίσουμε το SIZE με τρόπο που θα είναι εύκολο να αλλαχθεί. Επειδή τα αρχεία ελέγχου είναι γραμμένα για πίνακες των 7 ή 8 στοιχείων, επιλέγουμε μια από αυτές τις τιμές για τον ορισμό του SIZE. Αν θέλουμε να ελέγξουμε το πρόγραμμα για διαφορετικό μέγεθος πίνακα, θα αλλάξουμε απλά την τιμή του SIZE και θα ξανακάνουμε compile. #define SIZE 7 int main (int argc, char *argv[]) { char letters[size], to_insert; Παρατηρήσεις: Δεν ξεχνάμε ότι κατά σύμβαση, σταθερές και ονόματα ορισμένα με #define γράφονται με όλα τα γράμματα κεφαλαία. Η άσκηση δε φαίνεται να λύνει κάποιο πρόβλημα του πραγματικού κόσμου και ίσως αυτό μας κάνει να δυσκολευτούμε να βρούμε περιγραφικά ονόματα για τις μεταβλητές. Αλλά, εφόσον ο πίνακας περιέχει γράμματα, ένα καλό όνομα για αυτόν είναι letters ή characters (όχι chars γιατί είναι πολύ κοντά στη λέξη-κλειδί char και υπάρχει κίνδυνος τυπογραφικού λάθους). Το όνομα του χαρακτήρα προς τοποθέτηση είναι το αρκετά περιγραφικό to_insert. Εντοπισμός κεντρικής θέσης πίνακα Πρέπει να προσέξουμε δύο πράγματα κατά τον εντοπισμός της κεντρικής θέσης: Αν ο πίνακας έχει άρτιο μέγεθος, τότε έχει δύο κεντρικές θέσεις Η πρώτη θέση του πίνακα είναι 0 κι όχι 1 Στην περίπτωση που ο πίνακας έχει περιττό μέγεθος, η κεντρική θέση είναι SIZE/2. Στην περίπτωση που ο πίνακας έχει άρτιο μέγεθος, οι κεντρικές θέσεις είναι SIZE/2-1 και SIZE/2

Είσοδος δεδομένων Ζητείται να διαβαστούν SIZE χαρακτήρες, επομένως θα χρειαστούμε δομή επανάληψης. Εφόσον γνωρίζουμε τον πλήθος των επαναλήψεων, η πιο κατάλληλη δομή είναι for. Όταν διαβάζουμε χαρακτήρες πρέπει να είμαστε ιδιαίτερα προσεκτικοί γιατί ακόμη το enter ή κενό που θα πατήσουμε μετά την εισαγωγή ενός χαρακτήρα είναι κι αυτά χαρακτήρες, οπότε στην επόμενη επανάληψη θα διαβαστεί το enter (ή το κενό) 1. Στην περίπτωση της scanf το πρόβλημα λύνεται βάζοντας ένα κενό ανάμεσα στο " και στο %c. Στην περίπτωση της getchar το πρόβλημα λύνεται αν βάλουμε μια ακόμη getchar ώστε να διαβάσει και να "καταναλώσει" το enter ή κενό που πατήσαμε μετά το χαρακτήρα. Τοποθέτηση χαρακτήρων δεξιά / αριστερά Αν εξαιρέσουμε την τοποθέτηση του πρώτου χαρακτήρα, ο οποίος μπορεί να πάει σε μία ή δύο θέσεις ανάλογα με το αν το μέγεθος του πίνακα είναι περιττό ή άρτιο, η διαδικασία είναι ίδια και για τις δύο περιπτώσεις. Αρκεί να ξέρουμε σε ποια θέση αριστερά και ποια θέση δεξιά προσθέσαμε ένα χαρακτήρα στην προηγούμενη επανάληψη. Επομένως, η πιο πρακτική λύση είναι να χρησιμοποιήσουμε δύο μεταβλητές, μία για την αριστερή θέση και μία για τη δεξιά θέση. Απλά, στην περίπτωση περιττού μήκους, έχουν και οι δύο την ίδια τιμή. Από εκεί και πέρα, αρκεί να βάζουμε κάθε φορά τον χαρακτήρα που διαβάστηκε σε κάθε μία από αυτές τις δύο θέσεις. Εδώ είναι κατάλληλη η χρήση while : θέλουμε να τοποθετούμε χαρακτήρες μέχρι να φτάσουμε στα άκρα του πίνακα. Εφόσον η τοποθέτηση γίνεται συμμετρικά, αρκεί να κάνουμε έλεγχο για το ένα άκρο. if (SIZE%2) { /* περιττό μέγεθος πίνακα */ leftpos = rightpos = SIZE/2; else { /* άρτιο μέγεθος πίνακα */ leftpos = SIZE/2-1; rightpos = leftpos + 1; while (leftpos >= 0) { scanf(" %c", &to_insert); letters[leftpos] = letters[rightpos] = to_insert; leftpos--; rightpos++; Εκτύπωση πίνακα σε κάθε στάδιο Η εκφώνηση ζητά να εκτυπώνεται ο πίνακας μετά από κάθε εισαγωγή νέου χαρακτήρα, και να εμφανίζεται μια παύλα σε όσες θέσεις είναι ακόμη "άδειες". Αρχικά, είναι όλος ο πίνακας άδειος, επομένως είναι λογικό, πριν κάνουμε οτιδήποτε στο πρόγραμμα να αρχικοποιήσουμε το πίνακα letters με ένα for loop ώστε να περιέχει μια παύλα σε κάθε θέση. Μετά, όπως θα διαβάζονται οι χαρακτήρες θα αντικαθιστούν μία-μία τις παύλες. 1 Η είσοδος από το πληκτρολόγιο γίνεται με τρόπο παρεμφερή με αυτόν της εξόδου στην οθόνη, όπως εξηγήθηκε στο εργαστήριο. Ότι γράφουμε μπαίνει σε ένα προσωρινό πινακάκι, και κάθε φορά που εκτελείται scanf ή getchar διαβάζει το επόμενο πράγμα που βρίσκει στο πινακάκι. Έτσι το enter που πιθανώς είχαμε πατήσει μετά από την εισαγωγή ενός χαρακτήρα, εξακολουθεί να "ζει" και να περιμένει να διαβαστεί από κάποια επόμενη scanf ή getchar. Αυτό είναι πρόβλημα όταν διαβάζουμε χαρακτήρες. Αν η scanf ζητήσει ένα ακέραιο, τότε ακόμη κι αν υπάρχει ήδη κάποιο enter στο "πινακάκι", θα αγνοηθεί.

Τα περιεχόμενα του πίνακα θέλουμε να τυπώνονται κάθε φορά στην ίδια γραμμή, με ένα κενό ανάμεσα σε διαδοχικά στοιχεία, κι ένα χαρακτήρα αλλαγής γραμμής στο τέλος. for (i=0; i < SIZE; i++) { printf("%c ", letters[i]); printf("\n"); Παρατήρηση: Έχουμε βάλει ένα χαρακτήρα κενό μετά το %d Προσοχή: Το loop που εκτυπώνει τον πίνακα πρέπει να βρίσκεται μέσα στο while!