imitheos Δημοσ. 11 Οκτωβρίου 2012 Δημοσ. 11 Οκτωβρίου 2012 OK ευχαριστώ.. Αλλά και η fgets διαβάζει το \n και το αποθηκεύει.. μπορώ να το αποφύγω αυτό χωρίς το while; > .... fgets(text, MAXINPUT, stdin); len = strlen(text); if (text[len - 1] == '\n') text[len - 1] = '\0'; Μπορείς να "σβήσεις" την αλλαγή γραμμής. Ένας συνήθης τρόπος είναι ο παραπάνω. Αν ο τελευταίος χαρακτήρας είναι αλλαγή γραμμής, τότε του αλλάζεις τιμή σε '\0' οπότε είναι σαν να τελείωνε εκεί το string. Αν το χρησιμοποιείς σε πολλά σημεία, μπορείς να το πετάξεις σε μια συνάρτηση re4ctiv3_fgets και μετά να καλείς παντού αυτήν. EDIT: και ποιος είναι τότε ο "ασφαλέστερος" τρόπος για να διαβάσουμε έναν αριθμό; Μια σχετικά ασφαλή μέθοδος είναι να τον διαβάζεις σαν string με την fgets και μετά να χρησιμοποιείς μια συνάρτηση μετατροπής όπως strtol, strtod, κτλ. Έτσι έχεις πολύ καλύτερο έλεγχο σε περίπτωση που δοθούν λανθασμένες τιμές. Αν δεις σε προηγούμενες σελίδες του νήματος νομίζω έχουμε ξανα-αναφέρει αυτό το θέμα. 1
Star_Light Δημοσ. 13 Οκτωβρίου 2012 Δημοσ. 13 Οκτωβρίου 2012 Εχω συνδέσει το οτι τα arguments μιας συνάρτησης που περνάνε στην C by value και ουσιαστικα ειναι αντίγραφα με την διευθυνση μνήμης. Πχ ενα αντιγραφο έχει ιδια τιμή αλλα διαφορετικη θεση μνημης. Εχω άδικο? Ισως ειναι πολυ αυτονοητο αυτο που ρωταω αλλα θελω μια ξενη γνωμη. > #include<stdio.h> void f( int * ); int main(void) { int z=1 , *p = &z; printf(" In the function f()... "); f(p); printf(" After the function f() ... "); printf(" %p " , &p); printf(" %d " , *p); return 0; } void f( int * p) { int x = 2; p= &x; printf(" %p " , &p); printf(" %d " , *p); return ; } To ξερω οτι το p = &z στην main και μετα f(p) στην κληση ειναι πολυπλοκο και θα ηταν καλυτερα να παει απευθειας f(&z) αλλα το εκανα επιτηδες για να τσεκαρω ποια θεση μνημης δεσμευει ο μεταγλωτιστης για τον δεικτη. Η διευθυνση του δεικτη με ενδιεφερε . P.S Μαλλον το αντιγραφο τονιζεται ως προς το οτι ειναι προσωρινο και παυει να ισχυει μολις τελειωσει η συναρτηση και επιστρέψει στο σημειο οπου κληθηκε.
παπι Δημοσ. 13 Οκτωβρίου 2012 Δημοσ. 13 Οκτωβρίου 2012 Θα στο απλωσει στο stack frame (google ebp register) πχ > typedef struct { int x,y,z; }s; void foo(int x, int y,int z) { printf("%d %d %d", x, y, z); } typedef void (*foo_s)(s); int main(int argc, char **argv) { s _s = {1,2,3}; ((foo_s)foo)(_s); return 0; }
imitheos Δημοσ. 13 Οκτωβρίου 2012 Δημοσ. 13 Οκτωβρίου 2012 Εχω συνδέσει το οτι τα arguments μιας συνάρτησης που περνάνε στην C by value και ουσιαστικα ειναι αντίγραφα με την διευθυνση μνήμης. Πχ ενα αντιγραφο έχει ιδια τιμή αλλα διαφορετικη θεση μνημης. Ναι στην C τα πάντα περνάνε "by value". Όλα τα αντικείμενα έχουν μια διεύθυνση και μια τιμή. Όπως όταν δηλώνουμε μια μεταβλητή και της θέτουμε μια τιμή, δεσμεύεται μια διεύθυνση και εκεί μπαίνει η τιμή, έτσι και στην περίπτωση των παραμέτρων των συναρτήσεων δεσμεύεται μια διεύθυνση και εκεί αντιγράφεται η τιμή που δίνουμε. Οι δείκτες συμπεριφέρονται το ίδιο με τις απλές μεταβλητές και απλή η τιμή τους είναι μια άλλη διεύθυνση. P.S Μαλλον το αντιγραφο τονιζεται ως προς το οτι ειναι προσωρινο και παυει να ισχυει μολις τελειωσει η συναρτηση και επιστρέψει στο σημειο οπου κληθηκε. Όχι το γεγονός ότι όταν επιστρέψει η συνάρτηση αποδεσμεύεται η μνήμη δεν έχει σχέση με το "by value". Γράφοντας "p=%x" στη συνάρτηση, άλλαξες τον δείκτη να δείχνει αλλού οπότε δεν φαίνεται αυτό που είπες. > #include<stdio.h> void f(int *p); int main(void) { int z = 1; int *p = &z; printf(" In the function f()... \n"); f(p); printf(" After the function f() ... \n"); printf(" %p -> " , (void *)&p); printf(" %p\n " , (void *)p); printf(" %d\n " , *p); return 0; } void f(int *p) { printf(" %p -> " , (void *)&p); printf(" %p\n " , (void *)p); printf(" %d\n " , *p); *p = 2; } Έξοδος: In the function f()... 0xabea78 -> 0xabea9c 1 After the function f() ... 0xabea90 -> 0xabea9c 2 Άλλαξα τον κώδικα ώστε να εμφανίζει εκτός από την διεύθυνση του δείκτη p και την τιμή του. Όπως βλέπουμε, όταν δηλώσαμε τον δείκτη p μέσα στην main, δεσμεύτηκε η διεύθυνση abea90 και ο δείκτης ήταν έτοιμος για χρήση. Η τιμή ενός δείκτη είπαμε ότι είναι μια διεύθυνση οπότε όταν λέμε p = &z στη main, η τιμή που γράφεται είναι η διεύθυνση της μεταβλητής z που είναι η abea9c. Μέσα στην συνάρτηση f, δεσμεύεται μνήμη για ένα νέο αντικείμενο τύπου δείκτης σε int και παίρνουμε τη διεύθυνση abea78 που όπως βλέπουμε είναι διαφορετική από την 90 γιατί τα δύο p είναι διαφορετικά αντικείμενα. Επειδή στη C είπαμε οι παράμετροι περνάνε "by value" έχουμε αντιγραφή της τιμής του αρχικού p στον νέο p για αυτό και τα δύο αντικείμενα δείχνουν στη διεύθυνση 9c και έτσι μπορούμε έμμεσα να έχουμε πρόσβαση στη μεταβλητή z. Όπως δηλαδή όταν περνούμε μια απλή μεταβλητή "int k = 5" θα αντιγραφεί το 5 στην συνάρτηση, το ίδιο γίνεται και στον δείκτη με τη μόνη διαφορά ότι αντί ο δείκτης να έχει ως τιμή το 5 έχει μια διεύθυνση (την οποία μπορούμε αν μας ευκολύνει να την δούμε σαν ένα απλό αριθμό όπως το 5) 1
παπι Δημοσ. 13 Οκτωβρίου 2012 Δημοσ. 13 Οκτωβρίου 2012 Αλλα νταλαμ καταλαβα... Να συμπληρωσω στο Ναι στην C τα πάντα περνάνε "by value". Οτι το by pointer ειναι τεχνικη, δεν εχει κατι η c απο μονη της που να κανει αυτη τη δουλεια. Αλλες γλωσσες εχουν πχ η c++ εχει το reference (type&)
migf1 Δημοσ. 13 Οκτωβρίου 2012 Δημοσ. 13 Οκτωβρίου 2012 Εχω συνδέσει το οτι τα arguments μιας συνάρτησης που περνάνε στην C by value και ουσιαστικα ειναι αντίγραφα με την διευθυνση μνήμης. Πχ ενα αντιγραφο έχει ιδια τιμή αλλα διαφορετικη θεση μνημης. Εχω άδικο? Ισως ειναι πολυ αυτονοητο αυτο που ρωταω αλλα θελω μια ξενη γνωμη. ... Σε γενικές γραμμές δεν έχεις άδικο. Αυτά τα καθορίζουν τα λεγόμενα function calling conventions, τα οποία ενδέχεται να διαφέρουν από πλατφόρμα/compiler σε πλατφόρμα/compiler. Σε γενικές γραμμές ισχύει αυτό που είπες.
Star_Light Δημοσ. 13 Οκτωβρίου 2012 Δημοσ. 13 Οκτωβρίου 2012 (επεξεργασμένο) Ναι στην C τα πάντα περνάνε "by value". Όλα τα αντικείμενα έχουν μια διεύθυνση και μια τιμή. Όπως όταν δηλώνουμε μια μεταβλητή και της θέτουμε μια τιμή, δεσμεύεται μια διεύθυνση και εκεί μπαίνει η τιμή, έτσι και στην περίπτωση των παραμέτρων των συναρτήσεων δεσμεύεται μια διεύθυνση και εκεί αντιγράφεται η τιμή που δίνουμε. Οι δείκτες συμπεριφέρονται το ίδιο με τις απλές μεταβλητές και απλή η τιμή τους είναι μια άλλη διεύθυνση. Όχι το γεγονός ότι όταν επιστρέψει η συνάρτηση αποδεσμεύεται η μνήμη δεν έχει σχέση με το "by value". Γράφοντας "p=%x" στη συνάρτηση, άλλαξες τον δείκτη να δείχνει αλλού οπότε δεν φαίνεται αυτό που είπες. > #include<stdio.h> void f(int *p); int main(void) { int z = 1; int *p = &z; printf(" In the function f()... \n"); f(p); printf(" After the function f() ... \n"); printf(" %p -> " , (void *)&p); printf(" %p\n " , (void *)p); printf(" %d\n " , *p); return 0; } void f(int *p) { printf(" %p -> " , (void *)&p); printf(" %p\n " , (void *)p); printf(" %d\n " , *p); *p = 2; } Έξοδος: In the function f()... 0xabea78 -> 0xabea9c 1 After the function f() ... 0xabea90 -> 0xabea9c 2 Άλλαξα τον κώδικα ώστε να εμφανίζει εκτός από την διεύθυνση του δείκτη p και την τιμή του. Όπως βλέπουμε, όταν δηλώσαμε τον δείκτη p μέσα στην main, δεσμεύτηκε η διεύθυνση abea90 και ο δείκτης ήταν έτοιμος για χρήση. Η τιμή ενός δείκτη είπαμε ότι είναι μια διεύθυνση οπότε όταν λέμε p = &z στη main, η τιμή που γράφεται είναι η διεύθυνση της μεταβλητής z που είναι η abea9c. Μέσα στην συνάρτηση f, δεσμεύεται μνήμη για ένα νέο αντικείμενο τύπου δείκτης σε int και παίρνουμε τη διεύθυνση abea78 που όπως βλέπουμε είναι διαφορετική από την 90 γιατί τα δύο p είναι διαφορετικά αντικείμενα. Επειδή στη C είπαμε οι παράμετροι περνάνε "by value" έχουμε αντιγραφή της τιμής του αρχικού p στον νέο p για αυτό και τα δύο αντικείμενα δείχνουν στη διεύθυνση 9c και έτσι μπορούμε έμμεσα να έχουμε πρόσβαση στη μεταβλητή z. Όπως δηλαδή όταν περνούμε μια απλή μεταβλητή "int k = 5" θα αντιγραφεί το 5 στην συνάρτηση, το ίδιο γίνεται και στον δείκτη με τη μόνη διαφορά ότι αντί ο δείκτης να έχει ως τιμή το 5 έχει μια διεύθυνση (την οποία μπορούμε αν μας ευκολύνει να την δούμε σαν ένα απλό αριθμό όπως το 5) Ναι οκ . Τα 2 p ειναι διαφορετικα γιατι ο p μεσα στην συνάρτηση ειναι αντιγραφο του p της main οπως ακριβως συμβαινει και με τις μεταβλητες επειδη ακριβως η C ειναι αυστηρα pass by value οπως ειπε και ο παπι το by reference ειναι προσομοιωση μεσω δεικτων . Ηθελα απλα να δω τον ορισμο για το αντιγραφο.... αλλα ενταξει εφοσον αλλαζει η θεση μνημης του δεν χρειαζεται να το ψαξουμε αλλο. Αν πχ εχουμε 2 ανθρώπους που ο Α ειναι κλώνος του Β έχουν τα ιδια χαρακτηριστικα - ιδιες τιμές αλλα καταλαμβάνουν διαφορετικό χώρο μέσα στον κοσμοχωρο.... πανω στον πλανητη τελοςπαντων lol Και κατι αλλο.... οι παραμετροι μιας συναρτησης που περνανε αποθηκεύονται στον σωρο ή στην στοιβα? σαν τοπικες μεταβλητες που μπορουν να χρησιμοποιηθουν και μεσα στην συνάρτηση δεν αποθηκευονται κατα βαση στην στοιβα? Η στοιβα δεν ειναι ιδια με τον σωρο το ενα αυξανεται προς τα πανω το αλλο προς τα κατω κωστε οταν η μνημη τελειώσει να συναντιούνται. Επεξ/σία 13 Οκτωβρίου 2012 από Star_Light
imitheos Δημοσ. 13 Οκτωβρίου 2012 Δημοσ. 13 Οκτωβρίου 2012 Ναι οκ . Τα 2 p ειναι διαφορετικα γιατι ο p μεσα στην συνάρτηση ειναι αντιγραφο του p της main οπως ακριβως συμβαινει και με τις μεταβλητες επειδη ακριβως η C ειναι αυστηρα pass by value οπως ειπε και ο παπι το by reference ειναι προσομοιωση μεσω δεικτων. Ναι, αν και το "ο p είναι αντίγραφο" μπορεί να μπερδέψει κάποιον και να το εκλάβει ως το νόημα του "by reference". Λίγο πιο ξεκάθαρα μπορούμε να πούμε ότι αντιγράφεται η τιμή του p, το περιεχόμενο του p, κτλ. Για την ακρίβεια το πρότυπο δεν αναφέρει πουθενά τις φράσεις "by value" και "by reference". Απλά επειδή η συμπεριφορά είναι σαν αυτή που περιγράφουν οι δύο αυτές έννοιες και επειδή αυτές αναφέρονται παντού και λίγο-πολύ είναι γνωστές ως έννοιες, χρησιμοποιείται παντού "by value" και "by reference". Και κατι αλλο.... οι παραμετροι μιας συναρτησης που περνανε αποθηκεύονται στον σωρο ή στην στοιβα? σαν τοπικες μεταβλητες που μπορουν να χρησιμοποιηθουν και μεσα στην συνάρτηση δεν αποθηκευονται κατα βαση στην στοιβα? Η στοιβα δεν ειναι ιδια με τον σωρο το ενα αυξανεται προς τα πανω το αλλο προς τα κατω κωστε οταν η μνημη τελειώσει να συναντιούνται. Η διαφορά της στοίβας με το σωρό εκτός ότι φαίνεται από την ετυμολογία των ίδιων των λέξεων, μπορείς να βρεις άπειρες πληροφορίες που εξηγούν τις δύο έννοιες. Όσον αφορά το προς τα που μεγαλώνει, εξαρτάται από την πλατφόρμα και δεν είναι παντού το ίδιο.
Star_Light Δημοσ. 13 Οκτωβρίου 2012 Δημοσ. 13 Οκτωβρίου 2012 (επεξεργασμένο) Ακυρο αυτο που εγραψα για τους δεικτες (σβήστηκε) μλκια ηταν..... απλα με μπέρδεψε η ξενη ορολογια. Δεν υπάρχει λάθος στο βιβλιο φυσικα. Sorry guys. To indirection ειναι έμμεση αναφορα . http://www.programmerinterview.com/index.php/data-structures/difference-between-stack-and-heap/ Επεξ/σία 13 Οκτωβρίου 2012 από Star_Light
Star_Light Δημοσ. 14 Οκτωβρίου 2012 Δημοσ. 14 Οκτωβρίου 2012 Μου άρεσε αυτή η υλοποίηση (αν και χρειάζεται έναν έλεγχο ακόμα, για την περίπτωση που του περαστεί πίνακας με 1 μόνο στοιχείο) Ναι. Στην main. > printf(" Give elements : "); for(i=0; i<n; i++) scanf("%d" , &b[i]); if ( i == 1 ) { biggest = b[0]; printf(" here is only one element : %d " , biggest); exit(EXIT_SUCCESS); } Kαι παλι δεν ειναι σωστή ομως η υλοποιηση με χρηση της scanf επειδη δεν μπορει το προγραμμα να ελένξει αν ο χρηστης έδωσε 4 στοιχεια αλλα πληκτρολογησε 5. > kostas@kostas-SSL:~/PROGRAMS$ ./tests3 How many elements? 1 Give elements : 4 5 6 The unique largest element is : 4 Αρα θα πρεπει να χρησιμοποιηθει το κολπο με την fgets και μετα μετατροπή σε ακεραιο οπως εχουμε ξανασυζητησει.
migf1 Δημοσ. 14 Οκτωβρίου 2012 Δημοσ. 14 Οκτωβρίου 2012 Το input validation δεν πρέπει να είναι δουλειά της συνάρτησης που υπολογίζει τα large1 και large2. Οπότε αυτό που λες πρέπει να γίνει πριν την κλήση της συνάρτησης. Η συνάρτηση απλώς πρέπει να κάνει sanity check του n που θα της περαστεί, μονάχα δηλαδή για το κομμάτι που την αφορά. ΥΓ. Btw, και με την scanf() μπορείς να δεις πόσες τιμές διαβάστηκαν, ελέγχεις την τιμή επιστροφής της. Δεν είναι δηλαδή απαραίτητη η fgets() για το input validation.
Star_Light Δημοσ. 14 Οκτωβρίου 2012 Δημοσ. 14 Οκτωβρίου 2012 Συμφωνω. Πριν την κλήση της συνάρτησης το κάνω και εγω. http://ideone.com/7V72f
moukoublen Δημοσ. 14 Οκτωβρίου 2012 Δημοσ. 14 Οκτωβρίου 2012 Εχω συνδέσει το οτι τα arguments μιας συνάρτησης που περνάνε στην C by value και ουσιαστικα ειναι αντίγραφα με την διευθυνση μνήμης. Πχ ενα αντιγραφο έχει ιδια τιμή αλλα διαφορετικη θεση μνημης. Γενικά μπόρεσα να λύσω σε μένα το μπέρδεμα με τους pointer οργανώνοντας τις εξής σκέψεις (τις παραθέτω να υπάρχουν): 1) Στην C (και στην C++ με εξαίρεση το reference που είναι ένα άλλο ντύσιμο του pointer) ΚΑΘΕ (μα κάθε, μα κάθε x 1000^1000) παράμετρος (απλός τύπος ή struct) στο όρισμα και στην επιστροφή μιας συνάρτησης αντιγράφεται (σε ένα άλλο δοχείο - μεταβλητή - δομή ίδιου τύπου). 2) Ο pointer είναι μια απλή μεταβλητή - ένας απλός τύπος. Ο pointer είναι ένας απλός integer (δεν είναι, αλλά και είναι). Απλά η γλώσσα σε αφήνει το περιεχόμενό του να το χρησιμοποιήσεις σα διεύθυνση μνήμης και να έχεις πρόσβαση στη μνήμη μέσω αυτού. Ο ίδιος δηλαδή δεν είναι τίποτα παραπάνω από έναν integer. Η "γλώσσα" σε αφήνει να τον χρησιμοποιήσεις σαν εισιτήριο στη μνήμη. Ο προορισμός είναι το περιεχόμενο του - τα data του και ο "χειρισμός" που μπορεί να γίνει σε αυτό τον προορισμό καθορίζεται από την "υπογραφή" του pointer (μπορεί δηλαδή ο προορισμός να είναι μια struct ένας απλό τύπος ή ένας άλλος pointer). 3) Έτσι κάθε pointer - μιας και είναι απλός τύπος - "μπαίνοντας" σε μια συνάρτηση ή "βγαίνοντας" από αυτή, αντιγράφεται. Το ότι τα δεδομένα που "δείχνει" είναι ίδια μέσα και έξω από τη συνάρτηση είναι γιατί τα data που αντιγράφονται, είναι διεύθυνση μνήμης. Αλλά αυτό είναι κάτι αυτόνομο και συμβαίνει γιατί ο μηχανισμός της γλώσσας σου επιτρέπει να παίξεις εύκολα με αυτά και να έχεις πρόσβαση όπου είναι να έχεις πρόσβαση. 1
Star_Light Δημοσ. 14 Οκτωβρίου 2012 Δημοσ. 14 Οκτωβρίου 2012 Ωστοσο δεν έχει νοημα τα δεδομένα να παραμείνουν τα ιδια και μεσα και εξω απο την συνάρτηση. Αλλιως δεν περνας καν δεικτες σε αυτην. Οποτε ιδια αν χρησιμοποιήσεις τον (*) σε μια εντολη εκχώρησης μεσα στην συνάρτηση δεν θα μεινουν. Επειδη το * ειναι ενα ψευδωνυμο για την μεταβλητη που δειχνει ο δεικτης οπως πολυ ωραια λεει και ο King στο βιβλιο του.
migf1 Δημοσ. 14 Οκτωβρίου 2012 Δημοσ. 14 Οκτωβρίου 2012 Συμφωνω. Πριν την κλήση της συνάρτησης το κάνω και εγω. http://ideone.com/7V72f Κάνεις διπλοδουλειά στο validation... > #include <stdio.h> #include <stdlib.h> void find_two_largest(int *arr, int n, int *l1, int *l2 ); /* --------------------------------------------- */ int main( void ) { int *arr = NULL; int n, biggest, s_biggest; // demand valid n do { printf("How many elements ( > 1)? "); fflush(stdout); scanf("%d" , &n); } while ( n < 2 ); // alloc array of n int's arr = malloc( n * sizeof(int) ); if ( !arr ) { puts( "*** fatal error: possible memory shortage, abotring..." ); exit(1); } // read arr elems for (int i=0; i < n; i++) { printf( "Elem #%d: ", i+1 ); fflush( stdout ); scanf( "%d" , &arr[i] ); } find_two_largest( arr, n, &biggest, &s_biggest ); printf("The first biggest element is : %d The second biggest element is : %d", biggest, s_biggest ); free( arr ); exit(0); } Ωστοσο δεν έχει νοημα τα δεδομένα να παραμείνουν τα ιδια και μεσα και εξω απο την συνάρτηση. Αλλιως δεν περνας καν δεικτες σε αυτην. Οποτε ιδια αν χρησιμοποιήσεις τον (*) σε μια εντολη εκχώρησης μεσα στην συνάρτηση δεν θα μεινουν. Επειδη το * ειναι ενα ψευδωνυμο για την μεταβλητη που δειχνει ο δεικτης οπως πολυ ωραια λεει και ο King στο βιβλιο του. Δεν κατάλαβα τίποτα!
Προτεινόμενες αναρτήσεις