Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ. (επεξεργασμένο)

http://techforum4u.c...Techniques-In-C

 

μια καλη πηγη με μερικα tips για optimization

 

Πέρα από γενικότητες, δεν είδα να έχει κάποιο tip με την έννοια κάνε αυτό και εκείνο το βήμα. Ειδικά το "βάλε high-speed raid array" ήταν τέλειο tip :)

 

Όντως το benchmarking είναι επιστήμη όπως λέει ο migf1 αλλά εγώ είμαι της άποψης readability > micro-optimization. Ο compiler θα κάνει τα nested loops σε μη-nested, θα τα κάνει unroll αν πρέπει και γενικά θα κάνει ό,τι είναι δυνατό για να παίζει πιο γρήγορα ο κώδικας. Οι πιο πολλές "τακτικές για επιδόσεις" όπως "x >> 1" αντί για "x /= 2" και όπως το flattening των πινάκων είναι (κατά την προσωπική μου υποκειμενική γνώμη) χαζομάρες. Ο θείος compiler ξέρει που έλεγε και μια παλιά διαφήμιση.

 

Για να φανταστείς σε τι βαθμό φτάνει το optimization, μια απλή πράξη όπως είναι η διαίρεση να πας να κάνεις, αν διαιρείς με γνωστό στον compiler αριθμό αυτός δεν θα κάνει διαίρεση επειδή είναι αργή αλλά εκμεταλλεύεται το "overflow" των unsigned αριθμών και διάφορες άλλες τακτικές και πραγματοποιεί πολλαπλασιασμό με ένα πολύ μεγάλο αριθμό αντί για διαίρεση.

 

Όσον αφορά τις ερμηνείες που είπε ο migf1, δυστυχώς υπάρχει όντως θέμα. Το C++ είναι πιο strict και δεν έχει τόσες παρερμηνείες αλλά το C πρότυπο σηκώνει πολλή παρερμηνεία (αν και στο συγκεκριμένο θέμα, το undefined είναι η επίσημη ερμηνεία). Εκτός από τις διαφορετικές ερμηνείες υπάρχουν και άλλα θέματα και αντιφάσεις που είπε ο migf1 όπως αυτό με τις union που ανέφερα πριν. Σε λίγη ώρα που θα έχω περισσότερο χρόνο θα βρω τα αντίστοιχα εδάφια για να το συζητήσουμε.

 

Να μην ξεχνάμε και το πρόβλημα του eclipse που είπαμε. Κανείς δεν δουλεύει eclipse σε windows ? Όλοι Visual Studio δουλεύουν ? :P

 

Edit:

Έβαλα το eclipse και τον MinGW και πήγα New-> C Project -> Hello World Ansi Project. Πρόσθεσα μια κλήση συνάρτησης που δεν υπάρχει και όταν κάνω build παίρνω το εξής:

 

post-84828-0-77669200-1352643361_thumb.png

 

 

Κάτω κάτω υπάρχει το παράθυρο console που εμφανίζει τα λάθη καθώς και την έξοδο του προγράμματος. Ίδια ακριβώς συμπεριφορά έχει και το *nix eclipse. Μήπως ρώτησες κάτι άλλο και δεν κατάλαβα ?

Επεξ/σία από imitheos
  • Απαντ. 1,6k
  • Δημ.
  • Τελ. απάντηση

Συχνή συμμετοχή στο θέμα

Δημοσ.

...

Όντως το benchmarking είναι επιστήμη όπως λέει ο migf1 αλλά εγώ είμαι της άποψης readability > micro-optimization. Ο compiler θα κάνει τα nested loops σε μη-nested, θα τα κάνει unroll αν πρέπει και γενικά θα κάνει ό,τι είναι δυνατό για να παίζει πιο γρήγορα ο κώδικας. Οι πιο πολλές "τακτικές για επιδόσεις" όπως "x >> 1" αντί για "x /= 2" και όπως το flattening των πινάκων είναι (κατά την προσωπική μου υποκειμενική γνώμη) χαζομάρες. Ο θείος compiler ξέρει που έλεγε και μια παλιά διαφήμιση.

...

 

Κι όμως ο θειος compiler δεν ξέρει πάντα.

 

Βέβαια σε γενικό context συμφωνώ κι εγώ πως το pre-mature optimization δεν έχει νόημα, μιας και οι περισσότεροι από τους δημοφιλείς compilers είναι πλέον ιδιαίτερα "έξυπνοι", οπότε στη πλειοψηφία των περιπτώσεων το μόνο που χρειάζεται είναι απλώς να ενεργοποιήσουμε τα optimization flags τους (αν κι αυτό χρειάζεται λίγο διάβασμα πρώτα στην τεκμηρίωση του εκάστοτε compiler... π.χ. ο gcc έχει αρκετά περισσότερα από 1 optimization flag: http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html).

 

Το θέμα όμως έρχεται στο προσκήνιο με βαρύνουσα πλέον σημασία όταν γράφουμε speed-critical εφαρμογές, και ιδιαίτερα όταν δεν είναι εγγυημένο πως ο κώδικάς μας θα γίνεται πάντα compile με τον compiler που χρησιμοποιούσαμε εμείς όταν γράφαμε τον κώδικα (συχνά παίζει ρόλο ακόμα και η έκδοση του ίδιου compiler).

 

Δείτε για παράδειγμα ένα ακόμα άρθρο από το ίδιο site που συνέστησα σε προηγούμενο ποστ (τότε αναφορικά με τον δείκτη *walk): http://nadeausoftware.com/articles/2012/05/c_c_tip_how_copy_memory_quickly

 

Αυτή τη φορά το νέο άρθρο αφορά γρήγορη αντιγραφή μνήμης, και όπως βλέπουμε, διατυπώνεται ξεκάθαρα στα Conclusions (στο τέλος του άρθρου)...

 

PGCC and CLANG/LLVM both missed optimizing common code constructs, producing unexpectedly bad performance.

 

Πιο συγκεκριμένα, εξηγεί λίγο παραπάνω πως...

 

...

Benchmark results – compiled with optimizations

...

  • PGCC fails to optimize the loop with array indexes (blue) or get/set functions (yellow). The array index loop is a common code construct and should have been recognized and optimized, and the get/set functions should have been inlined. Additional, while the pointer loop (green) was optimized, its performance drops off suddenly at the 256 Kbyte array test, which is odd.
     
  • CLANG/LLVM fails to optimize the loop with pointers (green). This is a very common code construct and should have been optimized.

 

Ενδεχομένως νεότερες εκδόσεις των 2 αυτών compilers να κάνουν καλύτερη δουλειά, αλλά το main point είναι πως δεν μπορούμε να βασιζόμαστε τυφλά στα αυτόματα optimizations των compilers.

 

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

 

Ιδανικά πρέπει να επαναλαμβάνουμε τα παραπάνω σε κάθε νέα έκδοσή τους.

 

Οπότε σε speed-crtitcal εφαρμογές (και ιδιαίτερα αν δεν ξέρουμε με ποιον compiler ή ποια έκδοση του όποιου compiler θα γίνει compiled ο κώδικάς μας) συχνά είναι πιο παραγωγικό να χρησιμοποιήσουμε εξαρχής pre-mature optimization στα καίρια σημεία του κώδικά μας.

Δημοσ.

Το θέμα όμως έρχεται στο προσκήνιο με βαρύνουσα πλέον σημασία όταν γράφουμε speed-critical εφαρμογές, και ιδιαίτερα όταν δεν είναι εγγυημένο πως ο κώδικάς μας θα γίνεται πάντα compile με τον compiler που χρησιμοποιούσαμε εμείς όταν γράφαμε τον κώδικα (συχνά παίζει ρόλο ακόμα και η έκδοση του ίδιου compiler).

 

Ενδεχομένως νεότερες εκδόσεις των 2 αυτών compilers να κάνουν καλύτερη δουλειά, αλλά το main point είναι πως δεν μπορούμε να βασιζόμαστε τυφλά στα αυτόματα optimizations των compilers.

 

Οπότε σε speed-crtitcal εφαρμογές (και ιδιαίτερα αν δεν ξέρουμε με ποιον compiler ή ποια έκδοση του όποιου compiler θα γίνει compiled ο κώδικάς μας) συχνά είναι πιο παραγωγικό να χρησιμοποιήσουμε εξαρχής pre-mature optimization στα καίρια σημεία του κώδικά μας.

 

Το clang είναι σχετικά νέο project σε σχέση με το gcc που υπάρχει 130 χρόνια οπότε δικαιολογείται. Ο 3.1 LLVM που βγήκε 15 μέρες μετά το άρθρο είχε βελτιώσεις στον optimizer. Επίσης εγώ μίλησα γενικά για το κόσμο με μέτρια εμπειρία που διαβάζει το νήμα (και υποθέτω και το άρθρο σε μεγάλο βαθμό σε τέτοιους αναγνώστες απευθύνεται). Κάποιος που γράφει "speed critical εφαρμογές" και είναι "εξοικειωμένος με τον compiler" εννοείται πως μπορεί να κάνει ό,τι θέλει.

 

Όσον αφορά τις αντιφάσεις που ανέφερες πριν ας πω αυτό που έλεγα για τις unions. Μια "νόμιμη" χρήση των unions είναι για generic programming δηλαδή να έχεις μια union με διάφορους τύπους μέσα σε μια δομή και με βάση ένα πεδίο ελέγχου (συνήθως enum) να διαβάζεις / γράφεις τον αντίστοιχο τύπο που θέλεις. Έτσι αντί να έχουμε 10 δομές έχουμε μόνο μία.

 

Μία άλλη πολύ κοινή πρακτική είναι να χρησιμοποιείται η union για να βλέπουμε την αναπαράσταση κάποιου τύπου όπως πχ την αναπαράσταση ενός float ή την endianness ενός μηχανήματος.

 

>
#include <stdio.h>

int main(void)
{
   union endian {
       int i;
       char c[sizeof(int)];
   } myendian;

   myendian.i = 1;
   if (myendian.c[0])
       printf("Little-Endian\n");
   else
       printf("Big-Endian\n");

   return 0;
}

Για ευκολία ας υποθέσουμε 16bit int. Θέτουμε την τιμή 1 δηλαδή 0x0001 και μετά διαβάζουμε το 1ο char. Αν το μηχάνημα είναι Little-Endian, ο int θα έχει αποθηκευτεί ως 0x0100 οπότε το c[0] θα είναι 1. Τέτοιοι κώδικες κυκλοφορούν παντού.

 

Η C89 λέει στην παράγραφο 6.3.2.3 "If a member of a union object is access after a value has been stored in a different member of the object, the behavior is implementation-defined." και το ίδιο συνοψίζεται στο παράρτημα G3.9.

 

Πάμε τώρα στην C99. Σημειωτέον ότι η επιτροπή κοιτάζει στην εκάστοτε έκδοση του προτύπου να επισημοποιήσει την βέλτιστη πρακτική από πρακτικές που είναι κοινές και υποστηρίζονται από πολλούς compiler την εκάστοτε εποχή και όχι να εισάγει νέες πρακτικές. Με αυτό το σκεπτικό θα έπρεπε να επισημοποιηθεί ότι μπορείς να διαβάζεις όποιο πεδίο από μία union θέλεις. Παρόλα αυτά δεν άλλαξε κάτι και μέχρι και την 2η βελτιωτική αναθεώρηση TC2 που βγήκε το 2005 αναφέρονται τα ίδια. Συνοπτικά το παράρτημα J2 αναφέρει ως unspecified "The value of a union member other than the last one stored into (6.2.6.1).".

 

Για κάμποσο καιρό είχαν γίνει διάφορες νύξεις με defect reports να ξεκαθαριστεί το θέμα και τελικά στην 3η βελτιωτική αναθεώρηση TC3 που βγήκε το Σεπτέμβριο 2007, μπήκε ένα footnote το οποίο ξεκαθαρίζει "If the member used to access the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type" δηλαδή μπορείς να χρησιμοποιήσεις τον παραπάνω κώδικα και αυτή η συμπεριφορά συνεχίστηκε και στο C11. Μάλλον από λάθος, παρέμεινε η αναφορά στο παράρτημα J2 το οποίο συνεχίζει να το αναφέρει ως unspecified (το συγκεκριμένο παράρτημα όμως είναι μόνο πληροφοριακό και όχι δεσμευτικό).

 

Οπότε, αν έχεις C89 compiler δεν είσαι σίγουρος ότι ο κώδικας θα παίζει σωστά. Αν έχεις C99 compiler δεν είσαι σίγουρος ότι θα παίζει γιατί μπορεί να μην έχει ενσωματώσει την 3η βελτιωτική αναθεώρηση. Αν έχεις C99-TC3 ή C11 compiler και πάλι δεν είσαι σίγουρος γιατί μόνο το κυρίως κείμενο είναι δεσμευτικό και όχι τα footnote οπότε μπορεί ο compiler να το γράψει στα @@ του :)

 

