Πίνακες-Αλφαριθμητικά 5η Διάλεξη
Τύπος Πίνακα Μεταβλητές με δείκτη Αλφαριθμητικά-Πίνακες Δισδιάστατος-Πολυδιάστατος Πίνακας
Πίνακες Mια συλλογή μεμονωμένων τιμών δεδομένων οι πίνακες είναι διατεταγμένοι τα στοιχεία ενός πίνακα είναι τοποθετημένα με συγκεκριμένη σειρά οι πίνακες είναι ομοιογενείς όλα τα στοιχεία ενός πίνακα έχουν τιμές του ίδιου τύπου
Τύπος Πίνακα Σύνθετος τύπος δεδομένων Αναπαριστά ένα σύνολο ομοειδών τιμών Π.χ. βαθμοί ενός μαθητή, θερμοκρασίες ενός μήνα. Χαρακτηριστικά: μέγεθος πίνακα, τύπος στοιχείων
Δήλωση Πινάκων τύπος όνομα_πίνακα[μέγεθος] pinakas 1 2 3 4 5 6 7 8 9 int pinakas[10]; πίνακας ακεραίων με 10 θέσεις το μέγεθος του πίνακα είναι μια σταθερά που μπορεί να οριστεί και με την #define το μέγεθος του πίνακα δεν μπορεί να είναι η τιμή μιας μεταβλητής pinakas 1 2 3 4 5 6 7 8 9
Δήλωση-Αρχικοποίηση Δήλωση <τύπος> <όνομα-πίνακα> [<μέγεθος>]; Π.χ. float bathmos[5]; Αρχικοποίηση float bathmos[5]= {10, 8, 12.5, 15.5, 14}; float bathmos[] = {10, 8, 12.5, 15.5, 14}; (προσοχή στο πλήθος των αρχικών τιμών)
Προσπέλαση-Αναφορά Τα στοιχεία ενός πίνακα αποθηκεύονται σε γειτονικές (διαδοχικές) θέσεις μνήμης. Ο πίνακας είναι μια δομή τυχαίας προσπέλασης. 1 2 3 4 Δείκτες θέσεων bathmos 10 8 12.5 15.5 14 bathmos[0] bathmos[1] … bathmos[4] Μεταβλητές με δείκτες Δείκτης θέσης
Μεταβλητές με δείκτη-Ανάθεση Οι μεταβλητές με δείκτη χρησιμοποιούνται όπως οι κοινές μεταβλητές. Π.χ. x = bathmos[3]*2; y= (bathmos[i]+10)/5; Οι μεταβλητές με δείκτη χρησιμοποιούνται για ανάθεση τιμών στα στοιχεία του πίνακα. Π.χ. bathmos[3] = 14; bathmos[j] = bathmos[j+1] + 10;
Παράδειγμα Θεωρούμε μονοδιάστατο πίνακα 20 ακεραίων στοιχείων (int num[20]). Να γραφεί κώδικας C που να αυξάνει τα αρνητικά στοιχεία κατά 1 και να μειώνει τα θετικά κατά 2. for (i=0; i<20; i++) if (num[i] < 0) num[i]++; else num[i] -= 2;
Ανάθεση τιμών σε πίνακα όνομα_πίνακα[αριθμοδείκτης] pinakas[0] = 5; η τιμή του αριθμοδείκτη μπορεί να προέρχεται από μια μεταβλητή for (i = 0; i < 10; i++) pinakas[i] = 0;
Δήλωση πινάκων και ανάθεση τιμών τύπος_δεδομένων όνομα_πίνακα[] = {τιμή1, τιμή2, ...,} int numbers[] = {1, 2, 3, 4, 5}; Δηλώνει έναν πίνακα με όνομα numbers και μέγεθος 5, όσα είναι και τα στοιχεία μέσα στα άγκιστρα.
Πολυδιάστατοι Πίνακες τύπος όνομα_πίνακα[μέγεθος1] [μέγεθος2]... [μέγεθοςΝ] μπορούν να έχουν Ν διαστάσεις συνήθως 2 ή 3 διαστάσεων int pinakas[3][3] Pinakas[0][0] Pinakas[0][1] Pinakas[0][2] 1 Pinakas[1][0] Pinakas[1][1] Pinakas[1][2] 2 Pinakas[2][0] Pinakas[2][1] Pinakas[2][2]
Δήλωση πινάκων και ανάθεση τιμών int numbers[][] = { {1, 2, 3}, {4, 5, 6}, {7,8,9} }; Δηλώνει έναν πίνακα με όνομα numbers με δύο διαστάσεις και μέγεθος 3x3, όσα είναι και τα στοιχεία μέσα στα άγκιστρα.
Υπολογισμός Μέσης Τιμής #include <stdio.h> #define SIZE 10 int main() { int numbers[SIZE]; int sum = 0; double mean; for (int i=0; i < SIZE; i++) printf("Dwse arithmo %d:", i); scanf("%d", &numbers[i]); } sum += numbers[i]; mean = (double)sum / SIZE; printf("H mesi timi einai %g.", mean);
Υπολογισμός Τυπικής Απόκλισης #include <stdio.h> #include <math.h> #define SIZE 10 int main() { int numbers[SIZE]; int sum = 0; double mean, sum2, sigma; for (int i=0; i < SIZE; i++) printf("Dwse arithmo %d:", i); scanf("%d", &numbers[i]); } sum += numbers[i]; mean = (double)sum / SIZE; sum2 = 0.0; sum2 += (numbers[i] - mean)*(numbers[i] - mean); sigma = sqrt(sum2 / SIZE); printf("H apoklisi einai %g.", sigma);
Πρόσθεση Πινάκων #include <stdio.h> #define N 5 main() { float A[N][N],B[N][N],C[N][N]; int i,j; for (i=0;i<N;i++) for (j=0;j<N;j++) printf("A[%d,%d]:",i,j); scanf(“%g”, &A[i][j]); } printf("B[%d,%d]:",i,j); scanf(“%g”, &B[i][j]); C[i][j]=A[i][j]+B[i][j]; printf("C[%d,%d]:%7.2f ",i,j,C[i][j]); printf("\n");
Πολλαπλασιασμός Πινάκων (1/2) // pollaplasiasmoPinakon.c #include <stdio.h> #define N 5 main() { float A[N][N],B[N][N],C[N][N]; int i,j,k; float thisElement; for (i=0;i<N;i++) for (j=0;j<N;j++) printf("A[%d,%d]:",i,j); scanf(“%g”, &A[i][j]); } printf("B[%d,%d]:",i,j); scanf(“%g”, &B[i][j]);
Πολλαπλασιασμός Πινάκων (2/2) for (i=0; i<N; i++) for (j=0; j<N; j++) { thisElement=0; for (k=0;k<N;k++) thisElement=thisElement+A[i][k]*B[k][j]; C[i][j]=thisElement; } for (i=0;i<N;i++) for (j=0;j<N;j++) printf("C[%d,%d]:%7.2f ",i,j,C[i][j]); printf("\n");
Εύρεση ελαχίστου σε πίνακα // elaxistoSePinaka.c #include <stdio.h> #define N 10 main() { float A[N]; int i; float elaxisto; int thesiElaxistou; for (i=0;i<N;i++) printf("A[%d]:",i); scanf(“%g”, &A[i]); } elaxisto = A[0]; thesiElaxistou = 0; for (i=1;i<N;i++) if (elaxisto>A[i]) elaxisto=A[i]; thesiElaxistou=i; printf("To elaxisto stoixeio einai to %5.2f kai brisketai sti thesi %d\n", elaxisto, thesiElaxistou);
Αναστροφή πίνακα // anastrofiPinaka.c #include <stdio.h> #define N 5 main() { float A[N][N],C[N][N]; int i,j; for (i=0;i<N;i++) for (j=0;j<N;j++) printf("A[%d,%d]:",i,j); scanf(“%g”, &A[i][j]); } C[i][j]=A[j][i]; printf("C[%d,%d]:%7.2f ",i,j,C[i][j]); printf("\n");
Δισδιάστατος Πίνακας (1) Αναπαράσταση 10 φοιτητών και 4 μαθημάτων: Χρήση δισδιάστατου πίνακα int bathmos[10][4] (πίνακας 10 στοιχείων, κάθε στοιχείο πίνακας 4 ακεραίων ή πίνακας 10 γραμμών και 4 στηλών) Bathmos[0][1] βαθμός 2ου μαθήματος, πρώτου φοιτητή Αποθήκευση στη μνήμη κατά γραμμές (σαν μονοδιάστατος)
Δισδιάστατος Πίνακας (2) Μαθήματα(στήλες) Αρχικοποίηση int bathmos[4][3] = {{14, 15, 18} {12, 14, 16} {18, 15, 17} {13, 19, 18}} Φοιτητές (γραμμές) 1 2 14 15 18 12 14 16 1 18 15 17 2 13 19 18 3
Παράδειγμα #include <stdio.h> main() { int i, j, k, a[4][4]; for (i=0; i<=3; i++) for (j=0; j<=3; j++) a[i][j]=i+j; for (j=0; j<=3; j++){ printf("%d ", a[i][j]); k++; if (k == 4){ printf("\n"); }
Αλφαριθμητικά-Πίνακες Αλφαριθμητικό = ακολουθία αλφαβητικών και αριθμητικών χαρακτήρων (π.χ. Αριθμός σειράς μηχανήματος, ISBN βιβλίου κλπ) C πίνακας χαρακτήρων με τελευταίο στοιχείο τον μηδενικό χαρακτήρα (‘\0’)
Αλφαριθμητικά-συμβολοσειρές (strings) Δεν υπάρχει τύπος δεδομένων στην C για την αποθήκευση αλφαριθμητικών πίνακες από χαρακτήρες char str[50]; πίνακας για αποθήκευση 50 χαρακτήρων \0 χαρακτήρας null δηλώνει το τέλος μιας συμβολοσειράς %s – κωδικός μορφοποίησης printf
Διαχείριση Αλφαριθμητικών Μια συμβολοσειρά-αλφαριθμητικό (string) είναι ένας πίνακας χαρακτήρων στον οποίο τοποθετείται τελευταίος ο χαρακτήρας ‘\0’, ως ένδειξη του τέλους της Συμβολοσειράς Μπορούμε να διαχειριστούμε ένα string με δύο τρόπους – ως έναν πίνακα, το οποίο συνεπάγεται σχετική δυσκολία char line[8]; line[0] = ‘H’; line[1] = ‘e’; line[2] = ‘l’; line[3] = ‘l’; line[4] = ‘o’; line[5] = ‘\0’; – Μέσω της χρήσης ειδικών συναρτήσεων που παρέχει η C μέσω του αρχείου <string.h> strcpy(line, "Hello");
Αλφαριθμητικά (1) Δήλωση αλφαριθμητικών μεταβλητών char <όνομα-μετ> [<μέγεθος>]; (ωφέλιμο μέγεθος: <μεγεθος>-1) Π.χ. char message[25]; char str[8]; Αλφαριθμητική σταθερά (αποθηκεύεται σαν πίνακας) Π.χ. “Hello” Διαφορά μεταξύ ‘H’ και “H” Αρχικοποίηση: char str[] = {‘A’, ‘-’, ‘4’, ‘5’, ‘-’, ‘2’, ‘5’} ή char str[] = “A-45-25” ‘H’ ‘e’ ‘l’ ‘o’ ‘\0’
Αλφαριθμητικά (2) Εκτύπωση printf (“Hello”); printf (“Ο αριθμός είναι: %s\n”, str); Εισαγωγή scanf (“%s”, str); ή scanf (“%s”, &str[0]); *διαβάζει μέχρι το πρώτο κενό *προσοχή στην υπέρβαση του μεγέθους δεν χρειάζεται &
Παράδειγμα #include <stdio.h> #define MAX_CHARS 80 main () { char str[MAX_CHARS]; int i; printf(“Δώσε αλφαριθμητικό:”); scanf(“%s”, str); for (i = 0; i < 10; i++) printf(“%s\n”, str); } for (i = 0; i < 10; i++) printf(“%s”, str[i]);
Αρχικοποίηση Συμβολοσειράς Παρατηρούμε ότι δεν είναι απαραίτητο να βάλουμε το χαρακτήρα '\0', γιατί αυτό το κάνει ο compiler. 'Οπως και στα άλλα arrays έτσι και στα strings μπορούμε σε μία αρχικοποιημένη δήλωση να παραλείψουμε το πλήθος στοιχείων του array και ο compiler θα το συμπεράνει από την έκφραση που χρησιμοποιείται για να γίνει η αρχικοποίηση. Δεδομένου ότι τα strings είναι arrays δεν μπορούμε να χρησιμοποιήσουμε σ' αυτά τελεστές για να ελέγξουμε την ισότητα, να εκχωρήσουμε την τιμή ενός string σε κάποιο άλλο, κ.ο.κ. Για να κάνουμε αυτές τις λειτουργίες θα πρέπει να χρησιμοποιήσουμε συναρτήσεις που παρέχονται στη βασική βιβλιοθήκη της γλώσσας C.
Συχνές συναρτήσεις strcpy(char str1[], char str2[]), η οποία αντιγράφει το string str2 στο string str1. Μετά την κλήση της συνάρτησης δηλαδή το str1 θα έχει τους ίδιους χαρακτήρες με το str2. strncpy(char str1[], char str2[], int n), με την οποία αντιγράφουμε το πολύ n χαρακτήρες από το str2 στο str1. Η συνάρτηση αυτή χρησιμοποιείται όταν δεν είμαστε βέβαιοι ότι το str1 έχει αρκετό χώρο διαθέσιμο για να αποθηκεύσει όλους τους χαρακτήρες που περιέχονται στο str2. 'Ετσι τη συνάρτηση strncpy θα τη χρησιμοποιούσαμε σε κάποια περίπτωση όπως η πιο κάτω: char str1[20], str2[50]; ... strncpy(str1, str2, 19); Για να είναι ασφαλής έτσι μία κλήση στη strncpy θα πρέπει να ακολουθείται από την εντολή str1[n] = '\0'
Συχνές συναρτήσεις (2) strcat(char str1[], char str2[]) με την οποία προσθέτουμε στο τέλος του string str1 το string str2. 'Ετσι, αν το str1 έχει την τιμή "Hello " και το str2 την τιμή "there!" τότε μετά την κλήση της strcat το str1 θα έχει την τιμή "Hello there!". Το str1 θα πρέπει να έχει αρκετό χώρο για να αποθηκεύσει τους έξτρα χαρακτήρες strncat(char str1[], char str2[], int n) με την οποία προσθέτουμε το πολύ n χαρακτήρες του str2 στο τέλος του str1, το οποίο πρέπει να έχει αρκετό χώρο για να αποθηκεύσει τους έξτρα χαρακτήρες. Στο νέο τέλος του str1 προστίθεται ο χαρακτήρας '\0'. size_t strlen(char s[]) η οποία επιστρέφει το πλήθος των χαρακτήρων που περιέχει το string s (ο χαρακτήρας '\0' δεν υπολογίζεται). Ο τύπος size_t ορίζεται από τον C compiler με βάση ήδη υπάρχοντες τύπους. συνήθως ορίζεται ως int ή unsigned int και είναι απόλυτα ασφαλές να εκχωρήσουμε το αποτέλεσμα της strlen (ή οποιασδήποτε άλλης συνάρτησης ή τελεστή επιστρέφει τύπο size_t) σε μία μεταβλητή τύπου int ή unsigned int
Συχνές συναρτήσεις (3) int strcmp(char str1[], char str2[]) που επιστρέφει έναν ακέραιο μικρότερο από το μηδέν αν το str1 είναι μικρότερο από το str2, 0 αν τα strings είναι ίσα και έναν ακέραιο μεγαλύτερο από το μηδέν αν το str1 είναι μεγαλύτερο από το str2. Η σύγκριση στα strings γίνεται με λεξικογραφική σειρά, συγκρίνονται δηλαδή χαρακτήρα προς χαρακτήρα μέχρι να βρεθεί κάποιος διαφορετικός ή να φτάσουμε στο τέλος του ενός string. Αν έχει βρεθεί διαφορετικός χαρακτήρας τότε το string στο οποίο ανήκει ο μικρότερος από τους δύο χαρακτήρες είναι το μικρότερο. Αν φτάσουμε στο τέλος του ενός string, τότε αν ταυτόχρονα φτάσαμε στο τέλος του άλλου string, τα strings είναι ίσα. αν όχι, τότε το string στο τέλος του οποίου φτάσαμε είναι το μικρότερο. int strncmp(char str1[], char str2[], int n) η οποία είναι αντίστοιχη της strcmp με τη διαφορά ότι συγκρίνονται το πολύ n χαρακτήρες από τα strings int atoi(char s[]) η οποία μας επιστρέφει την ακέραια τιμή που αναπαριστά το string s. Αν, π.χ. το s έχει τιμή "1201" η atoi(s) θα επιστρέψει τον ακέραιο 1201. Δεν μπορούμε να επιτύχουμε το ίδιο αποτέλεσμα με το συμβολισμό (int)s. Το s μπορεί να περιέχει πρόσημο και κενά πριν και μετά από αυτό θ) long atol(char s[]) η οποία μας επιστρέφει την τύπου long τιμή που αναπαριστά το string s. Ισχύουν οι ίδιες παρατηρήσεις με την atoi. double atof(char s[]) που μας επιστρέφει την τύπου doyble τιμή που περιέχεται στο string s. Το s μπορεί να περιέχει οποιαδήποτε αναπαράσταση μιας double σταθεράς.
Header συμβολοσειρών Για να χρησιμοποιηθούν οι συναρτήσεις atoi, atol και atof θα πρέπει να έχουμε πριν από την πρώτη χρησιμοποίησή τους την οδηγία #include <stdlib.h>, ενώ για τις υπόλοιπες την οδηγία #include <string.h>.
gets/puts char *gets(char *s); αποθηκεύει στο string s. Αντικαθιστά τον τερματικό χαρακτήρα νέας γραμμής με ΄\0΄. Επιστρέφει s, ή NULL αν συναντηθεί το τέλος του αρχείου (EOF) ή αν συμβεί κάποιο λάθος int puts(const char *s); – Η puts γράφει το string s και ένα χαρακτήρα νέας γραμμής (΄\n΄) στην οθόνη. Επιστρέφει EOF αν συμβεί κάποιο λάθος, διαφορετικά επιστρέφει μη αρνητική τιμή.
Παράδειγμα 1a #include <stdio.h> Εκτέλεση: main() { $ ./aout char test1[5], test2[5]; scanf("%s", test1); printf("test1=%s\n", test1); gets(test2); printf("test2=%s\n", test2); } • Ισχύει ότι το test2 είναι ίσο με "end of line" από την προηγούμενη είσοδο Εκτέλεση: $ ./aout 13131 test1=13131 test2= $ ...
Παράδειγμα 1b #include <stdio.h> Εκτέλεση: main() { $ ./aout char test1[5], test2[5]; scanf("%s", test1); printf("test1=%s\n", test1); scanf("%s", test2); printf("test2=%s\n", test2); } Χρησιμοποιείται η scanf αντί για την gets. Η scanf αγνοεί την αλλαγή γραμμής αφού παίρνει το πρώτο μη blank και σταματά το αμέσως επόμενο μη blank Εκτέλεση: $ ./aout 1313 test1=1313 1233 test2=1233 $ ...
Μήκος Συμβολοσειράς #include <stdio.h> #include <stdio.h> main() { char str[50]; int i=0; gets(str); while (str[i] != '\0') i++; printf("Mikos %d", i); } #include <stdio.h> #include <string.h> main() { char str[50]; gets(str); printf("Mikos %d", strlen(str)); }
Mέτρηση Αριθμών, Γραμμάτων (1/2) #include <stdio.h> #include <string.h> main() { char str[256]; int n, en1, en2, i; gets(str); n = en1 = en2 = i = 0; while (str[i] != '\0') if (str[i] >='0' && str[i] <= '9') n++; else if (str[i] >= 'a' && str[i] <= 'z') en1++; else if (str[i] >= 'A' && str[i] <= 'Z') en2++; i++; } printf("Ari8moi %d Mikra %d Kefalaia %d", n, en1, en2);
Mέτρηση Αριθμών, Γραμμάτων (2/2) #include <stdio.h> #include <string.h> #include <ctype.h> main() { char str[256]; int n, en1, en2, el1, el2, i; gets(str); n = en1 = en2 = el1 = el2 = i = 0; while (str[i] != '\0') if (isdigit(str[i])) n++; else if (islower(str[i])) en1++; else if (isupper(str[i])) en2++; i++; } printf("Ari8moi %d Mikra %d Kefalaia %d", n, en1, en2);