Docstoc

Εισαγωγ_ στο Unix - LPIS_3_

Document Sample
Εισαγωγ_ στο Unix - LPIS_3_ Powered By Docstoc
					       Δομές στην C
       (επανάληψη)

       Γλώσσα C & Unix
       Τμήμα Πληροφορικής, ΑΠΘ
       B’ εξάμηνο

lpis.csd.auth.gr/curriculum/C+Unix/UNCL202.html
    Σύνθετοι Τύποι Δεδομένων
¡   structure (δομή): ομαδοποίηση πολλών
    μεταβλητών κάτω από ένα κοινό όνομα
    l   Π.χ. εγγραφή αρχείου
    l   Π.χ. γραμμή σε βάση δεδομένων
¡   union (ένωση): επιτρέπει το ίδιο μέρος της
    μνήμης να οριστεί ως δύο ή παραπάνω
    διαφορετικούς τύπους μεταβλητών
¡   enumeration (απαρίθμηση): λίστα
    συμβόλων
¡   typedef: δημιουργία νέων ονομάτων τύπων
    δεδομένων
                                                 2
    Δομή (structure)
¡   Ομαδοποίηση πολλών μεταβλητών κάτω από
    ένα κοινό όνομα
    l   Κρατιούνται μαζί τα δεδομένα που σχετίζονται μεταξύ
        τους
¡   Η δήλωση μιας δομής ορίζει ένα πρότυπο
    l   Μπορεί να χρησιμοποιηθεί για τη δημιουργία
        μεταβλητών αυτού του προτύπου
¡   Οι μεταβλητές που απαρτίζουν μια δομή
    λέγονται στοιχεία ή μέλη (members) της δομής
    l   Όλα τα στοιχεία μιας δομής πρέπει να σχετίζονται
        λογικά μεταξύ τους
    l   Π.χ. όνομα, επώνυμο και διεύθυνση ενός ατόμου
                                                           3
         Δήλωση Δομής

         ¡   Δομή για την αναπαράσταση των
             στοιχείων ενός μαθητή
                                               ¡ Όνομα   της δομής
          struct mathitis {
                 char onoma[15];
¡ Δηλώσεις       char eponymo[25];
  στοιχείων      short int apousies;
                 short int vathmos;
             }; ¡ Πληροφορεί τον μεταγλωττιστή της C ότι ξεκινά η
                    δήλωση μιας δομής (ή μιας μεταβλητής δομής).
                                                                   4
    Χρήση Δομής

¡   Ακόμα δεν έχει δημιουργηθεί καμία
    μεταβλητή
¡   Το mathitis είναι ένας καινούριος
    τύπος δεδομένων
¡   Μπορεί να χρησιμοποιηθεί για τη
    δήλωση μεταβλητών αυτού του τύπου
           struct mathitis x1;

                                        5
    Ταυτόχρονη Δήλωση και Χρήση
    Δομής

¡   Μπορούμε να δηλώσουμε μεταβλητές
    ταυτόχρονα με τη δήλωση μιας δομής
struct mathitis {
      char onoma[15];
      char eponymo[25];
      unsigned short int apousies;
      unsigned short int vathmos;
  } x1, x2, x3;
                                         6
    Ανώνυμες Δομές
¡   Όταν δηλώνουμε μεταβλητές μαζί με τη
    δομή μπορούμε να μη δώσουμε όνομα
    στη δομή
    l   Όταν δεν πρόκειται να δηλώσουμε
        επιπλέον μεταβλητές αυτού του τύπου
struct {
      char onoma[15];
      char eponymo[25];
      unsigned short int apousies;
      unsigned short int vathmos;
  } x1, x2, x3;
                                              7
    Προσπέλαση Στοιχείων Δομής

¡ Τα στοιχεία μιας μεταβλητής δομής,
  μπορούν να προσπελαστούν με τον
  τελεστή τελεία “.”
¡ Γενική μορφή:

     struct_var_name.member_name
¡ Παράδειγμα:

x1.apousies = 2;
printf("%d", x1.apousies);

                                       8
 Σύνθετες Δομές
struct mathitis {
    char onoma[15];
    ...
    struct date birthday;
} x1;
struct date {    •Πρόσβαση στοιχείων
    int day;     «εσωτερικής» δομής
    int month;    x1.birthday.year;
    int year;
};
                                  9
    Πίνακες από Δομές

¡   Η πιο συνηθισμένη χρήση των δομών,
    είναι σε πίνακες πολλών μεταβλητών
    δομής
