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

C Προβλημα με δυναμικη διχειριση μνημης.


antonis1245

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

Καλησπέρα, ξεκίνησα να κάνω μια εργασία στη C για τα χριστούγεννα κ μετα απο πολυ κοπο καταφερα να κανω σωστα τη διαχειριση της μνημης (τουλαχιστον ετσι νομιζα). Η εργασια ζηταει να φτιαξω ενα λεξικο (απο αγγλικα στα ελληνικα κ αντιστροφα) το οποιο θα ειναι δυναμικο (δηλ. θα χρειαστω δυσδιαστατο δυναμικο πινακα).  Αυτος ειναι ο κωδικας μου:

 

 

 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#define s_size 256



void show_menu();
void mem_alloc(char**,char**,unsigned int*);
void save_file(char**,char**,unsigned int*);

int main()
{
    unsigned int Sum_of_Terms=0; 
    char **En,**Gr;
    char ch,save;

   // Memory Initialization.
    En = (char**)malloc(sizeof(char* ));
    Gr = (char**)malloc(sizeof(char* ));


    do{
        show_menu();
        printf("\nInsert option: ");
        //scanf("%d",&ch);
        ch = getch();
        printf("\n");

        if(ch=='6')
        {
            do{
                printf("Would you like to save changes?(y/n): ");
                save = getch();
                printf("\n");

            }while(save!='y' && save!='n');
            if(save=='y')
                save_file(En,Gr,&Sum_of_Terms);
            else
                exit(0);

        }

        if(ch>'6' || ch<'1') printf("Invalid choice!\n");
        switch(ch)
        {
            case '1': mem_alloc(En,Gr,&Sum_of_Terms);
            break;
        }
        printf("\n Sum: %d",Sum_of_Terms);


    }while(ch!='6');


    return 0;
}

void show_menu()
{
    printf("\n\n********************************************");
    printf("\n***************** MENU *********************\n");
    printf("********************************************\n\n");

    printf("1. Insert new word. \n");
    printf("2. Modify an existing entry. \n");
    printf("3. Delete an entry. \n");
    printf("4. Translate a word. \n");
    printf("5. Translate a sentence. \n");
    printf("6. EXIT.\n");

}


void mem_alloc(char **En,char **Gr,unsigned int *w_count) // w_count = word count.
{
    int i;
    char s[s_size];

   (*w_count)++;

    En = (char**)realloc(En,sizeof(char* )*(*w_count));
    Gr = (char**)realloc(Gr,sizeof(char* )*(*w_count));

    if(En==NULL || Gr==NULL)
        printf("Could Not Allocate Memory (1).\n");
    else
    {

            //English Word.
            En[*w_count] = (char*)malloc(s_size*sizeof(char));
            if(En[*w_count]==NULL)
                printf("Could not allocate memory (2).\n");
            else
            {
                printf("Insert English Word: ");
                scanf("%s",s);
                //gets(s);
                En[*w_count]=(char*)malloc((strlen(s)+1)*sizeof(char)); // !**!
                strcpy(En[*w_count],s);
            }
            //Greek Word.
            Gr[*w_count] = (char*)malloc(s_size*sizeof(char));
            if(Gr[*w_count]==NULL)
                printf("Could not allocate memory (2).\n");
            else
            {
                printf("Insert Greek Word: ");
                scanf("%s",s);
                //gets(s);
                Gr[*w_count]=(char*)malloc((strlen(s)+1)*sizeof(char)); // !**!
                strcpy(Gr[*w_count],s);

            }

        //Test_point 1.
        for(i=1;i<=(*w_count);i++)
            printf("\n%s = %s\n",En[i],Gr[i]);

    }//else (1)

}
 

 

Το προβλημα που εχω ειναι οτι ενω οταν προσθετω λιγοτερα απο 3 στοιχεια ολα δουλευουν κομπλε αν παω να βαλω και τεταρτο στοιχειο το προγραμμα κρασαρει και επισης εμφανιζει τα στοιχεια των πινακων ως (null). Εχω σπασει το κεφαλι μου αλλα δν καταφερα να βρω το λαθος.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

  • Απαντ. 142
  • Δημ.
  • Τελ. απάντηση

Συχνή συμμετοχή στο θέμα

