aytias69 Δημοσ. 11 Απριλίου 2010 Δημοσ. 11 Απριλίου 2010 Θέλω να ανταλλάξω στοιχεία μεταξύ 2 δισδιάστατων πινάκων μέσω pointers σε πρόγραμμα C. Μπορώ να εναλλάξω τον αρχικό δείκτη ή πρέπει να εναλλάξω και τους ένθετους? Και πώς γίνεται αυτό?
bujar Δημοσ. 11 Απριλίου 2010 Δημοσ. 11 Απριλίου 2010 οπως βλεπεις και στο σχημα σου ο αρχικος δεικτης(το ονομα του πινακα) ειναι απλα ενας δεικτης στο πρωτο στοιχειο του πινακα, οποτε αν αλλαξεις αυτο, απλα θα αλλαξεις την πρωτη τιμη του πινακα σου, ομως ολος ο υπολοιπος πινακας θα ειναι ιδιος με πριν. ο μονος τροπος για να ανταλλαξεις τα στοιχεια αναμεσα σε δυο πινακες ειναι να αλλαξεις τα στοιχεια ενα ενα.
C6WGMN Δημοσ. 11 Απριλίου 2010 Δημοσ. 11 Απριλίου 2010 οπως βλεπεις και στο σχημα σου ο αρχικος δεικτης(το ονομα του πινακα) ειναι απλα ενας δεικτης στο πρωτο στοιχειο του πινακα, οποτε αν αλλαξεις αυτο, απλα θα αλλαξεις την πρωτη τιμη του πινακα σου, ομως ολος ο υπολοιπος πινακας θα ειναι ιδιος με πριν. ο μονος τροπος για να ανταλλαξεις τα στοιχεια αναμεσα σε δυο πινακες ειναι να αλλαξεις τα στοιχεια ενα ενα. Η να αλλάξει τους pointers (αν αυτό βολεύει). > int **m; int *p; p = m[2] m[2] = m[3]; m[3] = p;
aytias69 Δημοσ. 11 Απριλίου 2010 Μέλος Δημοσ. 11 Απριλίου 2010 Μάλλον δεν έθεσα σωστά το ερώτημα. Έστω ότι δημιουργώ 2 πίνακες s1 και s2 με διαστάσεις N x M. Όπως φαίνεται και από το παραπάνω σχήμα, δημιουργείται για κάθε πίνακα ένας δείκτης που δείχνει στην αρχή ενός πίνακα δεικτών. Εγώ αυτό που θέλω είναι να εναλλάξω τους αρχικούς δείκτες ώστε ο s1 να δείχνει στη διεύθυνση που αρχίζει ο s2 και ο s2 στη διεύθυνση που αρχίζει ο s1, ή τουλάχιστον να εναλλάξω τους ένθετους δείκτες, αν δε γίνεται το πρώτο. Δλδ με βάση τον παρακάτω κώδικα >int s1[N][M], s2[N][M], *temp[N]; //Τρόπος 1 temp=s1; s1=s2; s2=temp; //Τρόπος 2 for(i=0;i<N;i++) *(temp+i)=*(s1+i); for(i=0;i<N;i++) *(s1+i)=*(s2+i); for(i=0;i<N;i++) *(s2+i)=*(temp+i); γιατί δε δουλεύει κανένας από τους 2 τρόπους και πώς διορθώνεται? PS. Προσπαθώ να αποφύγω τη λύση της ανταλλαγής όλων των στοιχείων.
virxen75 Δημοσ. 11 Απριλίου 2010 Δημοσ. 11 Απριλίου 2010 δες το παράδειγμα που έφτιαξα πιο κάτω με βάση τα παραπάνω. Δεν ξέρω αν είναι αυτό που ζητάς. Δες το και πες μου. > #include <stdio.h> #include <stdlib.h> #define M 10 #define N 5 void print(int *[M]); void print(int *s[M]){ for (int i=0;i<N;i++){ for (int j=0;j<M;j++){ printf(" %d ",s[i][j]); } printf("\n"); } } int main(){ int ** s1,**s2,**temp; //s1 s1=(int **) malloc(N*sizeof(int*)); for (int i=0;i<N;i++) s1[i]=(int *) malloc(M*sizeof(int)); //s2 s2=(int **) malloc(N*sizeof(int*)); for (int i=0;i<N;i++) s2[i]=(int *) malloc(M*sizeof(int)); //temp temp=(int **) malloc(N*sizeof(int*)); for (int i=0;i<N;i++) temp[i]=(int *) malloc(M*sizeof(int)); //vale times for (int i=0;i<N;i++) for (int j=0;j<M;j++){ s1[i][j]=1; s2[i][j]=2; temp[i][j]=0; } //print s1 printf("\narray s1\n"); print(s1); //print s2 printf("\narray s2\n"); print(s2); //change values temp=s1; s1=s2; s2=temp; printf("changed values now are"); //print s1 printf("\narray s1\n"); print(s1); //print s2 printf("\narray s2\n"); print(s2); getchar(); return 0; }
aytias69 Δημοσ. 11 Απριλίου 2010 Μέλος Δημοσ. 11 Απριλίου 2010 Ok thanks. Κατάλαβα τι γίνεται και μου κάνει για την άσκηση που θέλω. Οπότε για να κάνεις εναλλαγή δεικτών πρέπει πρώτα να έχεις δεσμεύσει ρητά μνήμη. Αυτό που δεν κατάλαβα είναι γιατί το >int s1[N][M]; δεν είναι το ίδιο με το >s1=(int **) malloc(N*sizeof(int*)); for (int i=0;i<M;i++) s1[i]=(int *) malloc(M*sizeof(int)); Που είναι η διαφορά τους?
ARIANAROS Δημοσ. 11 Απριλίου 2010 Δημοσ. 11 Απριλίου 2010 Η διαφορά τους είναι στο ότι η πρώτη δήλωση ΔΕΝ μπορεί να υπάρξει , γιατί αυτό που κάνεις είναι δυναμική δήλωση των μεταβλητών , άρα μπορεί να γίνει με malloc ή calloc . Αλλιώς δεν μπορείς να χρησιμοποιήσεις μεταβλητές για να δεσμεύσεις χώρο ( έχει να κάνει με το compile time και run time ) .
C6WGMN Δημοσ. 11 Απριλίου 2010 Δημοσ. 11 Απριλίου 2010 Η διαφορά τους είναι στο ότι η πρώτη δήλωση ΔΕΝ μπορεί να υπάρξει , γιατί αυτό που κάνεις είναι δυναμική δήλωση των μεταβλητών , άρα μπορεί να γίνει με malloc ή calloc . Αλλιώς δεν μπορείς να χρησιμοποιήσεις μεταβλητές για να δεσμεύσεις χώρο ( έχει να κάνει με το compile time και run time ) . Μπορεί να είναι macros τα N και Μ. > #define N 100 #define M 50 αλλά ακόμα και αν ήταν μεταβλητές ο κώδικας είναι μια χαρά, σε compiler που υποστιρίζει c99. http://en.wikipedia.org/wiki/Variable-length_array
epersidi Δημοσ. 11 Απριλίου 2010 Δημοσ. 11 Απριλίου 2010 >int s1[N][M]; Δηλώνουμε έναν δισδιάστατο πίνακα ακεραίων δηλαδή ο πίνακας περιέχει ΑΚΕΡΑΙΟΥΣ. > int ** s1,**s2,**temp; s1=(int **) malloc(N*sizeof(int*)); for (int i=0;i<M;i++) s1[i]=(int *) malloc(M*sizeof(int)); Στην πρώτη γραμμή δηλώνουμε δείκτες προς δείκτες ακεραίων (**int) δηλαδή το περιεχόμενο π.χ. του s1 είναι η διεύθυνση ενός δείκτη τύπου ακέραιου (*int). Προς το παρών βέβαια ΔΕΝ υπάρχει περιεχόμενο, δηλαδή ο δείκτης δεν δείχνει πουθενά. Στην δεύτερη γραμμή δεσμεύουμε χώρο για N δείκτες ακεραίων και βάζουμε το s1 να δείχνει στο πρώτο στοιχείο του πίνακα (όπως φαίνεται και στο σχήμα σου). Το for που έδωσε ο φίλος virxen75 είναι λάθος φυσικά (λόγω βιασύνης φαντάζομαι) αφού το i πρέπει να φτάνει μέχρι το Ν (όσα τα στοιχεία του πίνακα που δεσμεύσαμε αμέσως πριν). Μέσα στο for δεσμεύουμε χώρο για M ακέραιους (ΠΡΟΣΟΧΗ πλέον μιλάμε για ακέραιους και όχι για δείκτες ακεραίων όπως πριν) κάθε φορά (για κάθε στήλη δηλαδή) και βάζουμε τον δείκτη s1 να δείχνει στο πρώτο στοιχείο του πίνακα που μόλις δεσμεύσαμε. Ελπίζω να κατάλαβες τη διαφορά που έχουν οι 2 εκδοχές. Μιλάμε για εντελώς διαφορετικά πράγματα. Το μόνο κοινό τους στοιχείο είναι ο τρόπος πρόσβασης στα δεδομένα αφού και στην δεύτερη περίπτωση αρκεί να γράψεις π.χ. s1[2][3] για να "διαβάσεις" το στοιχείο που βρίσκεται στη 3η σειρά στην 4η στήλη όπως ακριβώς θα έκανες και στην πρώτη.
aytias69 Δημοσ. 11 Απριλίου 2010 Μέλος Δημοσ. 11 Απριλίου 2010 Η δεύτερη δήλωση έχω καταλάβει τι κάνει. Αυτό που δεν έχω καταλάβει είναι τι γίνεται στην πρώτη δήλωση. Αφού δεν κρατάει έναν δείκτη προς έναν πίνακα δεικτών, όπου ο καθένας τους δείχνει σε έναν πίνακα ακεραίων, τι κάνει? Δλδ τι δεσμεύει κατά την αρχικοποίηση? PS. Όντως η for πρέπει να είναι έως N.
parsifal Δημοσ. 11 Απριλίου 2010 Δημοσ. 11 Απριλίου 2010 >int s1[N][M], s2[N][M], *temp[N]; //Τρόπος 1 temp=s1; s1=s2; s2=temp; //Τρόπος 2 for(i=0;i<N;i++) *(temp+i)=*(s1+i); for(i=0;i<N;i++) *(s1+i)=*(s2+i); for(i=0;i<N;i++) *(s2+i)=*(temp+i); γιατί δε δουλεύει κανένας από τους 2 τρόπους και πώς διορθώνεται? Παραθέτω από παλαιότερο μήνυμά μου: Υπάρχει μία παγίδα στο να σκέπτεται ο προγραμματιστής γενικώς κάθε array ως pointer και αυτό μάλλον είχε στο μυαλό του ο bokarinho. 1. Έστω στατικός πίνακας int και ένας int pointer: > int array[2]; int *p; Μπορεί ως έκφραση, το array σκέτο να αποτιμάται στη διεύθυνση μνήμης του πρώτου στοιχείου του πίνακά μας, αλλά το array καθεαυτό δεν είναι modifiable object. Π.χ. αυτό δεν επιτρέπεται: > array = p; Νομίζω στη βιβλιογραφία, η έκφραση array εδώ αναφέρεται ως "unmodifiable lvalue", κι έτσι είναι στην πράξη. Λειτουργεί ως constant. ... Αν τώρα είσαι διατεθειμένος να δουλέψεις αποκλειστικά με δυναμικά δεσμευμένη μνήμη αντί για στατικά δηλωμένους πίνακες, τότε φυσικά και μπορείς μετά από ένα malloc να κάνεις τον δείκτη(-ες) σου να δείχνει αλλού, δεν απαγορεύεται κάτι τέτοιο. Προσοχή όμως στους dangling pointers και στα memory leaks!
aytias69 Δημοσ. 12 Απριλίου 2010 Μέλος Δημοσ. 12 Απριλίου 2010 Δλδ από ό,τι κατάλαβα οι δείκτες που δημιουργούνται όταν φτιάχνεις έναν πίνακα είναι στατικοί και δεν μπορείς να τους βάλεις να δείχνουν αλλού. Γι αυτό και μου πέταγε errors στις αναθέσεις. Χίλια ευχαριστώ. Με έσωσες!
parsifal Δημοσ. 12 Απριλίου 2010 Δημοσ. 12 Απριλίου 2010 Δλδ από ό,τι κατάλαβα οι δείκτες που δημιουργούνται όταν φτιάχνεις έναν πίνακα είναι στατικοί Ωπ, υπάρχει σημειολογικό ενδιαφέρον εδώ! Και ίσως εξηγεί και το γιατί μπερδεύτηκες εξαρχής. Όταν δηλώνεις πίνακες στατικά, δε δημιουργούνται δείκτες. Το όνομα ενός πίνακα δεν είναι δείκτης, παρ' ό,τι σε μερικές περιπτώσεις φαίνεται να συμπεριφέρεται ως τέτοιος. Για περισσότερα, ρίξε μια ματιά εδώ: http://stackoverflow.com/questions/1641957/is-array-name-a-pointer-in-c
aytias69 Δημοσ. 12 Απριλίου 2010 Μέλος Δημοσ. 12 Απριλίου 2010 Ωπ, υπάρχει σημειολογικό ενδιαφέρον εδώ! Και ίσως εξηγεί και το γιατί μπερδεύτηκες εξαρχής. Όταν δηλώνεις πίνακες στατικά, δε δημιουργούνται δείκτες. Το όνομα ενός πίνακα δεν είναι δείκτης, παρ' ό,τι σε μερικές περιπτώσεις φαίνεται να συμπεριφέρεται ως τέτοιος. Για περισσότερα, ρίξε μια ματιά εδώ: http://stackoverflow.com/questions/1641957/is-array-name-a-pointer-in-c Δλδ όταν δημιουργείς στατικό πίνακα, δε δημιουργείται αυτόματα δείκτης προς την αρχή του πίνακα. Για να το κάνεις αυτό, πρέπει να δημιουργήσεις δείκτη και και να του αναθέσεις το πρώτο στοιχείο του στατικού πίνακα. Σωστά?
parsifal Δημοσ. 12 Απριλίου 2010 Δημοσ. 12 Απριλίου 2010 Ναι, αν θέλεις μπορείς να δηλώσεις έναν pointer προς πίνακα ορισμένων διαστάσεων και να τον κάνεις να δείχνει σε κάποιον πίνακα με αυτές τις διαστάσεις. Δες π.χ. αυτό: > #include <stdio.h> int main(void) { int array[4][2] = {{11, 12}, {21, 22}, {31, 32}, {41, 42}}; int (*pointer)[4][2]; pointer = &array; printf("%d\n", array[3][1]); /* 42 */ printf("%d\n", (*pointer)[3][1]); /* 42 */ return 0; }
Προτεινόμενες αναρτήσεις
Αρχειοθετημένο
Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.