¡   Για να δηλωθεί ένας πίνακας από
    δομές, πρέπει να δηλωθούν:
    l   η δομή, και μετά
    l   ένας πίνακας από αυτές τις δομές
¡   Παράδειγμα:
        struct mathitis m[100];
                                           10
Πίνακες από Δομές – Προσπέλαση
Στοιχείων

¡   Για να προσπελαστεί ένα στοιχείο
    μέσα στον πίνακα
    l   πρέπει να χρησιμοποιηθεί ο αύξων
        αριθμός του στοιχείου στον πίνακα
¡   Π.χ. εκτύπωση ονόματος του τρίτου
    μαθητή:
        printf("%s", m[2].onoma);

                                            11
 Δομές και Συναρτήσεις

¡ Πέρασμα μεμονωμένου στοιχείου
  δομής ως παράμετρο σε
  συνάρτηση
¡ Πέρασμα ολόκληρης δομής
 l   Κλήση με τιμή
¡ Πέρασμα   διεύθυνσης μνήμης
 δομής
 l   Κλήση με αναφορά
                                12
    Στοιχεία Δομής ως Παράμετροι
    Συναρτήσεων
¡   Οι μεταβλητές που αποτελούν τα
    στοιχεία μιας δομής μπορούν να δοθούν
    σε μια συνάρτηση
    l   ως τιμές
    l   ως δείκτες προς τη διεύθυνση τους
¡ Παράδειγμα δομής:
struct paradeigma {
      char c;
       int i;
      float f;
      char s[10];
  } x;                                      13
  Παραδείγματα Κλήσης με Τιμή
                struct paradeigma {
                     char c;
                     int i;
                     float f;
                     char s[10];
func_v1(x.c);   } x;
func_v2(x.i);
func_v3(x.f);
func_v4(x.s[2]);
                                 14
     Παραδείγματα Κλήσης με
     Αναφορά
 ¡   ο τελεστής διεύθυνσης & τοποθετείται πριν
     από το όνομα της μεταβλητής δομής
 ¡   όχι πριν από την μεταβλητή του στοιχείου
     της δομής

                          struct paradeigma {
                               char c;
func_r1(&x.c);                 int i;
                               float f;
func_r2(&x.i);                 char s[10];
func_r3(&x.f);            } x;

                                             15
     Παραδείγματα Κλήσης με
     Αναφορά
 ¡   Επειδή το όνομα ενός πίνακα
     χαρακτήρων είναι η διεύθυνση του
     πρώτου στοιχείου του πίνακα,
     παραλείπουμε τελείως τον τελεστή &

                        struct paradeigma {
                             char c;
                             int i;
func_r4(x.s);                float f;
                             char s[10];
                        } x;
                                          16
     Παραδείγματα Κλήσης με
     Αναφορά
 ¡   Όταν θέλουμε να δώσουμε τη διεύθυνση
     κάποιου συγκεκριμένου στοιχείου του
     πίνακα (εκτός του πρώτου) τότε πρέπει
     να χρησιμοποιήσουμε τον τελεστή &

                        struct paradeigma {
                             char c;
                             int i;
func_r5(&x.s[2]);            float f;
                             char s[10];
                        } x;
                                         17
     Παραδείγματα Κλήσης με
     Αναφορά
 ¡   Εναλλακτικά θα μπορούσε να είχε
     χρησιμοποιηθεί αριθμητική δεικτών



                        struct paradeigma {
                             char c;
                             int i;
func_r5((x.s)+2);            float f;
                             char s[10];
                        } x;
                                         18
 Κλήση Συνάρτησης με Τιμή μιας
 Ολόκληρης Δομής

¡ Όταν  μια μεταβλητή δομής δίνεται
  ως παράμετρος σε μια συνάρτηση,
  τότε γίνεται μια τυπική κλήση της
  συνάρτησης με τιμή.
¡ Οποιεσδήποτε αλλαγές γίνουν στα
  στοιχεία της μεταβλητής δομής
  μέσα στην συνάρτηση, δεν θα
  είναι μόνιμες.
                                 19
    Κλήση Συνάρτησης με Τιμή μιας
    Ολόκληρης Δομής
¡   Ο τύπος της τυπικής παραμέτρου της
    συνάρτησης πρέπει να είναι ίδιος με τον
    τύπο της μεταβλητής-παραμέτρου
¡   Η δομή πρέπει να δηλωθεί ως
    καθολικός τύπος δεδομένων
