migf1 Δημοσ. 13 Ιανουαρίου 2012 Δημοσ. 13 Ιανουαρίου 2012 Εξαντλείται η διαθέσιμη stack λόγω του ότι η αναδρομή σου επαναλαμβάνεται επ' άπειρον, δηλαδή μέχρι να εξαντληθεί η μνήμη της stack... και να την αυξήσεις την stack, πάλι το ίδιο πρόβλημα θα έχεις. Η λύση είναι να βρεις γιατί δεν σταματάει η αναδρομή σου όταν πρέπει να σταματήσει. ΥΓ. Btw, πολύ καλύτερος τώρα ο κώδικάς σου Σε λιγάκι θα ασχοληθώ να διορθώσω κάτι λάθη ή/και σημεία που παίρνουν βελτίωση που εντόπισα στην main και θα ποστάρω.
Exosouler Δημοσ. 13 Ιανουαρίου 2012 Μέλος Δημοσ. 13 Ιανουαρίου 2012 ευχαριστώ πολύ θα προσπαθήσω σε λιγάκι να βρώ γιατί δεν σταματάει η αναδρομή αν και μου φαίνεται περιεργο γιατί δουλεύει ας πούμε για ν=14 αλλα όχι για ν=17 και ουσιαστικά δεν γίνεται κάτι το διαφορετικό.Εγω πιστεύω οτι δεν επαναλαμβάνεται επ'άπειρον αλλα παρα πολλες φόρες ωστε να ξεχειλείζει η στοίβα(δηλάδη αν ανεβάσουμε το μέγεθος της στοίβας ισως να δουλεύει για λίγο πιο μεγάλα ν), αλλα και πάλι πρόβλημα στην υλοποίηση του αλγόριθμου υπάρχει.
migf1 Δημοσ. 13 Ιανουαρίου 2012 Δημοσ. 13 Ιανουαρίου 2012 Τώρα που το ξανασκέφτομαι, επειδή δεν έχω δει καθόλου τον κώδικά σου, παίζει η διαθέσιμη stack να μη χωράει πάνω από 15 αναδρομές. Οπότε δοκίμασε να την αυξήσεις, αλλά ο κάθε compiler έχει διαφορετικό τρόπο... ψάξε να βρεις στον δικό σου με ποιο command-line flag ορίζεις μέγεθος stack (αν είναι ήδη ρυθμισμένη σε όλη τη διαθέσιμη μνήμη, τότε επιστρέφουμε στο αρχικό πρόβλημα: infinite recursion). Για δώσε στο unix shell σου: $ ulimit -s Το νούμερο που σου επιστρέφει είναι η stack σε bytes. Με... $ulimit -s new_stcksize_in_bytes την αλλάζεις σε ότι νούμερο βάλεις αντί για new_stcksize_in_bytes
Exosouler Δημοσ. 13 Ιανουαρίου 2012 Μέλος Δημοσ. 13 Ιανουαρίου 2012 linux01:/home/users/sdi1100130/ask3r3>$ ulimit -s $: Command not found. linux01:/home/users/sdi1100130/ask3r3> αλλά δεν νομίζω να είναι αυτο το πρόβλημα γιατι το έχω δοκιμάσει στα pc της σχολής, λογικά θα είναι ρυθμισμένο κατάλληλα.
migf1 Δημοσ. 13 Ιανουαρίου 2012 Δημοσ. 13 Ιανουαρίου 2012 Λοιπόν, για άλλα ξεκίνησα και σε άλλα κατέληξα Δεν έχω λύση για το βασικό σου πρόβλημα, ασχολήθηκα μονάχα με τη main() και τις σχετικές συναρτήσεις που προσέθεσα... > #include <stdio.h> #include <stdlib.h> #include <time.h> #include <string.h> /* for memset(), ... */ /* Constants & Macros ================================ */ #define MAXINPUT (1023+1) /* max chars for our input line */ /* portable altenative to Windows' system("pause") ... to be used with fgets instead of scanf */ #define pressENTER() \ do{ \ char myInPUtBUFer[255]={'\0'}; \ printf("\npress ENTER..."); \ fgets(myInPUtBUFer, 255, stdin); \ }while(0) /* safer alternative to stdlib's free() */ #define SAFEFREE( p ) \ do { \ if ( (p) ) \ { \ free( (p) ); \ (p) = NULL; \ } \ }while(0) /* Function Prototypes ================================ */ int **create_prefs( const int n ); int input_getInt( const char *prompt ); void rec (int *,int *,int *, int**, int **, int, int); int stmar (int *, int *, int**, int **, int, int, int); void print_solution (int *, int *, int *, int); void free_prefs( int **, const int n ); void cleanup( int **wprefs, int **mprefs, int *wife, int *husb, int *preforder, const int n ); /* Function Definitions =============================== */ /* -------------------------------------------------------------- * * -------------------------------------------------------------- */ int main( void ) { int i,j,k ; /* metrhtes */ int n; /* plh8os antrwn & gunekwn */ int *wife = NULL, *husb = NULL, *preforder = NULL; int **wprefs = NULL, **mprefs = NULL; /* protimhseis gynekwn, antrwn*/ srand( (unsigned int) time(NULL) ); /* gennhtria pseydotyxaiwn */ n = input_getInt( "Total # of men and women (0 or negative to exit): " ); if ( n < 1 ) goto exit_success; /* dhmiourgia dynamikwn pinakwn */ mprefs = create_prefs( n ); /* protimiseis ka8e antra */ wprefs = create_prefs( n ); /* protimiseis ka8e gunekas */ wife = malloc( n * sizeof(int ) ); /* h guneka tou ka8e antra */ husb = malloc( n * sizeof(int ) ); /* o antras ths ka8e gunekas */ /* * h seira poy exei h gyneka toy kathe antra stis protimhseis toy * ( preforder[n] = to plithos olwn twn dynatwn tropwn kataskeyhs stable gamwn ) */ preforder = malloc( (n+1)* sizeof(int) ); /* elegxos gia apotyxia desmeyesh mnhmhs */ if ( !mprefs || !wprefs || !wife || !husb || !preforder) goto exit_fatal; preforder[ n ] = 0; /* 0 luseis */ /* protimhseis antrwn gia gynaikes */ for (i=0; i < n; i++) { wife[i] = 0; /* mhdenzoyme tis gunekes */ printf("Please give the order of preferences for: m%3.3d\n", i+1); for (j=0; j < n; j++) mprefs[i][j] = input_getInt( NULL ); } /* protimhseis gykaikwn gia antres */ for (i=0; i < n; i++) { husb[i] = 0; /* mhdenizoyme & tous antres */ printf("Please give the order of preferences for: w%3.3d\n", i+1); for (j=0; j < n; j++) wprefs[i][j] = input_getInt( NULL ); } /*** CONSIDER WHAT FOLLOWS INSTEAD for (i=0; i < n; i++) preforder[i] = 0; // oloi oi antres anypantroi ***/ memset( preforder, 0, n * sizeof(int) ); /* oloi oi antres anypantroi */ puts("\n\n\nFinding all solutions with backtracking via recursion\n\n\n"); rec( wife, husb, preforder, wprefs, mprefs, 0, n ); exit_success: puts( "exiting the program..." ); /* cleanup & exit */ cleanup( wprefs, mprefs, wife, husb, preforder, n ); pressENTER(); exit( EXIT_SUCCESS ); exit_fatal: puts("*** fatal error: out of memory"); /* cleanup & exit */ cleanup( wprefs, mprefs, wife, husb, preforder, n ); pressENTER(); exit( EXIT_FAILURE ); } /* -------------------------------------------------------------- * * -------------------------------------------------------------- */ int **create_prefs( const int n ) { int i,j, **prefs = NULL; /* desmeysh mnhmhs gia n deiktes se int (int *) */ prefs = calloc( n, sizeof(int *) ); if ( !prefs ) return NULL; /* desmeysh mnhmhs gia n ints se kathe prefs[i] */ for ( i=0; i < n; i++ ) { prefs[i] = calloc( n, sizeof(int) ); if ( !prefs[i] ) { for ( j=i; j > -1; j--) /* free previous indices */ free( prefs[j] ); SAFEFREE( prefs ); } } return prefs; } /* -------------------------------------------------------------- * * -------------------------------------------------------------- */ int input_getInt( const char *prompt ) { char input[ MAXINPUT ] = {'\0'}; if ( prompt ) printf("%s", prompt); fgets( input, MAXINPUT, stdin ); return atoi( input ); } /* -------------------------------------------------------------- * Kataskevh olwn twn dunatwn gamwn * -------------------------------------------------------------- */ void rec(int *wife,int *husb,int *preforder,int **wprefs,int **mprefs,int i ,int n) { int k,j; /* metrhtes */ int flag=0; while(i<n && preforder[n]!=-10) { for (j=preforder[i];j<n;j++) { printf("Trying to marry man %d to woman %d \n",i+1,mprefs[i][j]); if (husb[mprefs[i][j]-1]==0) { if (stmar(wife,husb,wprefs,mprefs,i,j,n)==0) { printf("Succeeded!!\n"); preforder[i]=j+1; wife[i]=mprefs[i][j] ; husb[mprefs[i][j]-1]=i+1 ; if (i==n-1) /* an pantrepsoume kai ton telefteo antra */ print_solution (wife, husb, &preforder[n], n); else { preforder[i+1]=0; break; } } else printf("Sorry, marriage is unstable\n"); } else printf("Sorry, woman%d is already married\n",mprefs[i][j]); } if (wife[i]==0) /* an o antras i+1 einai elef8eros */ { husb[wife[i-1]-1]=0; /* free woman whom man i-1 has married */ wife[i-1]=0; /* free man i-1 */ preforder[i]=0; for (k=0;k<i;k++) if (preforder[k]!=n) flag=1; if (flag==0){ /* if each man before i has married the last woman of his preferences */ printf("\n\nFound %d Solution(s)\n",preforder[n]); preforder[n]=-10; /* -10: random value which doesn't affect the program */ } if (preforder[n]!=-10) /* try to marry man i-1 */ rec(wife,husb,preforder,wprefs,mprefs,i-1,n); } i++; } } /* -------------------------------------------------------------- * * -------------------------------------------------------------- */ /*Elenxos an o gamos tou antra i me thn gunaika pou tis ekane protash gamou einai sta8eros Oi gamoi einai sta8eroi otan den exoume 2 gamous A-G a'-G' (o antras A exei na pantreftei thn guneka G kai o antras A' thn guneka G') tetoioi wste o a A na protima thn G' perissotero apo thn G kai h G' na protima ton A perissotero apo ton A'*/ int stmar (int *wife,int *husb,int **wprefs,int **mprefs,int i,int j,int n) { int k,p ; /* metrhtes */ int unstable1=0 ; int unstable2=0 ; for (k=1;k<=i;k++) { unstable1=unstable2=0; for(p=0;p<n;p++) { if (wprefs[wife[k-1]-1][p]== i+1) /* if woman of man k prefers man i+1 more than her man */ unstable1++; else if (wprefs[wife[k-1]-1][p]== k) /* if woman of man k prefers her man more than man i */ break; } for(p=0;p<n;p++) { if (mprefs[i][p]==wife[k-1]) /*if man i prefers woman of man k more than his woman */ unstable1++; else if (mprefs[i][p] == mprefs[i][j]) /*if man i prefers his woman more than woman of man k */ break; } if (unstable1==2 ) /* if there is a unstable marriage */ break; for(p=0;p<n;p++) { if (mprefs[k-1][p]==mprefs[i][j]) /*if man k prefers woman of man i more than his woman */ unstable2++; else if (mprefs[k-1][p]==wife[k-1]) /*if man k prefers his woman more than woman of man k */ break; } for(p=0;p<n;p++) { if (wprefs[mprefs[i][j]-1][p]==k) /*if woman of man i prefers man k more than her man */ unstable2++; else if (wprefs[mprefs[i][j]-1][p]==i+1) /*if woman of man i prefers her man more than man k */ break; } if (unstable2==2) /* if there is a unstable marriage */ break; } if (unstable1==2 || unstable2==2) return 1; else return 0; } /* -------------------------------------------------------------- * * -------------------------------------------------------------- */ /* ektupwsh twn lusewn */ void print_solution( int *wife,int *husb, int *solution, int n ) { int k; solution[0]++; /* increase by 1 the number of solutions */ printf("\nSolution %d: \n\n",solution[0]); for (k=0;k<n;k++) { printf("m%3.3d - w%3.3d ",k+1,wife[k]); if ((k+1)%4==0 && k!=0) printf("\n"); } printf("\n\n"); if (n!=1) { husb[wife[n-1]-1]=0; wife[n-1]=0; } } /* -------------------------------------------------------------- * * -------------------------------------------------------------- */ void free_prefs( int **prefs, const int n ) { int i; if ( !prefs ) return; for (i=0; i < n; i++ ) SAFEFREE( prefs[i] ); SAFEFREE( prefs ); return; } /* -------------------------------------------------------------- * * -------------------------------------------------------------- */ void cleanup( int **wprefs, int **mprefs, int *wife, int *husb, int *preforder, const int n ) { free_prefs( mprefs, n ); free_prefs( wprefs, n ); SAFEFREE( wife ); SAFEFREE( husb ); SAFEFREE( preforder ); return; } Το βασικό πρόβλημα που είχε ήταν πως δεν απελευθέρωνε πουθενά τη μνήμη που δέσμευε για όλους αυτούς τους πίνακες (ούτε όταν προέκυπτε σφάλμα αλλά ούτε και όταν δεν προέκυπτε). Η διόρθωση του παραπάνω γίνεται με τη συνάρτηση cleanup()μ η οποία αναλαμβάνει να απελευθερώσει οποιαδήποτε μνήμη έχει δεσμεύσει δυναμικά η main, και μόνο αυτή. Είναι σημαντικό να ελέγχεις αν όντως υπάρχει δεσμευμένη μνήμη σε έναν δείκτη πριν επιχειρήσεις να τον κάνεις free(), αλλιώς μπορεί να έχεις προβλήματα. Ο "μηχανισμός" που χρησιμοποιούμε στη C για αυτή τη δουλειά είναι πολύ απλός, και συνοψίζεται στους 3 παρακάτω "κανόνες"... Αρχικοποιούμε ΠΑΝΤΑ τους δείκτες (είτε σε NULL, είτε σε μνήμη που δείχνει άλλος δείκτης, είτε σε φρέσκια δεσμευμένη μνήμη με χρήση malloc/calloc). Ελέγχουμε ΠΑΝΤΑ να ΜΗΝ είναι NULL o δείκτης που θέλουμε να κάνουμε free() πριν τον κάνουμε free(). Θέτουμε ΠΑΝΤΑ σε NULL όποιον δείκτη έχουμε κάνει free(). Τα 2 τελευταία από τα παραπάνω, τα υλοποιεί το macro SAFEFREE(p) που έχω συμπεριλάβει και χρησιμοποιώ στον κώδικα (όπου χρησιμοποιώ σκέτο free() είναι επειδή έχω εξασφαλίσει πως δεν είναι NULL ο δείκτης που κάνω free() ... αν δεν τον θέτω κατόπιν χειροκίνητα ίσο με NULL είναι επειδή το πρόγραμμα θα τερματίσει έτσι κι αλλιώς). Για αρχή, μπορείς να χρησιμοποιείς παντού και πάντα το SAFEFREE() κι ας είναι redundant σε κάποιες λίγες περιπτώσεις. Το 1ο από τα παραπάνω το υλοποιώ στον ορισμό των δεικτών, έτσι ώστε να είμαι σίγουρος πως όταν η ροή περάσει μέσα στην cleanup ΚΑΝΕΝΑΣ δείκτης μου δεν θα είναι undefined, και άρα δεν πρόκειται να δώσει seg-fault κανένας από τους έλεγχους που κάνει η cleanup (μέσω της SAFEFREE() ) για μη NULL δείκτη πριν τον κάνει free(). Το επόμενο που άλλαξα είναι να φτιάξω μια ξεχωριστή συνάρτηση: create_prefs() για τη δέσμευση μνήμης των πινάκων wprefs & mprefs. Επειδή είναι 2-διάστατοι, θέλουν έξτρα κώδικα (για τη δέσμευση της 2ης διάστασης) ο οποίος κώδικας όταν είναι χύμα στη main() χαλάει πολύ το readability επειδή επαναλαμβάνεται οπτικά Μια σημαντική επισήμανση για την create_prefs() είναι πως αν αποτύχει οποιαδήποτε δέσμευση μνήμης στη 2η διάσταση (οποιοδήποτε δηλαδή indexed prefs[ i ] ) τότε αποδεσμεύει πρώτα τη μνήμη που είχε δεσμευτεί επιτυχημένα στα προηγούμενα indices της 1ης διάστασης, μετά αποδεσμεύει την 1η διάσταση (τον prefs δηλαδή) και τέλος επιστρέφει NULL. Η συνάρτηση: free_prefs() κάνει την ανάποδη διαδικασία από την create_prefs()... αποδεσμεύει πρώτα την 2η διάσταση και κατόπιν την 1η. Και θέτει τον prefs ίσο με NULL (μέσω της SAFEFREE(prefs) ). Αυτά ήταν τα σημαντικά που έπρεπε να γίνουν στην main(). Τα υπόλοιπα που έκανα δεν είναι κρίσιμης σημασίας, αλλά λύνουν διάφορες "ενοχλήσεις". Για παράδειγμα το διάβασμα με scanf() υποφέρει από το πρόβλημα με τα απομεινάρια στην κύρια είσοδο, τα οποία τα λαμβάνει εσφαλμένα ως user input η επόμενη scanf (getchar(), κλπ). Μια γενική λύση είναι να διαβάζουμε μονοκόμματα όλη τη γραμμή της stdin μέσα σε ένα string με την fgets(), το οποίο string πρέπει να έχει μέγιστο χώρο μεγαλύτερο από το προβλεπόμενο input του user. Αυτό το string στον κώδικα μου είναι το: input. Κατόπιν "τραβάμε¨" μέσα από το string input όποια ή όποιες μεταβλητές χρειαζόμαστε, είτε με sscanf() είτε με strtok() είτε με ato?(). Στον κώδικα έφτιαξα μια ξεχωριστή συνάρτηση για διάβασμα μεταβλητών int, την input_getInt( prompt ) που όπως θα δεις τη χρησιμοποιώ όπου εσύ είχες scanf. Τέλος, επειδή το: system("pause") λειτουργεί μόνο σε Windows, το αντικατέστησα με το macro: pressENTER() το οποίο είναι cross-platform, αλλά με την προϋπόθεση πως όλα σου τα input τα κάνεις με τον τρόπο που περιέγραψα παραπάνω (fgets() και μετά ato?(), sscanf() ή strtok()... υπάρχουν κι άλλες συναρτήσεις, αλλά αυτές αρκούν). ΥΓ1. Α, άλλαξα ελαφρώς και τα ονόματα 2-3 μεταβλητών (το series σε preforder βασικά και τα prefw & prefm σε wprefs & mprefs) ΥΓ2. Οι περισσότεροι καθηγητές απαγορεύουν τη χρήση του goto. Η παραπάνω χρήση του είναι αποδεκτή όμως, γιατί δομεί καλύτερα το πρόγραμμα.
Exosouler Δημοσ. 17 Ιανουαρίου 2012 Μέλος Δημοσ. 17 Ιανουαρίου 2012 έχω μερικές απορίες 1) δεν έχω καταλάβει τόσο καλά τις εξής αλλαγές: > /* Constants & Macros ================================ */ #define MAXINPUT (1023+1) /* max chars for our input line */ /* portable altenative to Windows' system("pause") ... to be used with fgets instead of scanf */ #define pressENTER() \ do{ \ char myInPUtBUFer[255]={'\0'}; \ printf("\npress ENTER..."); \ fgets(myInPUtBUFer, 255, stdin); \ }while(0) /* safer alternative to stdlib's free() */ #define SAFEFREE( p ) \ do { \ if ( (p) ) \ { \ free( (p) ); \ (p) = NULL; \ } \ }while(0) int input_getInt( const char *prompt ) { char input[ MAXINPUT ] = {'\0'}; if ( prompt ) printf("%s", prompt); fgets( input, MAXINPUT, stdin ); return atoi( input ); } memset( preforder, 0, n * sizeof(int) ); Το τι κάνουν κατάλαβα¨, πώς το κάνουν όμως? 2)τα σχόλια που εξηγούν τις συναρτήσεις να τα βάζω όλα μαζί κατώ απο τα προτοτυπά τους ή πάνω απο κάθε συνάρτηση? 3)"Θέτουμε ΠΑΝΤΑ σε NULL όποιον δείκτη έχουμε κάνει free()." Γιατί τα κάνουμε αυτο? (το NULL είναι ίσο με 0? το *p=NULL συμβολίζει ότι ο δείκτης δεν δείχνει πουθενά? 4)ποιές οι διαφορές μεταξύ malloc/realloc/calloc. 5)το πρόγραμμα πρέπει να το παραδώσουμε σε τουλάχιστον 2 πηγαία και 1 επικεφαλίδα, το καλύτερο είναι να βάλω στο ένα την main και στο αλλο όλες τις συναρτήσεις ή να φτιάξω διαφορετίκα πηγαία για το κάθε μέρος της άσκησης? ΥΠ: α)μου αρέσει η τροποποίηση τών σχολιών με ----------- και *** β)ο καθηγήτης μας έχει αυστηρά τονίσει οτι απαγορεύεται η χρήση της goto και μάλιστα η χρήση της στην άσκηση ισοδυναμεί με μηδενισμο!! Ευχαριστώ για τον χρόνο σου!
migf1 Δημοσ. 17 Ιανουαρίου 2012 Δημοσ. 17 Ιανουαρίου 2012 έχω μερικές απορίες 1) δεν έχω καταλάβει τόσο καλά τις εξής αλλαγές: > /* Constants & Macros ================================ */ #define MAXINPUT (1023+1) /* max chars for our input line */ /* portable altenative to Windows' system("pause") ... to be used with fgets instead of scanf */ #define pressENTER() \ do{ \ char myInPUtBUFer[255]={'\0'}; \ printf("\npress ENTER..."); \ fgets(myInPUtBUFer, 255, stdin); \ }while(0) /* safer alternative to stdlib's free() */ #define SAFEFREE( p ) \ do { \ if ( (p) ) \ { \ free( (p) ); \ (p) = NULL; \ } \ }while(0) int input_getInt( const char *prompt ) { char input[ MAXINPUT ] = {'\0'}; if ( prompt ) printf("%s", prompt); fgets( input, MAXINPUT, stdin ); return atoi( input ); } memset( preforder, 0, n * sizeof(int) ); Το τι κάνουν κατάλαβα¨, πώς το κάνουν όμως? Καταρχήν, να έχεις πάντα εύκαιρη την τεκμηρίωση των στάνταρ συναρτήσεων της γλώσσας, καθώς και της όποιας βιβλιοθήκης χρησιμοποιείς. man & info εφόσον είσαι σε Unix είναι οι φίλοι σου! Και το google επίσης Η memset() θέτει την τιμή του 2ου ορίσματος στη μνήμη που εκφράζει το 1ο όρισμα, ξεκινώντας από την αρχή της μέχρι όσο bytes ορίζει το 3ο όρισμα. Είναι κατά πολύ ταχύτερη από το να το κάνεις με "χειροκίνητα" με loop. Το SAFEFREE(p) απλώς ελέγχει ο δείκτης p να ΜΗΝ είναι NULL πριν τον κάνει free() και τον θέτει ίσο με NULL. Αν σε μπερδεύει η υλοποίηση ως macro, μπορείς να το κάνεις συνάρτηση... > void safe_free( void **p ) { if ( !p || !(*p) ) return; free( *p ); *p = NULL; return; } αλλά τότε θα πρέπει να τη καλείς με τη διεύθυνση του p και όχι σκέτο τον p. Π.χ... > int n = 10; int *p = calloc( n, sizeof(int) ); ... /* κάνεις ότι έχεις να κάνεις με τον p */ ... safe_free( &p ); ... Το pressENTER() το έχω λίγο πολύπλοκο! Βασικά είναι καλύτερα να αλλάξει σε... > #define pressENTER() \ do { \ int mY_cHr; printf( "press ENTER..." ); \ while ( (mY_cHr=getchar()) != '\n' && mY_cHr != EOF ) \ ; /* empty body */ \ } while (0) Ξανά, αν σε μπερδεύει ως macro, μπορείς κι αυτό να το κάνεις συνάρτηση... > void press_enter( void ) { int c; printf( "press ENTER..." ); while ( (c=getchar()) != '\n' && c != EOF ) ; /* empty body */ return; } Η input_getInt() αντιμετωπίζει το πρόβλημα που έχουν οι στάνταρ συναρτήσεις της C, ειδικά η scanf() αλλά και οι υπόλοιπες, οι οποίες ενδέχεται να αφήσουν σκουπίδια στη κύρια είσοδο, τα οποία τα εκλαμβάνουν ως έγκυρο input μεταγενέστερες κλήσεις των συναρτήσεων αυτών. Ρίξε μια ματιά κι εδώ: http://c-faq.com/stdio/scanfprobs.html Μια λύση είναι αυτό που κάνει η input_getInt() ... διαβάζει μονοκόμματα τη γραμμή της κύριας είσοδο μέσα σε ένα πολύ μεγάλο string, από το οποίο "τραβάει" κατόπιν τον int που θέλει. Το μειονέκτημα είναι πως έτσι πρέπει να φτιάξεις μια ξεχωριστή: input_get???() συνάρτηση για κάθε ξεχωριστό τύπο που θες να διαβάζεις. Μια άλλη λύση είναι να διαβάζεις απευθείας στον κώδικά σου το μεγάλο string με fgets() αντί για scanf() και αμέσως μετά να χρησιμοποιείς την sscanf() για να πάρεις τις μεταβλητές που θέλεις... > ... int n=0; float x = 0.0; char input[ 1023+1 ] = {'\0'}; printf( "enter an int and a float (e.g: n x): " ); fgets( input, 1023+1, stdin ); sscanf( input, "%d %f", &n, &x); ... Μια ακόμα λύση είναι να καθαρίζεις μόνος σου την κύρια είσοδο μετά ή πριν από κάθε διάβασμά της. Η fflush( stdin ) που θα δεις ως πρόταση έχει σταματήσει να λειτουργεί (μάλιστα δεν ξέρω αν λειτουργούσε καν ποτέ σωστά, τη χρησιμοποιούσα κι εγώ παλαιότερα). Οπότε... > #define stdinFLUSH() \ do { \ int mY_cHr; \ while ( (mY_cHr=getchar()) != '\n' && mY_cHr != EOF ) \ ; /* empty body */ \ } while (0) μπορείς να τη κάνεις κι αυτή συνάρτηση αν σε βολεύει καλύτερα. 2)τα σχόλια που εξηγούν τις συναρτήσεις να τα βάζω όλα μαζί κατώ απο τα προτοτυπά τους ή πάνω απο κάθε συνάρτηση? Πάνω από κάθε συνάρτηση. Μπορείς να χρησιμοποιείς και συγκεκριμένη μορφή στη συγγραφή τους, ώστε κατόπιν να χρησιμοποιείς εργαλεία όπως το Doxygen που διαβάζουν τα σχόλια και παράγουν αυτόματα τεκμηρίωση σε διάφορες μορφές (html, latex, pdf, κλπ, κλπ). 3)"Θέτουμε ΠΑΝΤΑ σε NULL όποιον δείκτη έχουμε κάνει free()." Γιατί τα κάνουμε αυτο? (το NULL είναι ίσο με 0? το *p=NULL συμβολίζει ότι ο δείκτης δεν δείχνει πουθενά? Διότι με σκέτο free() ο δείκτης μένει undefined, οπότε χάνουμε τη δυνατότητα να τον ελέγξουμε πριν τον ξανα-χρησιμοποιήσουμε. Έχω την εντύπωση πως στην αναθεώρηση C99 το free() τον θέτει αυτόματα σε NULL (αλλά και σίγουρος δεν είμαι και κανείς compiler μέχρι σήμερα δεν πληροί στο έπακρο τις προδιαγραφές της C99... ο καθένας υποστηρίζει διαφορετικό τμήμα προδιαγραφών). Το σίγουρο είναι πως πριν την αναθεώρηση C99 κάνοντας free() έναν δείκτη που είναι NULL παράγει segmentation-fault. Το NULL ισούται με 0 στην C++. Στην C συνήθως ισούται με (void *) 0 ... στη πράξη είναι το ίδιο πράγμα. Θέτοντας έναν δείκτη ίσο με NULL είναι ο τρόπος που έχουμε για να σιγουρεύουμε πως ένα δείκτης είναι συνειδητά απενεργοποιημένος από εμάς. 4)ποιές οι διαφορές μεταξύ malloc/realloc/calloc. Η calloc() κάνει ότι και η malloc() (με ελαφρώς διαφορετική σύνταξη) αλλά μηδενίζει εγγυημένα τη μνήμη που δεσμεύει. Η realloc() είναι για αυξομείωση μεγέθους της ήδη δεσμευμένης μνήμης στην οποία δείχνει κάποιος δείκτης μας. 5)το πρόγραμμα πρέπει να το παραδώσουμε σε τουλάχιστον 2 πηγαία και 1 επικεφαλίδα, το καλύτερο είναι να βάλω στο ένα την main και στο αλλο όλες τις συναρτήσεις ή να φτιάξω διαφορετίκα πηγαία για το κάθε μέρος της άσκησης? Το καλύτερο είναι το κάθε πηγαίο αρχείο σου να αποτελείται από συναρτήσεις που διαχειρίζονται το ίδιο concept Για παράδειγμα, θα μπορούσες να βάλεις σε ένα main.c να βάλεις τις... > void rec (int *,int *,int *, int**, int **, int, int); int stmar (int *, int *, int**, int **, int, int, int); void print_solution (int *, int *, int *, int); και την main() οι οποίες υλοποιούν το υπολογιστικό κομμάτι του προγράμματος και σε ένα util.c να βάλεις τις... > int **create_prefs( const int n ); int input_getInt( const char *prompt ); void free_prefs( int **, const int n ); void cleanup( int **wprefs, int **mprefs, int *wife, int *husb, int *preforder, const int n ); που ασχολούνται με το housekeeping. ΥΠ: α)μου αρέσει η τροποποίηση τών σχολιών με ----------- και *** β)ο καθηγήτης μας έχει αυστηρά τονίσει οτι απαγορεύεται η χρήση της goto και μάλιστα η χρήση της στην άσκηση ισοδυναμεί με μηδενισμο!! Ευχαριστώ για τον χρόνο σου! Σωστά το απαγορεύει ο καθηγητής, γιατί στις περισσότερες περιπτώσεις οδηγεί σε δυσνόητο κώδικα και κυρίως επιρρεπή σε bugs. Κι επειδή δεν μπορεί να είναι σίγουρος πότε κι εάν είστε σε θέση να το χρησιμοποιήσετε σωστά (σε εκείνες τις λίγες εξαιρέσεις των περιπτώσεων) λέει ένα γενικό "απαγορεύεται" και... καθαρίζει Οπότε, τροποποίησε τον κώδικα ώστε να μη χρησιμοποιεί το goto (βάλε δηλαδή να κάνει την ίδια δουλειά στα σημεία που έχει τώρα την goto το παράδειγμά μου).
imitheos Δημοσ. 17 Ιανουαρίου 2012 Δημοσ. 17 Ιανουαρίου 2012 έχω μερικές απορίες 1) δεν έχω καταλάβει τόσο καλά τις εξής αλλαγές: > #define SAFEFREE( p ) \ do { \ if ( (p) ) \ { \ free( (p) ); \ (p) = NULL; \ } \ }while(0) Το τι κάνουν κατάλαβα¨, πώς το κάνουν όμως? Όπως εξήγησε ο migf1 μπορείς να κάνεις το ίδιο με συνάρτηση αν σε μπερδεύει το macro. Πριν αναλάβει ο compiler, ο preprocessor κάνει ένα πέρασμα τον κώδικα και όπου έχεις SAFEFREE το αντικαθιστά με όλο εκείνο τον κώδικα. Έτσι αν θέλεις να το χρησιμοποιήσεις πολλές φορές, αντί να γράφεις όλο το κατεβατό μπορείς απλά να γράψεις SAFEFREE και για τον compiler θα είναι σαν να το είχες γράψει το κατεβατό. Το do-while(0) είναι μια μαγκιά που σου επιτρέπει να έχεις macros με πολλές γραμμές που να παίζουν όμως σε όλες τις καταστάσεις. > #define print_n_exit(s) \ printf("sunebh to ekshs la8os: %s\n", s); \ exit(-1) if (tade_sun8iki) print_n_exit("minima lathous"); Δες για παράδειγμα αυτό τον χαζό κώδικα. Όταν ο preprocessor αντικαταστήσει το print_n_exit (είθισται τα macro να έχουν κεφαλαία γράμματα αλλά βαριόμουν να κρατάω το shift ) τότε μέσα στο if θα εκτελείται μόνο η 1η γραμμή δηλαδή το printf ενώ η exit θα εκτελείται πάντα έτσι δεν κάνει αυτό που θέλεις. Με το do-while(0) ξεπερνάς αυτό το εμπόδιο και λόγω του while(0), οι εντολές μέσα στο do θα εκτελεστούν ακριβώς μία φορά. 3)"Θέτουμε ΠΑΝΤΑ σε NULL όποιον δείκτη έχουμε κάνει free()." Γιατί τα κάνουμε αυτο? (το NULL είναι ίσο με 0? το *p=NULL συμβολίζει ότι ο δείκτης δεν δείχνει πουθενά? Ο memory allocator του κάθε συστήματος (συνήθως) έχει κάποιες περιοχές μνήμης με διάφορα μεγέθη και όταν εσύ ζητάς με την malloc μνήμη, σου εκχωρεί μια τέτοια περιοχή. Όταν κάνεις free, σημειώνεται ότι η περιοχή δεν σου ανήκει πια και είναι ελεύθερη αλλά ο δείκτης συνεχίζει να δείχνει εκεί. Έτσι αν εσύ προσπαθήσεις να προσπελάσεις ξανά τον δείκτη μπορεί να γράψεις σε μνήμη που δεν πρέπει. Ενώ αν ο δείκτης έχει την τιμή NULL και τον προσπελάσεις, το πρόγραμμα θα crashάρει και έτσι θα καταλάβεις ότι κάτι φταίει. Μια άλλη συνήθης χρήση είναι για να γλυτώνεις το λεγόμενο double free. Αν κάνεις free ένα δείκτη που έχει γίνει ήδη free, θα crashάρει το πρόγραμμα (για την ακρίβεια μπορεί να γίνει οτιδήποτε αλλά χάριν ευκολίας ας πούμε ότι θα crashάρει) ενώ αν αυτός είναι NULL δεν θα γίνει τίποτα. Για αυτό το λόγο πολλοί ισχυρίζονται ότι είναι κακή πρακτική να θέτεις NULL στον δείκτη επειδή κρύβει τυχόντα λάθη στο πρόγραμμα που αλλιώς θα φαίνονταν. Το SAFEFREE(p) απλώς ελέγχει ο δείκτης p να ΜΗΝ είναι NULL πριν τον κάνει free() και τον θέτει ίσο με NULL. Ο έλεγχος για NULL (δεν κάνει κακό φυσικά αλλά) είναι περιττός. Έχω την εντύπωση πως στην αναθεώρηση C99 το free() τον θέτει αυτόματα σε NULL (αλλά και σίγουρος δεν είμαι και κανείς compiler μέχρι σήμερα δεν πληροί στο έπακρο τις προδιαγραφές της C99... ο καθένας υποστηρίζει διαφορετικό τμήμα προδιαγραφών). Το σίγουρο είναι πως πριν την αναθεώρηση C99 κάνοντας free() έναν δείκτη που είναι NULL παράγει segmentation-fault. Δεν νομίζω ότι η C99 αναφέρει ότι η free τον θέτει σε NULL αλλά δεν είμαι σίγουρος. Για το ότι πριν την C99 η free θα παράξει segmentation fault αν της δώσεις NULL που το βασίζεις ? Το ANSI (C89) πρότυπο αναφέρει 7.10.3.2 The free function If ptr is a null pointer, no action occurs. και νομίζω ότι ακόμη και πριν το πρότυπο η K&R έκανε το ίδιο αλλά δεν θυμάμαι. Σωστά το απαγορεύει ο καθηγητής, γιατί στις περισσότερες περιπτώσεις οδηγεί σε δυσνόητο κώδικα και κυρίως επιρρεπή σε bugs. Κι επειδή δεν μπορεί να είναι σίγουρος πότε κι εάν είστε σε θέση να το χρησιμοποιήσετε σωστά (σε εκείνες τις λίγες εξαιρέσεις των περιπτώσεων) λέει ένα γενικό "απαγορεύεται" και... καθαρίζει Αν μιλάμε για καθηγητή πανεπιστημίου τότε κακώς το κάνει. Δεν μιλάμε για παιδιά νηπιαγωγείου που η μαμά τους λέει "δεν θα περνάτε μόνοι σας το δρόμο". Να κάτσει να τους εξηγήσει ποιοι είναι οι κίνδυνοι και πότε πρέπει να αποφεύγεται η χρήση της goto αντί να απαγορεύει. Τέτοιες πρακτικές συνήθως σημαίνουν ότι ο ίδιος ο καθηγητής δεν έχει καταλάβει κάτι και προσπαθεί να το περάσει ως "απαγορεύεται να το χρησιμοποιείτε για να σας προστατεύσω".
nilosgr Δημοσ. 17 Ιανουαρίου 2012 Δημοσ. 17 Ιανουαρίου 2012 Αν μιλάμε για καθηγητή πανεπιστημίου τότε κακώς το κάνει. Δεν μιλάμε για παιδιά νηπιαγωγείου που η μαμά τους λέει "δεν θα περνάτε μόνοι σας το δρόμο". Να κάτσει να τους εξηγήσει ποιοι είναι οι κίνδυνοι και πότε πρέπει να αποφεύγεται η χρήση της goto αντί να απαγορεύει. Τέτοιες πρακτικές συνήθως σημαίνουν ότι ο ίδιος ο καθηγητής δεν έχει καταλάβει κάτι και προσπαθεί να το περάσει ως "απαγορεύεται να το χρησιμοποιείτε για να σας προστατεύσω". Ε, οχι. Μην γινεσαι "επιθετικος" σε ατομα / καταστασεις χωρις να εισαι σιγουρος.
Directx Δημοσ. 17 Ιανουαρίου 2012 Δημοσ. 17 Ιανουαρίου 2012 [..]Αν μιλάμε για καθηγητή πανεπιστημίου τότε κακώς το κάνει. Δεν μιλάμε για παιδιά νηπιαγωγείου που η μαμά τους λέει "δεν θα περνάτε μόνοι σας το δρόμο". Να κάτσει να τους εξηγήσει ποιοι είναι οι κίνδυνοι και πότε πρέπει να αποφεύγεται η χρήση της goto αντί να απαγορεύει. Τέτοιες πρακτικές συνήθως σημαίνουν ότι ο ίδιος ο καθηγητής δεν έχει καταλάβει κάτι και προσπαθεί να το περάσει ως "απαγορεύεται να το χρησιμοποιείτε για να σας προστατεύσω". Δεν νομίζω ότι είναι αυτός ο λόγος, απλά όταν μαθαίνει κανείς δομημένο προγραμματισμό είναι σαγηνευτικά εύκολο να ξεστρατίσει από το συγκεκριμένο μοτίβο με την χρήση της GOTO, οπότε για αρχή και μέχρι ο προγραμματιστής να φτάσει σε ένα επίπεδο που θα καταλαβαίνει μόνος του πότε ενδείκνυται η χρήση GOTO, απλά απαγορεύουν την χρήση της (συνήθως με ορισμένους αστερίσκους). Με τον καιρό βέβαια και καθώς προχωράς ξεφεύγεις μόνος σου από αυτές τις αγκυλώσεις και βλέπεις τις όποιες αρετές αυτής της εντολής (είμαι υπέρ της ύπαρξης της).
migf1 Δημοσ. 17 Ιανουαρίου 2012 Δημοσ. 17 Ιανουαρίου 2012 ... Ο έλεγχος για NULL (δεν κάνει κακό φυσικά αλλά) είναι περιττός. ... Δεν νομίζω ότι η C99 αναφέρει ότι η free τον θέτει σε NULL αλλά δεν είμαι σίγουρος. Για το ότι πριν την C99 η free θα παράξει segmentation fault αν της δώσεις NULL που το βασίζεις ? Το ANSI (C89) πρότυπο αναφέρει ... και νομίζω ότι ακόμη και πριν το πρότυπο η K&R έκανε το ίδιο αλλά δεν θυμάμαι. Έχεις δίκιο, στανταρίστηκε στο C89! Συνέβαινε όμως προ C89, δηλαδή K&R (να π.χ. μια τυχαία αναφορά που βρήκα: http://discuss.joelo...ign.4.194233.15) και μερικοί compilers συνέχιζαν να "υποφέρουν" από το πρόβλημα και μετά το σταντάρισμα. Παρεμπιπτόντως, εδώ είναι ένα εξαιρετικό άρθρο για τη χρήση δεικτών στη C (για όσους δεν το έχουν διαβάσει ήδη): http://www.eskimo.co...ss/int/sx7.html ΥΓ. Btw, σε Windows 7 64bit δίνει seg-fault και ο latest mingw32 gcc και η Pelles-C 6.0 64bit
imitheos Δημοσ. 17 Ιανουαρίου 2012 Δημοσ. 17 Ιανουαρίου 2012 Ε, οχι. Μην γινεσαι "επιθετικος" σε ατομα / καταστασεις χωρις να εισαι σιγουρος. Δεν νομίζω ότι είναι αυτός ο λόγος, απλά όταν μαθαίνει κανείς δομημένο προγραμματισμό είναι σαγηνευτικά εύκολο να ξεστρατίσει από το συγκεκριμένο μοτίβο με την χρήση της GOTO, οπότε για αρχή και μέχρι ο προγραμματιστής να φτάσει σε ένα επίπεδο που θα καταλαβαίνει μόνος του πότε ενδείκνυται η χρήση GOTO, απλά απαγορεύουν την χρήση της (συνήθως με ορισμένους αστερίσκους). Με τον καιρό βέβαια και καθώς προχωράς ξεφεύγεις μόνος σου από αυτές τις αγκυλώσεις και βλέπεις τις όποιες αρετές αυτής της εντολής. Ίσως ήμουν απότομος. Αυτό που είπα το βάσισα σε 3-4 καθηγητές πανεπιστημίου που γνωρίζω ότι το κάνουν (ό,τι δεν ξέρουν δεν είναι καλή πρακτική) αλλά η γενίκευση μου δεν ήταν δίκαιη. DirectX συμφωνώ με αυτό που είπες αλλά μιλάμε για πανεπιστήμιο. Δεν έχει ο φοιτητής την απαραίτητη κρίση να αποφασίσει πότε είναι χρήσιμη η goto ? (Με δεδομένο φυσικά ότι α) ότι ο καθηγητής θα εξηγήσει σωστά τι παίζει με το goto και β) ο φοιτητής θέλει να μάθει και θα προσέξει τι είπε ο καθηγητής). Στο πανεπιστήμιο (νομίζω ότι) πρέπει να σου ανοίγουν το μυαλό και να μπορείς να κρίνεις αντί να απαγορεύουν κάτι.
Directx Δημοσ. 17 Ιανουαρίου 2012 Δημοσ. 17 Ιανουαρίου 2012 Ίσως ήμουν απότομος. Αυτό που είπα το βάσισα σε 3-4 καθηγητές πανεπιστημίου που γνωρίζω ότι το κάνουν (ό,τι δεν ξέρουν δεν είναι καλή πρακτική) αλλά η γενίκευση μου δεν ήταν δίκαιη. DirectX συμφωνώ με αυτό που είπες αλλά μιλάμε για πανεπιστήμιο. Δεν έχει ο φοιτητής την απαραίτητη κρίση να αποφασίσει πότε είναι χρήσιμη η goto ? (Με δεδομένο φυσικά ότι α) ότι ο καθηγητής θα εξηγήσει σωστά τι παίζει με το goto και β) ο φοιτητής θέλει να μάθει και θα προσέξει τι είπε ο καθηγητής). Στο πανεπιστήμιο (νομίζω ότι) πρέπει να σου ανοίγουν το μυαλό και να μπορείς να κρίνεις αντί να απαγορεύουν κάτι. Επειδή τις περισσότερες φορές είτε η α είτε η β προϋπόθεση (είτε και οι δυο!) εκλείπουν ή απλά το συνολικό επίπεδο είναι χαμηλό (ως πολύ χαμηλό) αλλά και δεδομένου του πόσο σαγηνευτική είναι η χρήση της GOTO (όπως προείπα) ειδικά αν είσαι αρχάριος (συν ότι σε κάποιες γλώσσες πχ. όπως η JAVA δεν υποστηρίζεται -λάθος), για αυτό καταλήγουν σε ορισμένους αφορισμούς με αστερίσκους (αυτό συμβαίνει και στα ΤΕΙ ως προς την GOTO) και τελικά υποχρεώνουν τον φοιτητή να μην την χρησιμοποιεί ώστε να σε αναγκάσουν να σκεφτείς με "δομημένο τρόπο" δίχως υπεκφυγές (ακόμα και αν αυτό κοστίζει υπό συνθήκες περισσότερο).
migf1 Δημοσ. 17 Ιανουαρίου 2012 Δημοσ. 17 Ιανουαρίου 2012 ... YΓ. Btw, σε Windows 7 64bit δίνει seg-fault και ο latest mingw32 gcc και η Pelles-C 6.0 64bit Άκυρο το συγκεκριμένο, μόλις δοκίμασα και δεν (που είναι περίεργο, γιατί ήμουν σχεδόν σίγουρος). EDIT: Μόλις βρήκα κι ένα άρθρο στη Wikipedia που υλοποιεί την safe_free() ακριβώς όπως έδειξα κι εγώ, δηλαδή με έλεγχο για το αν είναι NULL ο δείκτης πριν τον κάνει free(): http://en.wikipedia.org/wiki/Dangling_pointer, για τον 1ο λόγο που εξήγησα κι εγώ (για την εγκυρότητα του δείκτη)... δεν αναφέρεται όμως σε seg-fault αν τον κάνεις free() όταν είναι NULL (γιατί ναι μεν έσκαγε επί K&R αλλά όντως στανταρίστηκε στο C89 όπως έδειξε ο imitheos)
nick518 Δημοσ. 18 Ιανουαρίου 2012 Δημοσ. 18 Ιανουαρίου 2012 Καλημερα, Exosouler, απο οτι καταλαβα εισαι πρωτοετης στην πληροφορικη του καποδιστριακου.Εγω εχω περασει πληροφορικη στην κερκυρα αλλα επειδη εδω τα πραγματα που κανουμε στην c το πρωτο εξαμηνο ειναι αρκετα απλα, ειπα για εξασκηση να ασχοληθω με τις δικες σας ασκησεις! Εχω γραψει πολυ παρομοιο κωδικα με τον δικο σου,οσον τουλαχιστον αφορα την αναδρομικη συναρτηση και παιρνω παρομοια σφαλματα... Αν τελικα καταφερεις να προσπερασεις το προβλημα θα σου ημουν ευγνομων αν μου ελεγες που ειχες κανει λαθος γιατι εχω σκαλωσει επικυνδινα.....ευχαριστω!!!!
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα