Προγραμματισμός Ι Πίνακες, Δείκτες, Αναφορές και Δυναμική Μνήμη Δημήτρης Μιχαήλ Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο Πίνακες Αντικειμένων Όπως στην C μπορούμε να έχουμε πίνακες από δομές, έτσι και στην C++ μπορούμε να έχουμε πίνακες αντικειμένων. 1 2 3 4 5 6 class cl { int param ; public : cl ( int j ) { param = j ; } int getParam ( ) { return param ; } }; 7 8 9 int main ( ) { cl ob [ 3 ] = { cl ( 1 ) , cl ( 2 ) , cl ( 3 ) } ; // initializers 10 for ( int i = 0 ; i < 3 ; i++) cout << ob [ i ] . getParam ( ) << endl ; 11 12 13 } Παραπάνω φαίνεται επίσης πως καλούμε τους constructors κάθε αντικειμένου. Για να μην δώσετε και τους initializers πρέπει η κλάση να παρέχει ένα constructor που να μην δέχεται παραμέτρους. Χαροκόπειο Πανεπιστήμιο 2/50 Δείκτες Αντικειμένων Όπως έχουμε δείκτες σε άλλους τύπους μεταβλητών, μπορούμε να έχουμε και δείκτες σε αντικείμενα. Όπως και στις εγγραφές για να προσπελάσουμε τα μέλη ενός αντικειμένου μέσω ενός δείκτη πρέπει να χρησιμοποιήσουμε τον τελεστή βέλους (->). 1 2 3 4 5 6 class cl { int param ; public : cl ( int j ) { param = j ; } int getParam ( ) { return param ; } }; 7 8 9 int main ( ) { cl ob ( 8 8 ) , * p ; 10 p = &ob ; 11 12 cout << p−>getParam ( ) << endl ; 13 14 } Χαροκόπειο Πανεπιστήμιο 3/50 Ο δείκτης this Όταν μια συνάρτηση μέλος μια κλάσης καλείται σε ένα αντικείμενο, έχει αυτόματη πρόσβαση σε ένα δείκτη this που δείχνει στο αντικείμενο αυτό. 1 2 3 4 5 6 7 8 9 10 class cl { int param ; public : cl ( int j ) { this−>param = j ; } int getParam ( ) { return this−>param ; } }; Στην παραπάνω περίπτωση η χρήση αυτή δεν είναι απαραίτητη και μπορεί να παραληφθεί ο δείκτης this. Υπάρχουν όμως περιπτώσεις όπου ο δείκτης αυτός είναι πολύ χρήσιμος. Χαροκόπειο Πανεπιστήμιο 4/50 Αναφορές Η C++ μας παρέχει την έννοια των αναφορών που χρησιμοποιείται σε 3 περιπτώσεις: 1. ως παράμετρος σε συνάρτηση 2. ως τύπος επιστροφής από συνάρτηση 3. ως ανεξάρτητη αναφορά Χαροκόπειο Πανεπιστήμιο 5/50 Κλήση μέσω Αναφοράς Η πιο σημαντική εφαρμογή των αναφορών είναι μάλλον η δυνατότητα να δημιουργήσουμε συναρτήσεις που χρησιμοποιούν αυτόματα "κλήση μέσω αναφοράς". 11 12 13 void neg ( int &i ) { i = −i ; } 14 15 16 int main ( ) { int x = 1 0 ; 17 cout << x << "␣negated␣is␣" ; 18 19 neg ( x ) ; 20 21 cout << x << endl ; 22 23 } Χαροκόπειο Πανεπιστήμιο 6/50 Κλήση μέσω Αναφοράς Η πιο σημαντική εφαρμογή των αναφορών είναι μάλλον η δυνατότητα να δημιουργήσουμε συναρτήσεις που χρησιμοποιούν αυτόματα "κλήση μέσω αναφοράς". 24 25 26 27 28 void swap ( int &x , int &y ) { int tmp = x ; x = y; y = tmp ; } 29 30 31 int main ( ) { int x = 10 , y = 2 0 ; 32 swap ( x , y ) ; 33 34 cout << "x␣=␣" << x << ",␣y␣=␣" << y << endl ; 35 36 } Χαροκόπειο Πανεπιστήμιο 7/50 Αντικείμενα ως Παράμετροι Εαν καλέσουμε μια συνάρτηση με παράμετρο ένα αντικείμενο, δημιουργείται ένα αντίγραφο του αντικειμένου. Στο τέλος της συνάρτησης το αντίγραφο αυτό καταστρέφεται κανονικά. class cl { int id ; public : cl ( int i ) { id = i ; cout << "Constructing␣id␣=␣" << id << endl ; } ~cl ( ) { cout << "Destructing␣id␣=␣" << id << endl ; } }; void print ( cl o ) { } void print1 ( cl& o ) { } / / no r e f e r e n c e , copy / / r e f e r e n c e , no copy int main ( ) { cl obj ( 2 ) ; print ( obj ) ; print1 ( obj ) ; } Χαροκόπειο Πανεπιστήμιο 8/50 Αντικείμενα ως Παράμετροι Με την χρήση αναφοράς δεν δημιουργείται αντίγραφο. class cl { int id ; public : cl ( int i ) { id = i ; cout << "Constructing␣id␣=␣" << id << endl ; } ~cl ( ) { cout << "Destructing␣id␣=␣" << id << endl ; } }; void print ( cl o ) { } void print1 ( cl& o ) { } / / no r e f e r e n c e , copy / / r e f e r e n c e , no copy int main ( ) { cl obj ( 2 ) ; print ( obj ) ; print1 ( obj ) ; } Χαροκόπειο Πανεπιστήμιο 8/50 Αναφορές ως Τύπος Επιστροφής Συνάρτησης Μια συνάρτηση μπορεί να επιστρέψει αναφορά. Το παράξενο γεγονός είναι πως με αυτόν τον τρόπο μπορεί μια συνάρτηση να χρησιμοποιηθεί στην αριστερή πλευρά μιας ανάθεσης. Πρέπει όμως πάντα να προσέχουμε πως η αναφορά πρέπει να αναφέρεται σε ένα αντικείμενο που δεν βγαίνει εκτός scope με το τέλος της συνάρτησης. Χαροκόπειο Πανεπιστήμιο 9/50 Αναφορές ως Τύπος Επιστροφής Συνάρτησης Μια συνάρτηση μπορεί να επιστρέψει αναφορά. #include < i o s t r e a m > using namespace std ; char s [ 8 0 ] = "Hello␣There" ; char& replace ( int i ) { return s [ i ] ; } / / return a reference int main ( ) { replace ( 5 ) = 'X' ; cout << s << endl ; } Χαροκόπειο Πανεπιστήμιο 10/50 Ανεξάρτητες Αναφορές Μπορούμε να δημιουργήσουμε ανεξάρτητες αναφορές, οι οποίες είναι απλά ψευδώνυμα για άλλες μεταβλητές. int main ( ) { int a ; int &ref = a ; / / independent r e f e r e n c e a = 10; cout << a << "␣" << ref << endl ; ref = 100; cout << a << "␣" << ref << endl ; int b = 1 9 ; ref = b ; / / put b ' s value of i n t o a cout << a << "␣" << ref << endl ; ref−−; ref−−; / / decrement a / / again cout << a << "␣" << ref << endl ; } Χαροκόπειο Πανεπιστήμιο 11/50 Δυναμική Μνήμη στην C++ Η C++ παρέχει δύο τελεστές για δυναμική δέσμευση μνήμης: new και delete. Για λόγους συμβατότητας η C++ υποστηρίζει και τις συναρτήσεις malloc() και free(). Είναι προτιμότερο όμως να χρησιμοποιούμε την μέθοδο της C++ για δέσμευση και ελευθέρωση δυναμικής μνήμης. Χαροκόπειο Πανεπιστήμιο 12/50 Δυναμική Μνήμη Ο τελεστής new δεσμεύει μνήμη και χρησιμοποιείται ως εξής: p_var = new type; Εδώ p_var είναι μια μεταβλητή τύπου δείκτη. Αντίστοιχα η διαγραφή της μνήμης γίνεται με τον τελεστή delete. delete p_var; Χαροκόπειο Πανεπιστήμιο 13/50 Δυναμική Μνήμη Παράδειγμα class complex { double a , b ; public : complex ( ) { this−>a = 0 . 0 ; this−>b = 0 . 0 ; } complex ( double a , double b ) { this−>a = a ; this−>b = b ; } ~complex ( ) ; double re ( ) { return a ; } double im ( ) { return b ; } }; int main ( ) { complex * c = new complex ; / / do something delete c ; } Χαροκόπειο Πανεπιστήμιο 14/50 Πλεονεκτήματα new σε σχέση με malloc 1. η new αυτόματα δεσμεύει τον απαραίτητο χώρο για την αποθήκευση ενός τύπου χωρίς να χρειάζεται να δώσουμε το μέγεθος του τύπου μέσω του τελεστή sizeof. 2. η new επιστρέφει ένα δείκτη στον τύπο που ζητήσαμε και άρα δεν χρειάζεται να γίνει κάποιο cast. 3. οι τελεστές new και delete μπορούν να υπερφορτωθούν ώστε να δημιουργήσουμε δικά μας συστήματα δέσμευσης μνήμης. Χαροκόπειο Πανεπιστήμιο 15/50 Αρχικοποίηση Δυναμικής Μνήμης Μπορούμε να αρχικοποιήσουμε την δεσμευμένη μνήμη με κάποια τιμή. Πρέπει βέβαια να υπάρχει και constructor που να υποστηρίζει αυτήν την τιμή. int main ( ) { complex * c = new complex ( 2 , 5 ) ; / / do something delete c ; } Χαροκόπειο Πανεπιστήμιο 16/50 Αρχικοποίηση Δυναμικής Μνήμης Μπορούμε να αρχικοποιήσουμε την δεσμευμένη μνήμη με κάποια τιμή. int main ( ) { int * d = new int ( 5 ) ; // i n i t i a l i z e to 5 / / do something delete d ; } Χαροκόπειο Πανεπιστήμιο 17/50 Δυναμικοί Πίνακες Για να δεσμεύσουμε μνήμη δυναμικά για πίνακες χρησιμοποιούμε την γενική μορφή: p_var = new array_type [size]; και για να διαγράψουμε την μνήμη του πίνακα: delete [] pvar; Χαροκόπειο Πανεπιστήμιο 18/50 Δυναμικοί Πίνακες #include < i o s t r e a m > using namespace std ; int main ( ) { int * p = new int [ 1 0 ] ; for ( int i = 0 ; i < 1 0 ; i++) p[i] = i; for ( int i = 0 ; i < 1 0 ; i++) cout << p [ i ] << "␣" ; delete [ ] p ; } Όταν δεσμεύουμε δυναμικά πίνακες, υπάρχει ο περιορισμός πως δεν μπορούμε να δώσουμε αρχικές τιμές. Αυτό σημαίνει πως αν θέλουμε ένα δυναμικό πίνακα με αντικείμενα, πρέπει η αντίστοιχη κλάση να περιέχει έναν constructor χωρίς παραμέτρους. Χαροκόπειο Πανεπιστήμιο 19/50 Έλεγχος Επιτυχής Δέσμευσης Εξαιρέσεις Η C++ χρησιμοποιεί ένα καινούριο μηχανισμό για να μας ενημερώσει πως η δέσμευση μνήμης δεν ήταν επιτυχής, τις εξαιρέσεις. θα κάνουμε μια μικρή παρένθεση ώστε να εξηγήσουμε λίγο την έννοια των εξαιρέσεων. Χαροκόπειο Πανεπιστήμιο 20/50 Εξαιρέσεις Exceptions Οι εξαιρέσεις είναι ένας σύγχρονως τρόπος ενημέρωσης για λάθοι. Στην C++ η διαχείριση εξαιρέσεων χρησιμοποιεί 3 δεσμευμένες λέξεις: • try • catch • throw Χαροκόπειο Πανεπιστήμιο 21/50 Εξαιρέσεις Exceptions Στην C++ η διαχείριση εξαιρέσεων χρησιμοποιεί 3 δεσμευμένες λέξεις: • συνήθως οι εντολές που θέλουμε να παρακολουθούμε για εξαιρέσεις εκτελούνται μέσα σε ένα try block. • εάν μια εξαίρεση (ένα λάθος) συμβεί μέσα στο try block, λέμε πως πετάχτηκε μια εξαίρεση (με την χρήση της throw). • η εξαίρεση πιάνετε με την χρήση της catch Χαροκόπειο Πανεπιστήμιο 22/50 Γενική Μορφή try try { // } catch( // } catch( // } ... catch( // } Χαροκόπειο Πανεπιστήμιο try block type1 arg ) { catch block type2 arg ) { catch block typeN arg ) { catch block 23/50 Γενική Μορφή try Όταν μια εξαίρεση πεταχτεί μέσα στο try block, πιάνεται από το αντίστοιχο catch block που εκτελεί κώδικα ώστε να διαχειριστεί την εξαίρεση. Πιο catch block θα εκτελεστεί εξαρτάται από τον τύπο της εξαίρεσης. Ο τύπος μπορεί να είναι οποιοσδήποτε, ακόμη και κλάσης που έχετε φτιάξει εσείς. Εαν ο κώδικας δεν πετάξει καμία εξαίρεση, δεν εκτελείται κανένα catch. Χαροκόπειο Πανεπιστήμιο 24/50 Γενική Μορφή throw throw exception; Εαν μια εξαίρεση πρέπει να πιαστεί, το throw πρέπει να κληθεί μέσα σε ένα try, ή μέσα σε μια συνάρτηση που κλήθηκε μέσε σε ένα try. Εαν δεν υπάρχει αντίστοιχο catch για τον τύπο της εξαίρεσης τότε το πρόγραμμα τερματίζει. Η τυπική βιβλιοθήκη καλεί την συνάρτηση terminate() η οποία με την σειρά της καλεί την συνάρτηση abort(). Υπάρχει βέβαια η δυνατότητα να αλλάξετε αυτή την διαδικασία και να καλέσετε δικιά σας συνάρτηση. Χαροκόπειο Πανεπιστήμιο 25/50 Παράδειγμα #include < i o s t r e a m > using namespace std ; int main ( ) { cout << "Start" << endl ; try { cout << "Inside␣try␣block" << endl ; throw 100; cout << "This␣will␣not␣execute" << endl ; } catch ( int i ) { / / catch exception of type i n t cout << "Caught␣an␣exception␣--␣value␣is␣" << i << endl ; } cout << "End" << endl ; } Χαροκόπειο Πανεπιστήμιο 26/50 Παράδειγμα Το προηγούμενο πρόγραμμα τυπώνει: Start Inside try block Caught an exception -- value is 100 End Χαροκόπειο Πανεπιστήμιο 27/50 Παράδειγμα Εαν πετάξουμε εξαίρεση που δεν υπάρχει αντίστοιχο catch, π.χ μια εξαίρεση τύπου double #include < i o s t r e a m > using namespace std ; int main ( ) { cout << "Start" << endl ; try { cout << "Inside␣try␣block" << endl ; throw 1 0 0 . 0 ; cout << "This␣will␣not␣execute" << endl ; } catch ( int i ) { / / catch exception of type i n t cout << "Caught␣an␣exception␣--␣value␣is␣" << i << endl ; } cout << "End" << endl ; } το πρόγραμμα θα τερματίσει. Χαροκόπειο Πανεπιστήμιο 28/50 Παράδειγμα Το προηγούμενο πρόγραμμα τυπώνει: Start Inside try block terminate called after throwing an instance of 'double' Aborted Χαροκόπειο Πανεπιστήμιο 29/50 Εξαιρέσεις μέσα σε συναρτήσεις #include < i o s t r e a m > using namespace std ; void Xhandler ( int test ) { try { if ( test ) throw test ; } catch ( int i ) { cout << "Caught␣Exception␣#:␣" << i << endl ; } } int main ( ) { cout << "Start" << endl ; Xhandler ( 1 ) ; Xhandler ( 2 ) ; Xhandler ( 0 ) ; Xhandler ( 3 ) ; cout << "End" << endl ; } Χαροκόπειο Πανεπιστήμιο 30/50 Εξαιρέσεις μέσα σε συναρτήσεις Το προηγούμενο πρόγραμμα τυπώνει: Start Caught Exception #: 1 Caught Exception #: 2 Caught Exception #: 3 End Χαροκόπειο Πανεπιστήμιο 31/50 Εξαιρέσεις μέσα σε συναρτήσεις #include < i o s t r e a m > using namespace std ; void Xtest ( int test ) { cout << "Inside␣Xtest,␣test␣is:␣" << test << endl ; if ( test ) throw test ; } int main ( ) { cout << "Start" << endl ; try { cout << "Inside␣try␣block" << endl ; Xtest ( 0 ) ; Xtest ( 1 ) ; Xtest ( 2 ) ; } catch ( int i ) { cout << "Caught␣an␣exception␣--␣value␣is␣" << i << endl ; } cout << "End" << endl ; } Χαροκόπειο Πανεπιστήμιο 32/50 Εξαιρέσεις μέσα σε συναρτήσεις Το προηγούμενο πρόγραμμα τυπώνει: Start Inside Inside Inside Caught End try block Xtest, test is: 0 Xtest, test is: 1 an exception -- value is 1 Χαροκόπειο Πανεπιστήμιο 33/50 Πιάνοντας Κλάσεις Μια εξαίρεση μπορεί να είναι οποιαδήποτε τύπου. Σε πραγματικά προγράμματα οι εξαιρέσεις είναι συνήθως κάποια κλάση. #include < i o s t r e a m > #include < c s t r i n g > using namespace std ; class MyException { char str_what [ 8 0 ] ; int what ; public : MyException ( ) { * str_what = 0 ; what = 0 ; } MyException ( char * s , int e ) { strcpy ( str_what , s ) ; what = e ; } int What ( ) { return what ; } char * StrWhat ( ) { return str_wat ; } } Χαροκόπειο Πανεπιστήμιο 34/50 Πιάνοντας Κλάσεις Μια εξαίρεση μπορεί να είναι οποιαδήποτε τύπου. Σε πραγματικά προγράμματα οι εξαιρέσεις είναι συνήθως κάποια κλάση. int main ( ) { int i ; try { cout << "Enter␣a␣positive␣number:␣" ; cin >> i ; if ( i < 0 ) throw MyException ( "Not␣Positive" , i ) ; } catch ( MyException e ) { cout << e . Str_What ( ) << ":␣" << e . What ( ) << endl ; } } Enter a positive number: -4 Not Positive: -4 Χαροκόπειο Πανεπιστήμιο 35/50 Πολλά catch #include < i o s t r e a m > using namespace std ; void Xhandler ( int test ) { try { if ( test ) throw test ; else throw "Value␣is␣zero" ; } catch ( int i ) { cout << "Caught␣Exception␣#:␣" << i << endl ; } catch ( const char * str ) { cout << "Caught␣a␣string:␣" << str << endl ; } } int main ( ) { cout << "Start" << endl ; Xhandler ( 1 ) ; Xhandler ( 2 ) ; Xhandler ( 0 ) ; Xhandler ( 3 ) ; cout << "End" << endl ; } Χαροκόπειο Πανεπιστήμιο 36/50 Πολλά catch Το προηγούμενο πρόγραμμα τυπώνει: Start Caught Caught Caught Caught End Exception Exception a string: Exception Χαροκόπειο Πανεπιστήμιο #: 1 #: 2 Value is zero #: 3 37/50 Πιάνοντας όλες τις Εξαιρέσεις Για να γράψουμε ένα catch που να πιάνει τα πάντα μπορούμε να χρησιμοποιήσουμε την εξής μορφή: catch(...) { // process all exceptions } Χαροκόπειο Πανεπιστήμιο 38/50 Πιάνοντας όλες τις Εξαιρέσεις #include < i o s t r e a m > using namespace std ; void Xhandler ( int test ) { try { if ( test == 0 ) throw test ; if ( test == 1 ) throw 'a' ; if ( test == 2 ) throw 1 . 3 3 ; } catch ( . . . ) { cout << "Caught␣Exception!" << endl ; } } int main ( ) { cout << "Start" << endl ; Xhandler ( 0 ) ; Xhandler ( 1 ) ; Xhandler ( 2 ) ; cout << "End" << endl ; } Χαροκόπειο Πανεπιστήμιο 39/50 Πιάνοντας όλες τις Εξαιρέσεις Το προηγούμενο πρόγραμμα τυπώνει: Start Caught Exception! Caught Exception! Caught Exception! End Χαροκόπειο Πανεπιστήμιο 40/50 Πιάνοντας όλες τις Εξαιρέσεις #include < i o s t r e a m > using namespace std ; void Xhandler ( int test ) { try { if ( test == 0 ) throw test ; if ( test == 1 ) throw 'a' ; if ( test == 2 ) throw 1 . 3 3 ; } catch ( int i ) { cout << "Caught␣an␣integer" << endl ; } catch ( . . . ) { cout << "Caught␣Other␣Exception!" << endl ; } } int main ( ) { cout << "Start" << endl ; Xhandler ( 0 ) ; Xhandler ( 1 ) ; Xhandler ( 2 ) ; cout << "End" << endl ; } Χαροκόπειο Πανεπιστήμιο 41/50 Πιάνοντας όλες τις Εξαιρέσεις Το προηγούμενο πρόγραμμα τυπώνει: Start Caught an integer Caught Other Exception! Caught Other Exception! End Χαροκόπειο Πανεπιστήμιο 42/50 Προσδιορίζοντας τις Εξαιρέσεις Μπορούμε να δηλώσουμε ρητά τους τύπους των εξαιρέσεων που μπορεί να πετάξει μια συνάρτηση. ret-type func-name(arg-list) throw(type-list) { //... } Εαν η συνάρτηση πετάξει οτιδήποτε που δεν ανήκει στην λίστα αυτή, η συνάρτηση unexpected() της τυπικής βιβλιοθήκης θα κληθεί. Η συνάρτηση αυτή όπως και η terminate() καλεί την abort(). Είναι όμως δυνατόν να αλλάξουμε αυτή την συμπεριφορά. Χαροκόπειο Πανεπιστήμιο 43/50 Επαναπέταγμα μιας Εξαίρεσης Μέσα σε ένα catch block μπορούμε να επαναπετάξουμε μια εξαίρεση. Αυτό είναι χρήσιμο εαν θέλουμε να διαχειριστούμε ένα λάθος τμηματικά. Για να συμβεί αυτό καλούμε την throw χωρίς παραμέτρους. Η εξαίρεση δεν θα πιαστεί από το ίδιο catch. Χαροκόπειο Πανεπιστήμιο 44/50 Επαναπέταγμα μιας Εξαίρεσης #include < i o s t r e a m > using namespace std ; void Xhandler ( ) { try { throw "hello" ; } catch ( const char * ) { cout << "Caught␣char␣*␣inside␣Xhandler" << endl ; throw ; / / rethrow out of f u n c t i o n } } int main ( ) { cout << "Start" << endl ; try { Xhandler ( ) ; } catch ( const char * ) { cout << "Caught␣char␣*␣inside␣main" << endl ; } cout << "End" << endl ; } Χαροκόπειο Πανεπιστήμιο 45/50 Επαναπέταγμα μιας Εξαίρεσης Το προηγούμενο πρόγραμμα τυπώνει: Start Caught char * inside Xhandler Caught char * inside main End Χαροκόπειο Πανεπιστήμιο 46/50 Επιστροφή στην Δυναμική Μνήμη Εξαίρεση bad_alloc Εαν για κάποιο λόγο δεν βρεθεί ο απαραίτητος χώρος που ζητήθηκε με την χρήση της new, η new πετάει την εξαίρεση bad_alloc. Η εξαίρεση αυτή είναι ορισμένη στο αρχείο επικεφαλίδας <new>. Χαροκόπειο Πανεπιστήμιο 47/50 Εξαίρεση bad_alloc #include < i o s t r e a m > #include <new> using namespace std ; int main ( ) { int * p ; try { p = new int ; } catch ( bad_alloc xa ) { cout << "Allocation␣failure" << endl ; return 1 ; } * p = 100; cout << "At␣" << p << "␣is␣the␣value␣" << * p << endl ; delete p ; } Χαροκόπειο Πανεπιστήμιο 48/50 Η Επιλογή nothrow Για να παρέχει η C++ πιο εύκολη μετάβαση από την C μας παρέχει και μια μορφή της new η οποία επιστρέφει null όταν η δέσμευση μνήμης αποτύχει. p_var = new(nothrow) type; Για την χρήση αυτής της μορφής πρέπει να κάνετε include το αρχείο επικεφαλίδας <new>. Χαροκόπειο Πανεπιστήμιο 49/50 Η Επιλογή nothrow #include < i o s t r e a m > #include <new> using namespace std ; int main ( ) { int * p ; p = new ( nothrow ) int ; if ( ! p ) { cout << "Allocation␣failure" << endl ; return 1 ; } * p = 100; cout << "At␣" << p << "␣is␣the␣value␣" << * p << endl ; delete p ; } Χαροκόπειο Πανεπιστήμιο 50/50
© Copyright 2024 Paperzz