Φίλε Αντώνη,

Με μια γρήγορη ματιά ο υπαίτιος φαινεται να είναι τα 2 realloc στην mem_alloc. Αλλάζοντας τα σε malloc λογικά θα σταματήσει να σου κρασάρει. Παρ' όλα αυτά το πρόγραμμα είτε με realloc είτε με malloc εχει memory leaks στην παρούσα κατάσταση του, τα οποία προφανώς θα πρέπει να διαχειριστείς κατάλληλα.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Με μια γρήγορη ματιά ο υπαίτιος φαινεται να είναι τα 2 realloc στην mem_alloc. Αλλάζοντας τα σε malloc λογικά θα σταματήσει να σου κρασάρει.

 

Γιατί; Δε φταίνε τα realloc σε τίποτα.

 

Έχεις σίγουρα λάθος εδώ (δύο λάθη για την ακρίβεια):

En[*w_count] = (char*)malloc(s_size*sizeof(char));

Πρώτον (και σχεδόν σίγουρα αυτό που προκαλεί το crash) ότι γράφεις out of bounds στον En. *w_count - 1 θα ήταν το σωστό γιατί zero-based indexing.

 

Δεύτερον δεν καταλαβαίνω γιατί κάνεις πρώτα μια μεγάλη malloc εδώ και στη συνέχεια (μετά τη scanf) κάνεις μια μικρότερη, και χωρίς να κάνεις free την προηγούμενη πρώτα. Αυτό είναι memory leak αν και δε μπορεί να προκαλέσει crash.

 

Επίσης, γράφεις σε διάφορα σημεία sizeof(char). Δεν ξέρω αν το κάνεις για να είναι "φανερά σωστός στον αναγνώστη" ο κώδικας, αλλά θα μπορούσες να το παραλείψεις γιατί αξιωματικά το sizeof(char) είναι πάντα 1.

 

ΥΓ

Νταξει, όποτε βγαίνει τέτοιο thread δε μπορώ να μη πεθάνω στα γέλια όταν θυμάμαι τις γνωστές συζητήσεις "να μάθουν C να έχουν υπόβαθρο". Εδώ το παλικάρι έχει παιδευτεί άπειρα (όλοι ξέρουμε πόσα έτη φωτός μακριά είναι τα realloc με διπλούς pointers από κάποιον αρχάριο) και ακόμα δεν έχει καταφέρει το πρόγραμμά του να κάνει τίποτα χρήσιμο.

 

Σε οποιαδήποτε λίγο φιλικότερη γλώσσα μετά από τόση δουλειά θα είμασταν στη φάση που θα είχαμε κάνει abstract τον container και δυναμικά επιλεγόμενο ανάμεσα σε arrays, linked lists και ότι άλλο αγαπάς για να τρέξουμε benchmarks να δούμε στην πράξη το big-oh των αλγορίθμων που θα είχαμε ήδη υλοποιήσει.

  • Like 5
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Μα ίσα ίσα αυτό λέω. Ότι είναι εντυπωσιακό το πόση δουλειά έριξε, και πάλι κοίτα πού είναι ακόμα επειδή σε κάθε βήμα πρέπει να πολεμάει τη γλώσσα.

  • Like 3
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Γιατί; Δε φταίνε τα realloc σε τίποτα.

 

Έχεις σίγουρα λάθος εδώ (δύο λάθη για την ακρίβεια):

En[*w_count] = (char*)malloc(s_size*sizeof(char));

Πρώτον (και σχεδόν σίγουρα αυτό που προκαλεί το crash) ότι γράφεις out of bounds στον En. *w_count - 1 θα ήταν το σωστό γιατί zero-based indexing.

 

Δεύτερον δεν καταλαβαίνω γιατί κάνεις πρώτα μια μεγάλη malloc εδώ και στη συνέχεια (μετά τη scanf) κάνεις μια μικρότερη, και χωρίς να κάνεις free την προηγούμενη πρώτα. Αυτό είναι memory leak αν και δε μπορεί να προκαλέσει crash.

 

Επίσης, γράφεις σε διάφορα σημεία sizeof(char). Δεν ξέρω αν το κάνεις για να είναι "φανερά σωστός στον αναγνώστη" ο κώδικας, αλλά θα μπορούσες να το παραλείψεις γιατί αξιωματικά το sizeof(char) είναι πάντα 1.

 

