pioneer2 Δημοσ. 21 Νοεμβρίου 2011 Δημοσ. 21 Νοεμβρίου 2011 Έχω κάνει μια άσκηση δουλεύει μέχρι ενός σημείου και μετά κολλάει. Πρέπει να παίρνει τις τιμές από έναν μονοδιάστατο πίνακα και να τις βάζει σε έναν τετραγωνικό στη διαγώνιο, ή στο πάνω μέρος (κάτω τριγωνικός) η στο κάτω (άνω τριγωνικός). Οι πίνακες είναι δυναμικοί με τη χρήση της malloc. Στο προγ/μά μου με στατικο 2σδιαστατο πίνακα κάπως δούλεψε, όμως με δυναμικό με πετάει. Καποια βοήθεια ? Ευχαριστώ εκ των προτέρων > main() { int* a = NULL; int i, n; printf("Dwste to megethos tou pinaka int a [] pou thelete na diavastei\n"); scanf("%d", &n); printf("\nO pinakas twra einai a [%d]",n); a = (int*)malloc(n*sizeof(int)); for (i=0; i<n; i++) { a[i] = 0; } printf("\nDwste ena-ena ta stoixeia tou pinaka\n"); for(i=0;i<n;i++) scanf("%d", &a[i]); printf("\nO pinakas twra gemise me\n"); for(i=0;i<n;i++){ printf("%d ", a[i]); } int num; int j, nrows, ncols; int **ar = NULL; ar =(int**) malloc(nrows * sizeof(int *)); for(i = 0; i < nrows; i++){ ar[i] = (int*)malloc(ncols * sizeof(int)); printf("\nDwste epilogi opou tha antigrafoun ta stoixeia tou trigwnikou\n"); printf("1 gia symmetriko\n"); printf("2 gia anw trigwniko\n"); printf("3 gia katw trigwniko\n"); scanf("%d\n",&num); for (i =0;i<nrows; i++ ){ for(j=0;j<ncols;j++) { if (num == 1){ if (i==j) ar[i][j]=a[i]; } if (num == 2){ if (i<j) ar[i][j]=a[i]; } if(num == 3){ if(i>j) ar[i][j]=a[i]; } } } for (i =0;i<ncols; i++ ) for(j=0;j<nrows;j++) printf("%d%d\n", ar[i][j]); } }
bnvdarklord Δημοσ. 21 Νοεμβρίου 2011 Δημοσ. 21 Νοεμβρίου 2011 Αρχικά δεν εχεις δώσει τιμές στα ncols και nrows, οπότε πας να κάνεις allocate στην μνήμη με άκυρο μέγεθος. Δεύτερον η επιλογή του είδους πίνακα θα πρέπει να γίνει εκτός του for που την έχεις βάλει γιατί έτσι θα εκτελείται συνέχεια και όχι μια φορα που θες να επιλέξεις. Τέλος, το allocate του δυσδιάστατου πίνακα θα πρεπει να γίνει ξεχωριστά δηλαδή έτσι: > int **ar = NULL; ar = (int **) malloc(nrows * sizeof(int *)); for (i = 0; i < nrows; i++) { ar[i] = (int *) malloc(ncols * sizeof(int)); } και μετά να κάνεις οτιδήποτε με αυτόν. Θα πρεπει φυσικά να τον αρχικοποιήσεις με κάποια τιμή(0). Οπως το χεις κάνει εσύ, πας να επεξεργαστείς στοιχεία που δεν έχεις κάνει allocate ακόμα, με αποτέλεσμα να κρασάρει. Επισης για την εκτύπωση του δώσε αυτό για πιο ευδιάκριτα αποτελέσματα. > for (i = 0; i < ncols; i++) { for (j = 0; j < nrows; j++) { printf("%d , ", ar[i][j]); } printf("\n"); }
pioneer2 Δημοσ. 21 Νοεμβρίου 2011 Μέλος Δημοσ. 21 Νοεμβρίου 2011 Eυχαριστώ για την απάντηση αλλά τι εννοείς η επιλογή του πίνακα να γίνει έξω από την for ? Δε πρέπει όταν σκανάρει τον δισδιάστατο να κάνει τα if - else ? Διαφορετικά "έξω" απ'τη διπλή for πώς θα διασχίζει τα στοιχεία για να κάνει την επιλογή (κάτω , άνω τριγςωνικος κτλ)
bnvdarklord Δημοσ. 21 Νοεμβρίου 2011 Δημοσ. 21 Νοεμβρίου 2011 Εννοώ αυτό το κομμάτι: > printf("\nDwste epilogi opou tha antigrafoun ta stoixeia tou trigwnikou\n"); printf("1 gia symmetriko\n"); printf("2 gia anw trigwniko\n"); printf("3 gia katw trigwniko\n"); scanf("%d", &num);
pioneer2 Δημοσ. 22 Νοεμβρίου 2011 Μέλος Δημοσ. 22 Νοεμβρίου 2011 Δεν το κατάφερα αυτό με τις if-else, μπερδέυτηκα περισσότερο, μπορεί κάποιος να συμπήρώσει τονν κώδικα ?
migf1 Δημοσ. 22 Νοεμβρίου 2011 Δημοσ. 22 Νοεμβρίου 2011 Δεν το κατάφερα αυτό με τις if-else, μπερδέυτηκα περισσότερο, μπορεί κάποιος να συμπήρώσει τονν κώδικα ? Έχεις κάποιες ανακρίβειες... π.χ. στην αρχή λες πως ο μονοδιάστατος θέλεις να αντιγραφεί στην διαγώνιο του 2διάστατου, αλλά μέσα στο πρόγραμμα αντί για διαγώνιο, γράφεις συμμετρικό (που είναι άλλο πράγμα). Τέσπα, η άσκηση αυτή μεταξύ άλλων θέλει συναρτήσεις, γιατί καταντάει μακρινάρι σε μια main... κάνε το εσύ. Σου παραθέτω κώδικα που λύνει το μέρος με τη διαγώνιο (συμμετρικό, άνω και κάτω τριγωνικό φτιάξε τα εσύ). Στον κώδικα θεωρώ πως η απάντηση του χρήστη στο μενού καθορίζει και το μέγεθος στο οποίο θα δημιουργηθεί ο 2Δ πίνακας, μιας και π.χ. το για απλό γέμισμα διαγωνίου χρειάζεται 2Δ πίνακα διαφορετικού μεγέθους από ότι αν αντί για απλή διαγώνιο τον θες συμμετρικό (όπως γράφεις στον κώδικά σου) ή ακόμα κι άνω/κάτω τριγωνικό. Τελειώνοντας, προσπάθησε να γράφεις ευανάγνωστο κώδικα, με σωστή στοίχιση, διαχωριστικά κενά διαστήματα, ονόματα μεταβλητών που βγάζουν νόημα, κλπ... όσο πιο δυσανάγνωστος είναι ο κώδικας που παραθέτεις τόσο λιγότερες πιθανότητες έχεις να ασχοληθεί μαζί του σοβαρός/έμπειρος άνθρωπος! Και να γράφεις σχόλια μέσα στον κώδικα, ειδικά όταν ποστάρεις για βοήθεια > #include <stdio.h> #include <stdlib.h> int main( void ) { int *arr = NULL, narr = 0; /* 1D πίνακας & πλήθος στοιχείων */ int menusel = -1; /* επιλογή μενού */ int **arr2d = NULL, nrows=0, ncols=0; /* 2D πίνακας, πλήθος γραμμών & στηλών */ register int i, j; printf("Megethos Monodiastatoy Pinaka: "); scanf("%d", &narr); /* δημιουργία μονοδιάστατου πίνακα, narr θέσεων */ arr = calloc( narr, sizeof(int) ); /* δημιουργία & μηδενισμός στοιχείων */ if ( arr == NULL ) { /* αποτυχία δημιουργίας */ puts("*** fatal error: out of memory, aborting..."); return 1; } printf("\to pinakas arr[%d] dhmioyrghthike epityxws\n\n", narr); /* συμπλήρωμα στοιχείων από τον χρήστη στον μονοδιάστατου πίνακα */ puts("Stoixeia Pinaka (ena-ena)..."); for (i=0; i < narr; i++) { printf("thesh %d: ", i); scanf("%d", &arr[i] ); } /* τυπωμένη επιβεβαίωση συμπληρωμένων στοιχείων */ printf("\tsymplhrwthikan: "); for (i=0; i < narr; i++) printf("%d ", arr[i] ); puts("\n"); /* εμφάνιση μενού */ puts("\nMetatroph Monodiastatoy se..."); puts("0 : diagwnio 2diastatoy"); puts("1 : symmetriko 2diastato"); puts("2 : anw trigwniko 2diastato"); puts("3 : katw trigwniko 2diastato"); printf("> "); /* ανάγνωση επιλογής & ανάλογη αρχικοποίηση των nrows, ncols */ scanf( "%d", &menusel ); switch ( menusel ) { case 0: /* στη διαγώνιο */ nrows = ncols = narr; break; case 1: /* συμμετρικός */ nrows /* = ?? */; /* βάλε τιμή */ ncols /* = ?? */; /* βάλε τιμή */ break; case 2: /* άνω τριγωνικός */ nrows /* = ?? */; /* βάλε τιμή */ ncols /* = ?? */; /* βάλε τιμή */ break; case 3: /* κάτω τριγωνικός */ nrows /* = ?? */; /* βάλε τιμή */ ncols /* = ?? */; /* βάλε τιμή */ break; default: /* διαχειρίσου εδώ άκυρες επιλογές στο μενού (π.χ. 10) */ break; } /* δημιουργία 2-διάστατου πίνακα */ /* αρχικά δημιουργούμε nrows γραμμές από δείκτες σε int */ arr2d = (int **) calloc( nrows, sizeof(int *) ); if (arr2d == NULL ) { /* αποτυχία δημιουργίας */ puts("fatal error: out of memory, aborting..."); free( arr ); /* απελευθέρωση μνήμης του 1D πίνακα */ return 1; } /* κατόπιν σε κάθε δημιουργημένη γραμμή, δημιουργούμε 1D πίνακες ncols θέσεων */ for (i = 0; i < nrows; i++) { /* δημιουργία 1D πίνακα ncols θέσεων στην i-οστή γραμμή του arr2d */ arr2d[ i ] = (int *) calloc( ncols, sizeof(int) ); if ( arr2d[ i ] == NULL ) /* αποτυχία δημιουργίας πίνακα στη γραμμή i*/ { for (j=i-1; j > -1; j--)/* απελευθέρωση προηγούμενων έως γραμμή 0 */ free( arr2d[ j ] ); free( arr2d ); /* απελευθέρωση του 2D πινακα */ free( arr ); /* απελευθέρωση του αρχικού μονοδιάστατου */ puts("*** fatal error: out of memory, aborting..."); return 1; } } /* * Σε αυτό το σημείο έχουμε 2 πίνακες, έναν 1D (arr) κι έναν 2D (arr2d) * με τις γραμμές (nrows) και τις στήλες (ncols) του arr2d να τις έχουμε * καθοριστεί βάση της επιλογής που έκανε ο χρήστης στο μενού. */ /* γέμισμα του arr2d από τον arr, βάση της επιλογής του χρήστη */ switch ( menusel ) { case 0: /* στην διαγώνιο */ /* Σημείωση: λόγω της calloc() ο arr2d έχει ήδη μηδενισμένα όλα τα στοιχεία του, άρα θα ασχοληθούμε μονάχα με την διαγώνιο */ for (i=0; i < nrows; i++) arr2d[i][i] = arr[i]; break; case 1: puts("syntoma (symmetrikos)"); break; case 2: puts("syntoma (anw trigwnikos)"); break; case 3: puts("syntoma (katw trigwnikos)"); break; default: /* silently continue (do nothing) */ break; } /* τύπωμα των στοιχείων του arr2d */ puts("\nEkypwsh 2diastatoy Pinaka\n-------------------------"); for (i=0; i < nrows; i++) { for (j=0; j < ncols; j++) printf("%5d ", arr2d[i][j] ); putchar('\n'); } puts("\n"); /* !!! ΑΠΕΛΕΥΘΕΡΩΣΗ ΤΗΣ ΔΕΣΜΕΥΜΕΝΗΣ ΜΝΗΜΗΣ !!! */ /* απελευθέρωση των γραμμών του arr2d */ for (i=0; i < nrows; i++) if ( arr2d[i] != NULL ) free( arr2d[i] ); /* απελευθέρωση του arr2d */ if ( arr2d != NULL ) free( arr2d ); /* απελευθέρωση του arr */ if ( arr != NULL ) free( arr ); return 0; } /*** ΑΠΕΝΕΡΓΟΠΟΙΗΜΕΝΟΣ ΑΥΘΕΝΤΙΚΟΣ ΚΩΔΙΚΑΣ main() { int* a = NULL; int i, n; printf("Dwste to megethos tou pinaka int a [] pou thelete na diavastei\n"); scanf("%d", &n); printf("\nO pinakas twra einai a [%d]",n); a = (int*)malloc(n*sizeof(int)); for (i=0; i<n; i++) { a[i] = 0; } printf("\nDwste ena-ena ta stoixeia tou pinaka\n"); for(i=0;i<n;i++) scanf("%d", &a[i]); printf("\nO pinakas twra gemise me\n"); for(i=0;i<n;i++){ printf("%d ", a[i]); } int num; int j, nrows, ncols; int **ar = NULL; ar =(int**) malloc(nrows * sizeof(int *)); for(i = 0; i < nrows; i++){ ar[i] = (int*)malloc(ncols * sizeof(int)); printf("\nDwste epilogi opou tha antigrafoun ta stoixeia tou trigwnikou\n"); printf("1 gia symmetriko\n"); printf("2 gia anw trigwniko\n"); printf("3 gia katw trigwniko\n"); scanf("%d\n",&num); for (i =0;i<nrows; i++ ){ for(j=0;j<ncols;j++) { if (num == 1){ if (i==j) ar[i][j]=a[i]; } if (num == 2){ if (i<j) ar[i][j]=a[i]; } if(num == 3){ if(i>j) ar[i][j]=a[i]; } } } for (i =0;i<ncols; i++ ) for(j=0;j<nrows;j++) printf("%d%d\n", ar[i][j]); } } ***/ Έχω συμπεριλάβει πολλά σχόλια, τα οποία αναλύουν σχεδόν γραμμή προς γραμμή το τι γίνεται.
pioneer2 Δημοσ. 22 Νοεμβρίου 2011 Μέλος Δημοσ. 22 Νοεμβρίου 2011 Σε ευχαριστώ πάρα πολύ για το χρόνο σου, ο κώδικας είναι με αλφάδι πραγματικά . Δυστυχώς στο τει μας βάζουν να γράφουμε κώδικα στο χαρτί , εξ'ου και o κώδικας spaghetti που παρουσίασα.
bnvdarklord Δημοσ. 22 Νοεμβρίου 2011 Δημοσ. 22 Νοεμβρίου 2011 @migf1 εχει νοημα το free αμέσως πριν τελειώσει το πρόγραμμα;
migf1 Δημοσ. 23 Νοεμβρίου 2011 Δημοσ. 23 Νοεμβρίου 2011 @migf1 εχει νοημα το free αμέσως πριν τελειώσει το πρόγραμμα; Εξαρτάται από την πλατφόρμα, το λειτουργικό, τον compiler ακόμα και το actual ή το potential scope του προγράμματός σου. Θεωρητικά, στη συντριπτική πλειοψηφία των δημοφιλών λειτουργικών δεν χρειάζεται καν να κάνεις free, όχι μόνο πριν τον τερματισμό του προγράμματος, αλλά οπουδήποτε., διότι το λειτουργικό απελευθερώνει όλα τα resources του process σου (memory included). Αλλά π.χ. τι συμβαίνει αν η process σου (το πρόγραμμά σου δηλαδή) κάνει spawn ένα child process, το οποίο child δεσμεύει μνήμη την οποία δεν απελευθερώνει όταν επιστρέφει τον έλεγχο στην parent process? Και πάλι εξαρτάται από το λειτουργικό, αλλά μπορεί και να σημαίνει πως η parent process θα "κουβαλάει" την άχρηστη αλλά μαρκαρισμένη ως δεσμευμένη μνήμη μέχρι να τερματίσει η ίδια... (το ανάποδο δηλαδή από το "αμαρτίες γονέων παιδεύουσι τέκνα" ) Επίσης, αν μελλοντικά θελήσεις να χρησιμοποιήσεις σε ένα νέο μεγαλύτερο project κώδικα που έχεις γράψει παλιότερα και στον παλιό κώδικα δεν είχες φροντίσει να απελευθερώνεις τη μνήμη που δέσμευες, είναι έως και 100% σίγουρα πως το νέο project θα υποφέρει από memory leaks. Υπάρχουν βέβαια και περιπτώσεις που συνειδητά δεν κάνεις free(), όπως για παράδειγμα όταν γράφεις shared-libraries (αν κι εκεί είναι προτιμητέο να διαχειρίζονται αυτά σε ένα μόνο module). Άλλη περίπτωση που μπορείς να μη κάνεις συνειδητά free() είναι π.χ. αν το πρόγραμμά σου προορίζεται να τρέξει τελευταίο πριν από shutdown, οπότε το χειροκίνητο garbage cleanup ενδέχεται να καθυστερεί αχρείαστα την διαδικασία. Σε γενικές γραμμές όμως είναι bad-practice να επαφίεσαι σε εξωγενείς παράγοντες να καθαρίζουν "your own mess", ενώ το αντίθετο κάνει και πιο ασφαλή, και πιο αυτόνομο και πιο portable τον κώδικά σου (όταν μάθεις δλδ να κάνεις μόνος σου free() τα malloc/calloc/realloc που έχεις κάνει) @pioneer2: να σαι καλά φίλε μου (έχει κάτι missing checks ο κώδικας, αλλά είπα να μην το παρακάνω τελείως )
bnvdarklord Δημοσ. 23 Νοεμβρίου 2011 Δημοσ. 23 Νοεμβρίου 2011 Κατάλαβα, περισσότερο για σιγουριά δηλαδή αμέσως πριν τελειώσει το πρόγραμμα. Στις αλλες περιπτώσεις υποθέτω οτι καλο ειναι να κανουμε free οσο το δυνατόν γρηγορότερα. Περισσότερο Java/C# εχω ασχοληθεί παρά με C/C++ και δυστυχώς(?) δεν εχω ασχοληθεί αρκετά με αυτά.
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα