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

Δείκτες Δισδιάστατων Πινάκων στη C


aytias69

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

Δημοσ.

Θέλω να ανταλλάξω στοιχεία μεταξύ 2 δισδιάστατων πινάκων μέσω pointers σε πρόγραμμα C.

 

arraypointers.gif

 

Μπορώ να εναλλάξω τον αρχικό δείκτη ή πρέπει να εναλλάξω και τους ένθετους? Και πώς γίνεται αυτό?

Δημοσ.

οπως βλεπεις και στο σχημα σου ο αρχικος δεικτης(το ονομα του πινακα) ειναι απλα ενας δεικτης στο πρωτο στοιχειο του πινακα, οποτε αν αλλαξεις αυτο, απλα θα αλλαξεις την πρωτη τιμη του πινακα σου, ομως ολος ο υπολοιπος πινακας θα ειναι ιδιος με πριν. ο μονος τροπος για να ανταλλαξεις τα στοιχεια αναμεσα σε δυο πινακες ειναι να αλλαξεις τα στοιχεια ενα ενα.

Δημοσ.
οπως βλεπεις και στο σχημα σου ο αρχικος δεικτης(το ονομα του πινακα) ειναι απλα ενας δεικτης στο πρωτο στοιχειο του πινακα, οποτε αν αλλαξεις αυτο, απλα θα αλλαξεις την πρωτη τιμη του πινακα σου, ομως ολος ο υπολοιπος πινακας θα ειναι ιδιος με πριν. ο μονος τροπος για να ανταλλαξεις τα στοιχεια αναμεσα σε δυο πινακες ειναι να αλλαξεις τα στοιχεια ενα ενα.

 

Η να αλλάξει τους pointers (αν αυτό βολεύει).

>
int **m;
int *p;

p = m[2]
m[2] = m[3];
m[3] = p;

Δημοσ.

Μάλλον δεν έθεσα σωστά το ερώτημα. Έστω ότι δημιουργώ 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. Προσπαθώ να αποφύγω τη λύση της ανταλλαγής όλων των στοιχείων.

Δημοσ.

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

Δεν ξέρω αν είναι αυτό που ζητάς.

Δες το και πες μου.

 

>
#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;
}

Δημοσ.

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));

 

Που είναι η διαφορά τους?

Δημοσ.

Η διαφορά τους είναι στο ότι η πρώτη δήλωση ΔΕΝ μπορεί να υπάρξει , γιατί αυτό που κάνεις είναι δυναμική δήλωση των μεταβλητών , άρα μπορεί να γίνει με malloc ή calloc . Αλλιώς δεν μπορείς να χρησιμοποιήσεις μεταβλητές για να δεσμεύσεις χώρο ( έχει να κάνει με το compile time και run time ) .

Δημοσ.
Η διαφορά τους είναι στο ότι η πρώτη δήλωση ΔΕΝ μπορεί να υπάρξει , γιατί αυτό που κάνεις είναι δυναμική δήλωση των μεταβλητών , άρα μπορεί να γίνει με malloc ή calloc . Αλλιώς δεν μπορείς να χρησιμοποιήσεις μεταβλητές για να δεσμεύσεις χώρο ( έχει να κάνει με το compile time και run time ) .

 

Μπορεί να είναι macros τα N και Μ.

>
#define N 100
#define M 50

αλλά ακόμα και αν ήταν μεταβλητές ο κώδικας είναι μια χαρά, σε compiler που υποστιρίζει c99.

 

http://en.wikipedia.org/wiki/Variable-length_array

Δημοσ.

>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η στήλη όπως ακριβώς θα έκανες και στην πρώτη.

Δημοσ.

Η δεύτερη δήλωση έχω καταλάβει τι κάνει. Αυτό που δεν έχω καταλάβει είναι τι γίνεται στην πρώτη δήλωση. Αφού δεν κρατάει έναν δείκτη προς έναν πίνακα δεικτών, όπου ο καθένας τους δείχνει σε έναν πίνακα ακεραίων, τι κάνει? Δλδ τι δεσμεύει κατά την αρχικοποίηση?

 

PS. Όντως η for πρέπει να είναι έως N.

Δημοσ.
>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!

Δημοσ.

Δλδ από ό,τι κατάλαβα οι δείκτες που δημιουργούνται όταν φτιάχνεις έναν πίνακα είναι στατικοί και δεν μπορείς να τους βάλεις να δείχνουν αλλού. Γι αυτό και μου πέταγε errors στις αναθέσεις.

 

Χίλια ευχαριστώ. Με έσωσες!

Δημοσ.
Δλδ από ό,τι κατάλαβα οι δείκτες που δημιουργούνται όταν φτιάχνεις έναν πίνακα είναι στατικοί

 

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

 

Όταν δηλώνεις πίνακες στατικά, δε δημιουργούνται δείκτες. Το όνομα ενός πίνακα δεν είναι δείκτης, παρ' ό,τι σε μερικές περιπτώσεις φαίνεται να συμπεριφέρεται ως τέτοιος.

 

Για περισσότερα, ρίξε μια ματιά εδώ: http://stackoverflow.com/questions/1641957/is-array-name-a-pointer-in-c

Δημοσ.
Ωπ, υπάρχει σημειολογικό ενδιαφέρον εδώ! Και ίσως εξηγεί και το γιατί μπερδεύτηκες εξαρχής.

 

Όταν δηλώνεις πίνακες στατικά, δε δημιουργούνται δείκτες. Το όνομα ενός πίνακα δεν είναι δείκτης, παρ' ό,τι σε μερικές περιπτώσεις φαίνεται να συμπεριφέρεται ως τέτοιος.

 

Για περισσότερα, ρίξε μια ματιά εδώ: http://stackoverflow.com/questions/1641957/is-array-name-a-pointer-in-c

 

Δλδ όταν δημιουργείς στατικό πίνακα, δε δημιουργείται αυτόματα δείκτης προς την αρχή του πίνακα. Για να το κάνεις αυτό, πρέπει να δημιουργήσεις δείκτη και και να του αναθέσεις το πρώτο στοιχείο του στατικού πίνακα. Σωστά?

Δημοσ.

Ναι, αν θέλεις μπορείς να δηλώσεις έναν 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;
}

Αρχειοθετημένο

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

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