Αυτά για την άχρηστη πληροφορία της σημερινής ημέρας :P Ας πάω να κάνω και καμμιά δουλειά.

Δημοσ.

Ναι, τα unions δεν ενδεικνύονται για portable κώδικα. Η κύρια χρησιμότητά τους είναι για εξοικονόμηση μνήμης (καθώς και ταχύτητα, είναι ταχύτερα από το casting... δεν είμαι 100% σίγουρος, διασταυρώστε το) σε implementation specific context.

 

ΥΓ. Δεν καταλαβαίνω την αμυντική στάση που πήρες στα σχόλια μου περί "ο θείος compiler ξέρει". Δεν σου έκανα προσωπική επίθεση, ενημερωτική τοποθέτηση έκανα και μάλιστα ορίζοντας συγκεκριμένο context. Τοποθετήθηκες υποκειμενικά όπως έγραψες πως γενικώς κι αορίστως το pre-mature optimization είναι χαζό επειδή ο θείος compiler ξέρει, και θεώρησα χρήσιμο να επισημάνω όσο πιο εμπεριστατωμένα μπορούσα πως ο θείος compiler δεν ξέρει πάντα και δεν τα ξέρει όλα.

Δημοσ.

ΥΓ. Δεν καταλαβαίνω την αμυντική στάση που πήρες στα σχόλια μου περί "ο θείος compiler ξέρει". Δεν σου έκανα προσωπική επίθεση, ενημερωτική τοποθέτηση έκανα και μάλιστα ορίζοντας συγκεκριμένο context. Τοποθετήθηκες υποκειμενικά όπως έγραψες πως γενικώς κι αορίστως το pre-mature optimization είναι χαζό επειδή ο θείος compiler ξέρει, και θεώρησα χρήσιμο να επισημάνω όσο πιο εμπεριστατωμένα μπορούσα πως ο θείος compiler δεν ξέρει πάντα και δεν τα ξέρει όλα.

 

Ε ? Ξαναδιαβάζω τώρα το μήνυμά μου και δεν μου φαίνεται ότι απήντησα αμυντικά / απότομα. Επίσης δεν εξέλαβα το μήνυμά σου σαν επίθεση προς εμέ, δεν μου πέρασε καν από το μυαλό για επίθεση.

 

Edit: Ping στον nik324. Δες λίγο την εικόνα από το προηγούμενο μήνυμά μου για το eclipse.

Δημοσ.

Αν το βιβλιο που λεω το θεωρει σαν διπλο δεικτη τοτε ειναι λαθος .

 

Αν ο multi ειναι διπλος... τοτε το &multi ειναι τριπλος? δεν παει ετσι.

 

Το προτυπο δεν αναφερει πουθενα για διπλους δεικτες.

 

>

#include <stdio.h>

int main(void)
{

int a[4][3] = { {1 , 2 , 3} , { 3 , 4 , 5} , { 5 , 5, 4} , { 3 , 3 , 3} } ;

printf(" %d " , *( (*a) + 1 ) ) ;

return 0;
}

 

Το * ( (*a) + 1 ) ) ειναι ισοδυναμο με * ( (a[0] + 1 ) ) . To a[0] + 1 ειναι διευθυνση του 2ου στοιχειου του 1ου πινακα αρα με * παιρνεις το περιεχομενο της. Το 2 σε αυτη την περιπτωση.

 

Αν εχω καταλαβει τι θες να πεις..... με το οτι το βιβλιο το γραφει σωστα.

Δημοσ.

Αν το βιβλιο που λεω το θεωρει σαν διπλο δεικτη τοτε ειναι λαθος .

 

Αν ο multi ειναι διπλος... τοτε το &multi ειναι τριπλος? δεν παει ετσι.

 

Έτσι πάει.

 

Το προτυπο δεν αναφερει πουθενα για διπλους δεικτες.

 

Αυτά που έχω κοκκινισμένα στο πρότυπο τα είδες;

 

Για το x το x μετατρέπεται σε δείκτη πινάκων, ο οποίος με η σειρά του για το x[j] μετατρέπεται σε νέο δείκτη στοιχείου. Αυτό ακριβώς λένε τα κοκκινισμένα (από μένα) στο πρότυπο.

Δημοσ.

Οχι. Γιατι δινουν ιδιες διευθυνσεις.

 

Αν το πάρεις ετσι πρεπει μετα να δικαιολογησεις αυτο που επισης λεει το προτυπο

για τον τελεστη & διπλα σε πινακες οπως επισης και την τιμη του πινακα που δεν ειναι αλλη διευθυνση αλλα στοιχειο.

Το εξηγησε και ο ημιθεος αυτο και μου φανηκε λογικη η εξηγηση του.

 

Ουτε σε ξενο φορουμ που ρωτησα τολμησε κανεις να μιλησει για διπλους δεικτες σε τετοιο σημειο.

Δημοσ.

Δεν είμαι εγώ αρμόδιος να δικαιολογήσω τα πρότυπα, σε αυτούς που τα γράφουν πρέπει να απευθυνθείς :P

 

ΥΓ. Btw, το ότι δίνουν ίδιες διευθύνσεις είναι επιβεβαίωση των κοκκινισμένων του προτύπου.

Δημοσ.

Ωραια τοτε πρεπει να ρωτησουμε κάποιον που να μπορει να απαντησει αν οντως είναι ή δεν ειναι ξεκάθαρα.

 

Σε ποιον θες να στειλεις email? Στον King ή τον Torvalds? :D

 

Εμενα παντως το επιχειρημα οτι η τιμή του a σαν διεύθυνση δεν μπορει να χρησιμοποιηθει σαν αλλη διευθυνση ωστε να πεις οτι οντως προκειται για διπλο δεικτη μου κανει.

 

Διοτι αν ειχες εναν διπλο και έλεγες οτι

 

>

int x=2 , *p = &x , **pp = &p ;

 

Τοτε κανοντας προσπελαση στο pp παιρνεις την διευθυνση του p και αυτη η τιμη μπορει να χρ/θει σαν μια αλλη διευθυνση αυτη του x .

Δημοσ.

Ουτε σε ξενο φορουμ που ρωτησα τολμησε κανεις να μιλησει για διπλους δεικτες σε τετοιο σημειο.

 

Αυτό το έγραψες την ώρα που έγραφα κι εγώ.

 

Ε και; Τι σημαίνει αυτό; Σημαίνει πως δεν υπάρχει η σχετική παράγραφος στο πρότυπο; Κάντους το copy & paste οπότε στο εξής να τολμάνε :lol:

 

Για να ξεκαθαρίζουμε όμως για τι μιλάμε (γιατί νομίζω δεν το έχεις καταλάβει) μιλάμε για ισοδυναμία και όχι για ισότητα.

 

Ωραια τοτε πρεπει να ρωτησουμε κάποιον που να μπορει να απαντησει αν οντως είναι ή δεν ειναι ξεκάθαρα.

 

Σε ποιον θες να στειλεις email? Στον King ή τον Torvalds? :D

 

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

Δημοσ.

MIGF1 αν ο δισδιαστατος πινακας ηταν οντως ενας διπλος δεικτης τοτε

μεσα σε μια συνάρτηση θα μπορούσες να περάσεις εναν βέρο διπλο οπως κάνεις και με μια συναρτηση και εναν single pointer.

 

Απλα στην περιπτωση του απλου πινακα της μιας διαστασης η ισοδυναμια κολλαει καλυτερα επειδη προκειται για δεικτη.... η παρεξηγηση απο εκει και πανω ομως κτυπαει στον compiler οποτε καταλαβαινει κανεις περαιτερω οτι αυτη η γενικη θεωρια δεν μπορει να εφαρμοστει και περισσοτερο....

 

Οσο για αυτα που εφαρμοζεις και χρησιμοποιεις άπειρες φορες δεν εχω προβάλλει καποια αμφισβητηση καθως έχεις γραψει αξιολογα ακομη και αξιοζηλευτα με την καλη πλευρα παντοτε της έννοιας επαγγελματικα προγραμματα αλλα αυτο δεν εχει να λεει επειδη αυτο που συζηταμε εδω εχει να κανει με θεωρια..... στην πραξη ειτε νομιζεις πως ειναι διπλος ο πινακας ειτε οχι μια χαρα τον δουλευεις.... μονο στην περιπτωση που πας να περάσεις εναν δισδιαστατο πινακα μεσα σε μια συναρτηση και οταν πας να την γραψεις βάλεις **pointer μεσα στις παραμετρους της εκει θα κτυπησει. Ισως επειδη σου λεει οτι δεν μπορει να εκχωρησει την τιμη του πινακα σε εναν διπλο δεικτη.

 

υ.γ Τι σε κανει να πιστευεις οτι αυτοι οι ανθρωποι δεν εχουν διαβασει το προτυπο αλλα αποφευγουν να απαντησουν απλα σε τετοιες ερωτησεις? :D

Δημοσ.

MIGF1 αν ο δισδιαστατος πινακας ηταν οντως ενας διπλος δεικτης τοτε

μεσα σε μια συνάρτηση θα μπορούσες να περάσεις εναν βέρο διπλο οπως κάνεις και με μια συναρτηση και εναν single pointer.

 

Ρε συ Κώστα, το έχουμε λιώσει στην εξήγηση το θέμα (καταλαβαίνω πως δεν το κατανοείς με τίποτα... οπότε όπως σου είπα και στο π.μ. άστο και πήγαινε παρακάτω... γράφε τα πάντα με [][] notation τα 2D και άσε τον compiler να κάνει τα optimizations).

 

Απλα στην περιπτωση του απλου πινακα της μιας διαστασης η ισοδυναμια κολλαει καλυτερα επειδη προκειται για δεικτη.... η παρεξηγηση απο εκει και πανω ομως κτυπαει στον compiler οποτε καταλαβαινει κανεις περαιτερω οτι αυτη η γενικη θεωρια δεν μπορει να εφαρμοστει και περισσοτερο....

 

Ξαναλέω λοιπόν πως μιλάμε για ισοδυναμία και όχι για ισότητα. Και για του λόγου το αληθές, ορίστε κώδικας που καταρρρίπτει αυτό που γράφεις...

 

>
#include <stdio.h>
#include <stdlib.h>

#define NROWS    2
#define NCOLS    3

// ---------------------------------------
void arrInt2d_print( int **arrInt2d, int nrows, int ncols )
{
   if ( !arrInt2d || nrows < 1 || ncols < 1 || nrows > NROWS || ncols > NCOLS )
       return;

   int *walk = (int *)arrInt2d;
   int *stop = (int *)arrInt2d + nrows * ncols;

   while ( walk < stop )
       printf( "%d\n", *walk++ );
   return;

}

// ---------------------------------------
int main( void )
{
   int arr2d[NROWS][NCOLS] = { {10, 20, 30}, {40, 50, 60} };

   arrInt2d_print( (int **)arr2d, NROWS, NCOLS );

   system("pause");
   exit(0);
}

 

Όπως βλέπεις μια χαρά περνάω τον ορισμένο ως 2d πίνακα στην συνάρτηση, κάνοντάς τον cast σε βέρο διπλό δείκτη (ισοδυναμία και ουχί ισότητα) και δουλεύει μια χαρά η συνάρτηση, ούτε καν warnings.

Δημοσ.

@migf1 να σε ρωτησω κατι?

 

Δηλαδη εσυ πιστευεις οτι αυτο εδω ->

 

(*p) ειναι δείκτης σε δεικτη και αρα διπλος δεικτης? ενα ναι ή ενα οχι θέλω.

 

Ενταξει το δεχεται ο μεταγλωτιστης επειδη το κανεις πρωτα cast σε διπλο δεικτη... μαλλον δεν με καταλαβαινεις....

 

εγω λεω για αυτο εδω ->

 

http://c-faq.com/aryptr/pass2dary.html

 

οπως επισης και για το αν θα περνουσες τον arr2d σκετο με το ονομα του χωρις ηθελημενες μετατροπες στον τυπο που εσυ θέλεις.

 

Μια χαρα εχω καταλαβει πως δουλευουν... αλλου ειναι η διαφωνια μας οπως βλεπεις.

 

The rule (see question 6.3) by which arrays decay into pointers is not applied recursively

 

Πάρε και απο stackoverflow

 

http://stackoverflow...-double-pointer

 

 

Is 2d array a double pointer?

No. This line of your program is incorrect:

 

Και εχει και 7 ψηφους.

 

 

Ψηνομαι ασχημα να στειλω μηνυμα και στον King ρισκαροντας το να με περάσει τρελό ή ψωνιο.

Επισκέπτης
Αυτό το θέμα είναι πλέον κλειστό για περαιτέρω απαντήσεις.

  • Δημιουργία νέου...