¡   Το όνομα της δομής πρέπει να
    χρησιμοποιηθεί για τη δήλωση των
    l   τοπικών μεταβλητών δομής
    l   τυπικών παραμέτρων των συναρτήσεων
                                             20
    Κλήση Συνάρτησης με Τιμή μιας
    Ολόκληρης Δομής - Παράδειγμα
#include <stdio.h>
                         ¡Καθολικός   τύπος
                          δεδομένων
struct test {
    int a, b;
    char ch;    void f1(struct test p) {
};
                    printf("%d", p.a);
                }
void main(void) {
    struct test x1;
     x1.a = 1000;
     f1(x1);
}                                        21
                  Κλήση Συνάρτησης με Αναφορά
                  σε μία Ολόκληρη Δομή

              ¡   Μπορούμε να περνάμε τη διεύθυνση
                  μνήμης μιας μεταβλητής δομής ως
                  παράμετρο σε συνάρτηση
              ¡   Μπορούμε να κάνουμε μόνιμες αλλαγές
                  στα στοιχεία της μεταβλητής δομής
Πλεονέκτημα




                  μέσα στη συνάρτηση
                  l   Δίνοντας τη διεύθυνση της μεταβλητής
                      δομής στη μνήμη έχουμε κλήση της
                      συνάρτησης με αναφορά
                                                             22
              Κλήση Συνάρτησης με Αναφορά
              σε μία Ολόκληρη Δομή

              ¡Η   εκτέλεση της συνάρτησης
               επιταχύνεται δραστικά
Πλεονέκτημα




               l   Δεν δημιουργείται αντίγραφο της
                   μεταβλητής δομής στη μνήμη για
                   χρήση μόνο μέσα στην συνάρτηση
               l   Έχουμε απευθείας προσπέλαση στη
                   μνήμη
                                                     23
    Δήλωση Δείκτη σε Δομή

¡   Γενική μορφή:
    struct onoma_domis *onoma_deikti
¡   Θα πρέπει να έχει προηγηθεί η δήλωση
    του structure με όνομα onoma_domis
¡   Υπάρχουν κάποια σημεία
    διαφοροποίησης από τους υπόλοιπους
    δείκτες


                                      24
    Χρήση Δείκτη σε Δομή
struct mathitis {
    char onoma[15];
    char eponymo[25];
    unsigned short int apousies;
    unsigned short int vathmos;
};

void main(void){
    struct mathitis x, *p;

      p = &x;
}                                  25
    Τελεστής Βέλος (->)

¡   Δεν μπορεί να χρησιμοποιηθεί ο
    τελεστής τελεία (.) για προσπέλαση
    των στοιχείων της δομής
¡   Πρέπει να χρησιμοποιηθεί ένας
    καινούργιος τελεστής, ο τελεστής
    βέλος (->)
¡   Π.χ. για προσπέλαση του στοιχείου
    apousies μέσω του δείκτη p:
              p->apousies = 2;
                                         26
     Εναλλακτική Προσπέλαση
     Στοιχείου Δομής από Δείκτη

    ¡ Ένας πιο δύσχρηστος τρόπος για
      προσπέλαση ενός στοιχείου μιας
      δομής, μέσω του τελεστή τελεία:
             (*p).apousies = 2;
              p->apousies = 2;
¡   Η χρήση των παρενθέσεων είναι απαραίτητη
    λόγω χαμηλότερης προτεραιότητας του
    τελεστή *
                                               27
    Συναρτήσεις που Επιστρέφουν
    Δομές
struct mathitis make_student(
          char *first, char *last) {

      struct mathitis temp;
      strcpy(temp.onoma,first);
      strcpy(temp.eponymo,last);
      temp.apousies=0;
      temp.vathmos=0;
      return temp;
}                                  28
      Συναρτήσεις που Επιστρέφουν
      Δομές

      void main(void){
          struct mathitis x;
          char first[]=“John”;
          char last[]=“Smith”;

          x = make_student(first,last);
      }
¡   Επιτρέπεται η ανάθεση τιμής σε ολόκληρη τη
    δομή (αντιγραφή)
¡   Δεν επιτρέπεται σύγκριση δομών
                                                 29
    Εφαρμογή – Μέτρηση Συχνότητας
    Εμφάνισης Λέξεων σε Κείμενο
¡   Έχουμε ένα μεγάλο κείμενο και
    ψάχνουμε μέσα σε αυτό να βρούμε
    πόσες φορές εμφανίζονται
    συγκεκριμένες λέξεις-κλειδιά