ΥΓ

Νταξει, όποτε βγαίνει τέτοιο thread δε μπορώ να μη πεθάνω στα γέλια όταν θυμάμαι τις γνωστές συζητήσεις "να μάθουν C να έχουν υπόβαθρο". Εδώ το παλικάρι έχει παιδευτεί άπειρα (όλοι ξέρουμε πόσα έτη φωτός μακριά είναι τα realloc με διπλούς pointers από κάποιον αρχάριο) και ακόμα δεν έχει καταφέρει το πρόγραμμά του να κάνει τίποτα χρήσιμο.

 

Σε οποιαδήποτε λίγο φιλικότερη γλώσσα μετά από τόση δουλειά θα είμασταν στη φάση που θα είχαμε κάνει abstract τον container και δυναμικά επιλεγόμενο ανάμεσα σε arrays, linked lists και ότι άλλο αγαπάς για να τρέξουμε benchmarks να δούμε στην πράξη το big-oh των αλγορίθμων που θα είχαμε ήδη υλοποιήσει.

 

 

Δοκιμασα να κανω αυτο μου ειπες (με το *w_count-1) αλλα παλι εχω προβλημα.. Οσο για τις malloc που δε καταλαβαινεις τις εβαλα καταλαθος... (μου  χει καει το μυαλο λιγο με αυτο προγραμμα.. ). Το sizeof(char) ξερω οτι ειναι ενα απλα το κανω για να ναι πιο ξεκαθαρο..

Αρχιζω να πιστευω οτι κατι παιζει με τις realloc, ομως δε μπορω να βρω τι φταιει μεχρι τωρα..

Αμα εχεις καμια ιδεα θα ηθελα πολυ να την ακουσω. :-)

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημοσ. (επεξεργασμένο)

Τα realloc είναι λάθος. Σε τι ακριβώς κάνουν resize...;

Σε bytes... ή σε pointers...

 

Το En = (char**)realloc(En,sizeof(char* )*(*w_count));

Πετάει το παλιό En χάνεται...δεν ελευθερώνεται!

Επιπλέον σε κάθε νέα αντιγραφή επειδή γράφει "απ'έξω" από τον πίνακα το νέο δείκτη....θα πάρει τελικά ένα πίνακα όλο Null........

Επειδή κάπου το μικρότερο μπλοκ είναι 16 bytes...στα 1,2,3 ήδη έχουμε 16 Bytes και δεν υπάρχει πρόβλημα!

στη 4 λέξη φτιάχνει πάλι 16 bytes...και εμείς γράφουμε έξω από το μπλοκ! (στο +4 στοιχείο, δηλαδή το πέμπτο)

Επεξ/σία από M2000
  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Πετάει το παλιό En χάνεται...δεν ελευθερώνεται!

Μήπως να διάβαζες τι ακριβώς κάνει η realloc πρώτα?

 

Επιπλέον σε κάθε νέα αντιγραφή επειδή γράφει "απ'έξω" από τον πίνακα το νέο δείκτη....θα πάρει τελικά ένα πίνακα όλο Null........ Επειδή κάπου το μικρότερο μπλοκ είναι 16 bytes...στα 1,2,3 ήδη έχουμε 16 Bytes και δεν υπάρχει πρόβλημα!

στη 4 λέξη φτιάχνει πάλι 16 bytes...και εμείς γράφουμε έξω από το μπλοκ! (στο +4 στοιχείο, δηλαδή το πέμπτο)

Αυτό ίσως θέλεις να το εξηγήσεις λίγο καλύτερα επειδή δε βγάζει κανένα νόημα.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Πως δεν βγάζει νόημα...

When allocating any small blocks of memory, remember that the granularity for blocks allocated by the malloc library is 16 bytes. Thus, the smallest block of memory you can allocate is 16 bytes and any blocks larger than that are a multiple of 16

Εγώ το κατάλαβα πριν το διαβάσω εδώ:

https://developer.apple.com/library/mac/documentation/Performance/Conceptual/ManagingMemory/Articles/MemoryAlloc.html

