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

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


antonis1245

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

Ένα άλλο σημείο για να προσέξεις ειναι το θεματάκι που έχεις όπου κάποια μηνύματα τυπώνονται 2 φορές. Γνωρίζεις γιατί συμβαίνει αυτό;

 

Όσον αφορά το word_count, γνώμη μου είναι πως πρέπει να δηλωθεί μέσα στη συνάρτηση σαν static, και αν το χρειάζεται απ'έξω τότε να το επιστρέφει.


Επίσης εκεί που κάνεις διπλές malloc, θα μπορούσες στη θέση της δεύτερης malloc να βάλεις μία realloc. Επίσης, δε χρειάζεσαι το στατικά δεσμευμένο s.

 

Τέλος, δε βλέπω πουθενά να κάνεις free.

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

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

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

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

Πέρα από τις πολύ σωστές συμβουλές που έδωσαν τα άλλα παιδιά, να χρησιμοποιείς πάντα την πιο απλή δομή που λύνει το πρόβλημά σου. Αν μπορείς το λύσεις με μονό δείκτη, μην πας σε διπλό.

 

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

 

* Ακόμη και να μην κάνατε δομές, πάλι μπορείς να γλυτώσεις τους διπλούς δείκτες. Από ό,τι βλέπω, χρησιμοποιείς το σταθερό μέγεθος "s_size" δηλαδή 256 χαρακτήρες. Οπότε γιατί μπλέκεσαι με malloc και ιστορίες και δεν ορίζεις ένα απλό char (*En)[s_size] ώστε απλά να εκχωρείς μνήμη για κάθε λέξη που εισάγεται. Θα χρησιμοποιείς περισσότερη μνήμη βέβαια αλλά στο πλαίσιο της άσκησης, who cares.

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

 

 

Για κάποιο λόγο το (*En)[s_size] μου κάθεται στραβά. Μάλλον ψυχολογικό. Ήταν ένας κώδικας που έπρεπε να διαβάσω και ήταν χάλια γραμμένος. Μπερδεμένες δηλώσεις συναρτήσεων (Kernighan style μαζί με ANSI), καθόλου σχόλια, μεταβλητές του τύπου a1,a2,a3,x1,x2, και full pointers σε στατικούς πίνακες και όλος ο κώδικας σε ένα αρχείο. Τότε τα είδα πρώτη φορά να μαζί με όλο αυτό το σοκ, οπότε μόνο έτσι εξηγείται.

 

 

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

Για κάποιο λόγο το (*En)[s_size] μου κάθεται στραβά.

Πέρα από ότι είναι άσχημο, δεν είναι δυσνόητο. Τέλος πάντως, ας το ξεχάσουμε αυτό και ας δούμε αυτό που είπα με την δομή.

 

struct word {
    char en[s_size];
    char gr[s_size];
};

struct dict {
    unsigned int count;
    struct word *word;
};

void mem_alloc(struct dict *dict);

int main()
{
    struct dict dict;

    /* se kati pio prohgmeno auta 8a htan meros mia _init sinartisis alla gia edo einai peritto */
    dict.count = 0;
    dict.word = NULL;

    blah blah;

        switch(ch)
        {
            case '1': mem_alloc(&dict);
            break;
        }
        printf("\n Sum: %d",dict.count);
    free(dict.word);

    return 0;
}

/* asximo onoma, mia kai to nohma ths synarthshs den einai na kanei alloc
   alla na eisagei tis lekseis */
void mem_alloc(struct dict *dict)
{
    int i;
    int cnt;
    char s[s_size];
    struct word *tmp_word;

    cnt = dict->count;
    cnt++;

    /* anti gia dekapente malloc kai realloc, exoyme mono ena to opoio
       ekxorei mnimi gia mege8os *tmp_word diladi oso mia domi word
       * to plithos ton lekseon poy exoyme diladi to auksimeno kata ena cnt */
    tmp_word = realloc(dict->word, cnt * sizeof *tmp_word);
    if (tmp_word == NULL) {
        printf("Could Not Allocate Memory (1).\n");
        return;
    }
    dict->word = tmp_word;

    /* den peiraksa auto to komati kai afisa tis scanf */
    printf("Insert English Word: ");
    scanf("%s",s);
    strcpy(dict->word[cnt - 1].en, s);
    printf("Insert Greek Word: ");
    scanf("%s",s);
    strcpy(dict->word[cnt - 1].gr, s);

    //Test_point 1.
    // i changed to 0 from 1
    for(i = 0; i < cnt; i++)
       printf("Word %d\n%s = %s\n",i, dict->word[i].en, dict->word[i].gr);

    dict->count = cnt;
}
Το 90% της συνάρτησης του op αναλωνόταν στην εκχώρηση μνήμης και το 10% στον πραγματικό σκοπό της συνάρτησης που ήταν η εισαγωγή των λέξεων.

 

Επίσης, εφόσον μιλάμε για στατικό μέγεθος s_size, δεν χρειαζόταν καν η ενδιάμεση μεταβλητή s και θα μπορούσε η scanf να γίνεται κατευθείαν με τα en/gr.

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

Κάτι είναι αυτό! Αλλά η λογική πρέπει να έχει και άλλα πράγματα όπως π.χ. πώς γίνεται να ΜΗΝ γράψει την ίδια λέξη δυο φορές!

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

Κάτι είναι αυτό! Αλλά η λογική πρέπει να έχει και άλλα πράγματα όπως π.χ. πώς γίνεται να ΜΗΝ γράψει την ίδια λέξη δυο φορές!

Το έκανε αυτό ο αρχικός κώδικας ?

 

Εγώ πήρα αυτό που είδα και το έγραψα με πιο απλό (τουλάχιστον κατά τη γνώμη μου πιο απλό. ίσως είναι δυσνόητος ο κώδικάς μου) τρόπο. Από εκεί και πέρα το τι μπορεί να γίνει γενικά είναι αλλουνού παπά.

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

Δεν έχω ένσταση για το κώδικα που έβαλες παραπάνω! Τίποτα δεν είναι απλό ακόμα και ένα λεξικό!

Αλλά αν θες μπορώ να κάνω την ένστασή μου!

Π.χ. έχεις βάλει μόνιμο μέγεθος στο στοιχείο των λέξεων. Δηλαδή το size_s. Μικρή μεγάλη θα είναι το ίδιο. Βολεύει για να παρουσιάσεις το πρόγραμμα. Αλλά δεν βολεύει με την έννοια της δυναμικής καταχώρησης της μνήμης.

Με το σκεπτικό ότι δεν κοιτάμε τι καταχωρούμε..θα αρκούσε ένας απλός πίνακας char με ένα μέγεθος 1000*size_s και αντί να βάζουμε τις λέξεις με δείκτη, θα τις βάζαμε..άμεσα με strcpy(). Απλά θα κρατάμε σε μια μεταβλητή την επόμενη κενή θέση...Ένας έλεγχος για το γέμισμα χρειάζονταν αν η λέξη που θα βάλουμε απαιτεί περισσότερο χώρο και τότε θα δίναμε "άλλο τόσο" (όπως είναι η πρακτική).

Για να διαβάσουμε το πίνακα..θα ήταν ακόμα πιο εύκολο, Διαβάζουμε από μια θέση Α και το μήκος του αλφαριθμητικού συν ένα για το μηδέν το προσθέτουμε στο Α και πέρνουμε το επόμενο.  Μάλιστα αν θέλουμε ρίχνουμε και ένα 0 στη θέση "νέας" εγγραφής" σαν σκοπός και δεν κοιτάμε άλλη συνθήκη παρά αν έχουμε κενό αλφαριθμητικό!

 

(η C για αυτά τα κόλπα είναι φτιαγμένη)

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

Και μετά μόλις θέλεις να κάνεις κάτι περισσότερο από insert και linear search τα ξηλώνεις όλα και το κάνεις διαφορετικά. Ο ορισμός του premature optimization?

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

Δεν έχω ένσταση για το κώδικα που έβαλες παραπάνω! Τίποτα δεν είναι απλό ακόμα και ένα λεξικό!

Αλλά αν θες μπορώ να κάνω την ένστασή μου!

Π.χ. έχεις βάλει μόνιμο μέγεθος στο στοιχείο των λέξεων. Δηλαδή το size_s. Μικρή μεγάλη θα είναι το ίδιο. Βολεύει για να παρουσιάσεις το πρόγραμμα. Αλλά δεν βολεύει με την έννοια της δυναμικής καταχώρησης της μνήμης.

Με το σκεπτικό ότι δεν κοιτάμε τι καταχωρούμε..θα αρκούσε ένας απλός πίνακας char με ένα μέγεθος 1000*size_s και αντί να βάζουμε τις λέξεις με δείκτη, θα τις βάζαμε..άμεσα με strcpy(). Απλά θα κρατάμε σε μια μεταβλητή την επόμενη κενή θέση...Ένας έλεγχος για το γέμισμα χρειάζονταν αν η λέξη που θα βάλουμε απαιτεί περισσότερο χώρο και τότε θα δίναμε "άλλο τόσο" (όπως είναι η πρακτική).

Για να διαβάσουμε το πίνακα..θα ήταν ακόμα πιο εύκολο, Διαβάζουμε από μια θέση Α και το μήκος του αλφαριθμητικού συν ένα για το μηδέν το προσθέτουμε στο Α και πέρνουμε το επόμενο.  Μάλιστα αν θέλουμε ρίχνουμε και ένα 0 στη θέση "νέας" εγγραφής" σαν σκοπός και δεν κοιτάμε άλλη συνθήκη παρά αν έχουμε κενό αλφαριθμητικό!

 

(η C για αυτά τα κόλπα είναι φτιαγμένη)

Μαζί με αυτό όμως πρέπει να υπάρχει και το ανάλογο documentation (το οποίο πρέπει να είναι εκτενέστατο). Στην άλλη περίπτωση όμως, ο κώδικας είναι self documented. Δε χρειάζεται καν να τον δω για να καταλάβω τί κάνει.

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

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

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main()
{
    char *word, *name, *top, *buf, *limit, *temp;
    const int s_size=255, m_page=20;
    char  label[][100]= {"Enter a Greek phrase/word: ","Enter an English phrase/word: "};
    int k=10, p=1;
    buf=malloc(s_size);
    name=malloc(p*m_page+1);
    limit=name+m_page*p;
    top=name;
    word=name;
    do {
    printf("%s",label[k % 2]);
    scanf("%[^\n]%*c",buf);
    if(strlen(buf)>0) {
        top+=strlen(buf)+1;
        if(top>limit) {
                p+=(top-limit)/m_page+1;
                temp=realloc(name,p*m_page+1);
                if (!temp) break;
                word+=temp-name; //realocate
                top+=temp-name;  //realocate
                limit=name+m_page*p;
                name=temp;
        }
        strcpy(word, buf);
        strcpy(buf,"");  // if you forget it...you have a problem
        printf("Your phrase is: %s\n",word);
        word=top;

     } else { k=1;
        printf("Look this %d 2\n", k);
     }
    k--;
    printf("%d\n", k);
    }while(k>0);
    printf("Now we see what we have\n");
    word=name;
    strcpy(top,"");  // guard
    k=strlen(word);
    while(k>0) {
        printf("%s\n",word);
        word+=k+1;
        k=strlen(word);
    }
    free(name);
    free(buf);
    return 0;
}

Αυτό είναι και το πρώτο μου πρόγραμμα σε C...!

το m_page το έχω 20 αλλά μπορεί κανείς να το βάλει 4096

Δουλεύει κανονικά με ελληνικά!

Τροποποίησα λίγο το πρόγραμμα (δούλευε παρόλο που είχα ξεχάσει την limit να την υπολογίσω ξανά)

 Να και τα ελληνικά!

Δοκίμασα με page 50000 και αλλαγή σε κάθε καταχώρηση.

Δουλεύει με -= και όχι με +=. Όσο η μνήμη είναι κάτω από το 64k δεν δίνει άλλο μπλοκ η realloc. Μόλις περάσουμε το 64k αλλάζει και τη βάση (εδώ name). Πίστευα ότι με += θα δουλέψει!

  • word+=temp-name; //realocate
  • top+=temp-name; //realocate

post-370421-0-19064100-1452124375_thumb.png

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

Το μελέτησα το θέμα...

προσοχή όταν δίνουμε σε ένα δείκτη ένα literal string αυτό που δίνουμε είναι μια διεύθυνση εκεί όπου ΔΕΝ μπορούμε να γράψουμε.

π.χ

char *alfa;

alfa="George";

strcpy(alfa,"Hello");   // αυτό είναι σφάλμα

 

Το "George" ο compiler το έχει βάλει σε σημείο που είναι Read Only. και δίνει μια διεύθυνση (βάζει και το 0 στο τέλος του αλφαριθμητικού). Αν θέλουμε να γράψουμε ένα αλφαριθμητικό...πρέπει να δώσουμε ένα χώρο εκεί που ΔΕΝ είναι READ ONLY.

Αυτό μας το κάνει ο malloc() ή ο realloc().  Η διαφορά είναι ότι πρέπει να απελευθερώνουμε την παροχή μνήμης με τη free. Πώς ξέρει το σύστημα ποια μνήμη απελευθερώνουμε; Όταν την δημιουργούμε μας δίνει μια διεύθυνση. Αυτή είναι ταυτόχρονα και handler. Αν την γράψουμε σε μια μεταβλητή που είναι δείκτης (π.χ. μια char *pointer) τότε με free(pointer) θα την απελευθερώσουμε. Όμως στο παράδειγμα παραπάνω, το alfa δεν είναι handler block μνήμης, αλλά μόνο διεύθυνση. Οπότε μια free(alfa); θα βγάλει λάθος.