¡   Χρειαζόμαστε 2 πίνακες
    l   Για την αποθήκευση των λέξεων-κλειδιών
            char *keyword[NKEYS];
    l   Για την αποθήκευση της συχνότητας
        εμφάνισης της κάθε λέξης
             int keycount[NKEYS];
                                             30
    Χρήση Πίνακα Δομών

¡   Υπάρχει 1-1 αντιστοιχία μεταξύ των 2
    πινάκων, το πιο «κομψό» θα ήταν να
    χρησιμοποιηθεί 1 πίνακας δομών
 struct key {
       char *word;
       int count;
};
struct key keytab[NKEYS];
                                           31
    Αρχικοποίηση Πίνακα Δομών

¡   Ο πίνακας θα χρησιμοποιείται σε πολλά
    σημεία του προγράμματος
    l   Ορίζεται ως εξωτερική (global) μεταβλητή
struct key keytab[] = {
   {"account",0},     ¡ Κάθε ζεύγος αντι-
   ...                  στοιχεί στα στοι-
   {"programming",0},   ¡ Ταμιας δομής
                        χεία εσωτερικά
                          άγκιστρα δεν
   {"unix",0}             είναι υποχρε-
};                        ωτικά
                                                   32
    Δομή Προγράμματος

¡   Η συνάρτηση main καλεί συνεχώς τη
    συνάρτηση getword
    l   Διαβάζει από την είσοδο μία λέξη τη φορά
¡   Κάθε λέξη αναζητείται μέσα στον
    πίνακα keytab χρησιμοποιώντας
    «δυαδική αναζήτηση» (binary search)
¡   Η λίστα των λέξεων-κλειδιών πρέπει
    να είναι ταξινομημένη σε αύξουσα
    σειρά
                                               33
      Συνάρτηση main
                            Δυαδική αναζήτηση του string
                       Κάθε κλήση στην getword βρίσκει
      main() {
                                word στον πίνακα keytab
                        μια λέξη και την αντιγράφει στον
        int n;
        char word[MAXWORD];                  πίνακα word

         while (getword(word, MAXWORD) != EOF)
           if (isalpha(word[0]))
              if ((n = binsearch(word,keytab,NKEYS)) >= 0)
                keytab[n].count++;           Αυξάνεται ο αντί-
           for (n = 0; n < NKEYS; n++)        στοιχος counter
              if (keytab[n].count > 0)
Εκτύπωση
αποτελεσμάτων printf("%4d %s\n",
                   keytab[n].count, keytab[n].word);
         getchar(); //Για να προλάβουμε να δούμε τα
      αποτελέσματα
      }                                                  34
        Επικεφαλίδες
      #include <stdio.h>
      #include <ctype.h>
      #include <string.h>        ¡   Μέγεθος ολόκλη-
                                     ρου του πίνακα
      #define MAXWORD 100        ¡   Αριθμός λέξεων-
                                     κλειδιών
#define NKEYS
           (sizeof keytab / sizeof(struct key))

        ¡ Τελεστής compile-time
 ¡   Μέγεθος ενός στοιχείου
        ¡ Επιστρέφει το μέγεθος μιας δομής δεδομένων
     του πίνακα
                                                  35
  Συνάρτηση binsearch
int binsearch(char *word, struct key tab[], int n)
{ int cond, low, high, mid;
                                   • Αρχικά πρόκειται για
  low = 0; high = n - 1;              το μέσο του πίνακα
  while (low <= high) {
     mid = (low+high) / 2;
     if ((cond = strcmp(word,tab[mid].word)) < 0)
       high = mid - 1;
     else if (cond > 0)
       low = mid + 1;
     else                     • • Αν το word είναι
                                 Αν το word είναι
       return mid;                 μικρότερο,
                                 μεγαλύτερο, η επόμενη
                       • Αλλιώς, βρέθηκε η επόμενη
  }                                αναζήτηση γίνει στο
                                 αναζήτηση θαθα γίνει στο
                                 μέσο του μισού το string
                   • Συγκρίνω το string word με πίνακα
                                   μέσο του μισού πίνακα
  return -1;
                                 (προς πίνακα
                     στη θέση mid του τα πάνω)
}                                  (προς
    • Αν το «κάτω» ξεπεράσει το «πάνω», τα κάτω)
      τότε δεν βρέθηκε                                36
    Συνάρτηση getword
int getword(char *word, int lim) {
  int c; char *w = word;                ¡   Αγνοεί τα
                                            αρχικά κενά
    while (isspace(c = getchar())) ;
    if (c != EOF) *w++ = c;
                                ¡ Διαβάζει χαρακτήρες
    if (!isalpha(c)) {
                                   σε έναν buffer και
      *w = '\0';
                                   επιστρέφει τον πρώτο
                      ¡ Διαβάστηκε κάποιος «σωστός»
      return c;
                        χαρακτήρας χαρακτήρα του buffer
    }
    for ( ; --lim > 0; w++)
      if (!isalnum(*w = getchar())) {
         ungetch(*w);
         break;                 ¡ Επιστρέφει έναν
                      ¡ Αν δε διαβάστηκε γράμμα
      }                 σταμάτα χαρακτήρα πίσω
                     ¡ Κύριος βρόχος ανάγνωσης, στο
    *w = '\0';                    buffer
                       μέχρι να συναντηθεί μη-
    return word[0];    αλφαριθμητικός χαρακτήρας
                                                     37
}
Εναλλακτικό πρόγραμμα – Χρήση
Δεικτών σε Δομές - main
main() {
  char word[MAXWORD];
  struct key *p;

    while (getword(word, MAXWORD) != EOF)
      if (isalpha(word[0]))
         if ((p=binsearch(word,keytab,NKEYS)) != NULL)
           p->count++;
    for (p = keytab; p < keytab + NKEYS; p++)
      if (p->count > 0)
         printf("%4d %s\n", p->count, p->word);
}

                                                  38
    Εναλλακτικό πρόγραμμα – Χρήση
    Δεικτών σε Δομές - binsearch
struct key *binsearch(char *word,struct key *tab,int n)
{ int cond;
  struct key *low = &tab[0];       • Αρχικά εκτός ορίων
  struct key *high = &tab[n];         πίνακα
  struct key *mid;                 • Η αριθμητικές πρά-
                                      ξεις δεικτών εξα-
  while (low < high) {                σφαλίζουν σωστό
     mid = low+(high-low)/2;          αποτέλεσμα
     if ((cond = strcmp(word, mid->word)) < 0)
       high = mid;
     else if (cond > 0)         Η προσπέλαση στοι-
                             ¡¡Η συνάρτηση πλέον
       low = mid + 1;           χείων του keytab
                               επιστρέφει pointers
     else
       return mid;
                                γίνεται πλέον με
                               και όχι ακεραίους
  }                             δείκτες
  return NULL;
}                                                    39
    Ένωση (union)

¡  Είναι μια θέση μνήμης που μπορεί να
   χρησιμοποιηθεί από πολλές
   μεταβλητές διαφορετικού τύπου
¡ Δήλωση παρόμοια με τη δήλωση μιας
   δομής
union paradeigma {
        int i;
        char ch;
   };
                                     40
Μεταβλητές union

    μεταβλητή union μπορεί να
¡ Μια

 δηλωθεί
  l   τοποθετώντας το όνομα της μαζί
      με τη δήλωση του union, ή
  l   Μετά, σαν μια ξεχωριστή δήλωση
        union paradeigma x1;

                                       41
Μεταβλητές union και Μνήμη

¡   Ο ακέραιος i και ο χαρακτήρας ch
    μοιράζονται τον ίδιο χώρο μνήμης.
¡   Ο i καταλαμβάνει 2 bytes ενώ ο ch 1




                                          42
Μεταβλητές union και Μνήμη

¡ Ότανδηλώνεται ένα union, ο
 μεταγλωττιστής αυτόματα
 κρατάει χώρο στη μνήμη για
 τον μεγαλύτερο τύπο
 μεταβλητής που υπάρχει μέσα
 στο union.

                               43
    Προσπέλαση στοιχείων union

¡   Παρόμοια με τις δομές
¡   Αν χρησιμοποιούμε απευθείας
    μεταβλητή union, χρησιμοποιούμε τον
    τελεστή τελεία
¡   Αν χρησιμοποιούμε δείκτη προς union,
    τότε χρησιμοποιούμε τον τελεστή βέλος
¡   Π.χ., για ανάθεση της τιμής 10 στην
    ακέραια μεταβλητή i:
                 x1.i = 10;
                                       44

				
DOCUMENT INFO
Shared By:
Categories:
Tags:
Stats:
views:0
posted:7/4/2013
language:Greek
pages:44