Κοιτάμε πρώτα τι κάνει το realloc όχι το πώς εμείς καταλαβαίνουμε ότι κάνει. Φυσικά όπως το έχει γράψει φτιάχνει ένα πίνακα με δείκτες! Αυτό δεν είναι λάθος, αλλά στην πράξη τι κάνει; Πόσα bytes πιάνει;


ζητάει 1 του δίνει 4 το σύστημα εκείνος γράφει στο 2..κανένα πρόβλημα!

ζητάει 2 του δίνει 4 το σύστημα εκείνος γράφει στο 3..κανένα πρόβλημα!

ζητάει 3 του δίνει 4 το σύστημα εκείνος γράφει στο 4..κανένα πρόβλημα!

ζητάει 4 του δίνει 4 το σύστημα εκείνος γράφει στο 5..Crash!!!!!

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημοσ. (επεξεργασμένο)

Λοιπόν επειδή είναι απλά βαρετό να μιλάς με γεροσοφούς...

 

1. Η realloc κάνει free (για την ακρίβεια, η realloc κάνει ο,τι κάνει η malloc και ο,τι κάνει η free ξεχωριστά, μπορείς να γράψεις πρόγραμμα μόνο με realloc χωρίς malloc και χωρίς free απλά θα "φαίνεται λίγο περίεργο), σε αντίθεση μ' αυτό που είπες πριν. Το να μη ξέρεις τι κάνει η realloc σε γενικές γραμμές για μένα προσωπικά βάζει Χ σε οτιδήποτε άλλο έχεις να πεις περι memory management.

 

2. Δεν ξέρω αν το πρόσεξες αλλά το παλικάρι δε γράφει στο 5 γιατί όπως είπε την έκανε τη διόρθωση που πρότεινα και πάλι έχει crash.

 

3. Μόλις έτρεξα το πρόγραμμα, το crash συμβαίνει πριν την 4η προσπάθεια. Όχι ότι αυτό έχει σημασία γιατί βλέπε #2.

 

4. H συγκεκριμένη malloc της apple τυχαίνει να έχει granularity 16. Για τη malloc γενικότερα δε μπορείς να κάνεις τέτοια υπόθεση. Για την ακρίβεια, είναι σχεδόν σίγουρο ότι οποιαδήποτε malloc έχει διαφορετικό granularity σε debug και release mode compilation. Χωρίς να ξέρουμε πλατφόρμα και compiler settings δε μπορεί να γίνει κάποια υπόθεση τέτοιου είδους.

 

Τώρα...

 

Βλέποντας πάλι προσεκτικά βρήκα νομίζω και το τελευταίο και φαρμακερό bug της υπόθεσης.

 

Γενικό σχόλιο: θα γελάσει και το παρδαλό κατσίκι.

 

Hint για να μη το πάρει το ποτάμι αμέσως: γιατί είναι pointer η 3η παράμετρος της mem_alloc? Τι κοινό έχει με τις άλλες δύο παραμέτρους της? Και most importantly... τι δεν έχει κοινό μ' αυτές ενώ θα έπρεπε?

Επεξ/σία από defacer
  • Like 2
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δεν έχω χρησιμοποιήσει την C...αν και την έχω μελετήσει. Δέχομαι να με διορθώνεις. Δεν έχω πρόβλημα!

Τώρα που το "είπες"...το unsigned int *w_count   κάνει το w_count δείκτη οπότε η αύξηση ++ του δίνει +4 και όχι +1???

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

  • Moderators

Το ++ στους pointers αυξάνει κατά sizeof(type) (δεν έχω διαβάσει το standard και δεν ξέρω τι άλλο μπορεί να κάνει, απλώς αυτό ξέρω αυτό γράφω). Μπορείς να δεις εδώ.

  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Μ'αρεσει που κολλησατε με τα allocation. Εδω ζητανε απο το παλικαρι να γραψει λεξικο απο ελληνικα στα αγγλικα. Hello! Ελληνικα. 

  • Like 3
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

  • Moderators

Μ'αρεσει που κολλησατε με τα allocation. Εδω ζητανε απο το παλικαρι να γραψει λεξικο απο ελληνικα στα αγγλικα. Hello! Ελληνικα. 

 

O migf1 δεν είχε γράψει ένα μεγάλο post για unicode σε C;

  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

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