Αν έχουμε φτιάξει ένα μπλοκ όπως στο μεγάλο παράδειγμα πιο πριν, μπορούμε να αντιγράψουμε το δείκτη (διεύθυνση) σε άλλους δείκτες. Π.χ. στο top και στο word. Δεν έχουμε εδώ αντικείμενα με καταμέτρηση αναφορών. Μπορούμε να προσθέτουμε δυο δείκτες και θα πάρουμε δείκτη! Αυτό που παρατήρησα ήταν ότι η realloc όσο η μνήμη είναι διαθέσιμη στην "ευθεία" της, δεν αλλάζει handler, και η διαφορά temp-name...ήταν μηδέν! Το τσέκαρα στο Linux προσθέτοντας 50000 bytes σε κάθε εγγραφή! Μάλιστα έκανα και την "πατέντα" να περάσω αμέσως μετά τα πρώτα 50000 μια μνήμη 200000bytes..ώστε να του κόψω τη φόρα..να μην βάλει σελίδα αμέσως μετά! Το Linux αν το πιέσεις πολύ...δηλαδή του ζητήσεις πολύ πράγμα τότε το διευκολύνεις...διότι δεν κάνει καν αντιγραφή, αλλά δίνει απ' ευθείας σελίδα, δηλαδή ενημερώνει ένα ακέραιο κάπου!

Δεν τα βγάζω από το μυαλό μου! Δείτε Link.png Site: εδώ


Σε Μ2000 είναι πιο κατανοητός ο κώδικας! Αλλά σεβασμός στη C (είναι η μάνα γλώσσα που έβγαλε το καμάρι το C++)

 

Σελ=4 : Σελ_νο=1
Πίνακας Ον$(2), Λεξ$(Σελ*Σελ_νο)
Ον$(0)="Δώσε Ελληνική λέξη ή φράση","Δώσε Αγγλική λέξη ή φράση"
Όριο=Διάσταση(Λεξ$(),1)
Κ=10
κορυφή=0
Ενώ Κ>0 {
      Τύπωσε Ον$(κ υπολ 2);
      Αν κορυφή>=Όριο τότε Σελ_νο++ : Πίνακας Λεξ$(Σελ*Σελ_νο) : Όριο=Διάσταση(Λεξ$(),1)
      Δες οκ {
            Εισαγωγή ": ", Λεξ$(κορυφή)
      }
      Αν Λεξ$(κορυφή)="" ή όχι οκ τότε έξοδος
      κορυφή++
      Κ--
}
Τύπωσε "Να δούμε τι έχουμε"
Αν κορυφή >0 τότε {
      Για ι=0 έως κορυφή {
            Τύπωσε Λεξ$(ι)
      }
}

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

Μπορούμε να προσθέτουμε δυο δείκτες και θα πάρουμε δείκτη!

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

 

Μπορείς όμως να αφαιρέσεις δύο pointers (μόνο υπό συγκεκριμένες συνθήκες αλλιώς UB), και εκεί το αποτέλεσμα έχει νόημα.

 

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

Όλα τα μοντέρνα λειτουργικά αυτό κάνουν.

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

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

 

Μπορείς όμως να αφαιρέσεις δύο pointers (μόνο υπό συγκεκριμένες συνθήκες αλλιώς UB), και εκεί το αποτέλεσμα έχει νόημα.

 

Όλα τα μοντέρνα λειτουργικά αυτό κάνουν.

Χαρά στο κουράγιο σου. Ήρθαν πόσες ειδοποιήσεις για τα edits, και κάθε φορά έβλεπα να προστίθεται ακόμη μία ανακρίβεια στο σωρό των προηγούμενων. Ξεκίνησα τρεις - τέσσερις φορές να γράψω σχόλια αλλά σταμάτησα με το σκεπτικό ότι τι να πρωτο-σχολιάσω. Πρώτη φορά βλέπω μηνύματα με τόσες ανακρίβειες και γενικά τόσο μικρό νόημα μέσα σε τόσο πολύ θόρυβο. Μέχρι και τα μηνύματα του starlight μεγαλύτερο snr είχαν.

 

Έκανα ignore το μεσημέρι και ησύχασα.

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

Όχι το περιεχόμενο των δεικτών, αλλά τους δείκτες ως διευθύνσεις, μέσω offset. Αν πρόσεξες προσθέτω αυτό που λέμε offset.

Τώρα κάτι ήθελε να πει ο ημίθεος...και λέει ότι είδε ένα σωρό ανακρίβειες και κολοκύθια.

Βάλε στο νου σου ότι είναι το πρώτο πρόγραμμα σε C που γράφω!

Εγώ βλέπω ότι δουλεύει! Και σε αυτό ο "ημίθεος" έκανε την πάπια!

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

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