Avatar billede mbm2016 Nybegynder
23. december 2009 - 19:16 Der er 38 kommentarer og
1 løsning

C++ Hukommelses allokering

Hej eksperter,

Jeg har lavet en kode som laver en hukommelses blok med plads til 2 heltal. Problemet er bare at når jeg så sætter hver hukommelses plads til et heltal, så kan jeg også sætte et tal å plads 3 og der op af, selvom jeg kun har allokeret plads til 2.

Derefter reallokerer jeg så der kun er plads til 1 heltal, og tildeler derefter et heltal til 3 pladser mere, stadig ingen access violation. Dt fprstår jeg ikke?

Min kode:

int * hej = (int *)malloc(sizeof(int)*2);
    *(hej) = 10;
    *(hej+1) = 20;
    *(hej+2) = 30;

    realloc(hej,sizeof(int));

    *(hej+3) = 10;
    *(hej+4) = 20;
    *(hej+5) = 30;


    for(int i = 0;i<6;i++)
    cout << *(hej+i) << endl;


På forhånd mange tak for hjælpen
Avatar billede arne_v Ekspert
23. december 2009 - 19:23 #1
C *kan* give dig en access violation hvis du bruger memory som ikke er korrekt allokeret, men C *garanterer ikke* at give dig en access violation.
Avatar billede arne_v Ekspert
23. december 2009 - 19:23 #2
D.v.s. at du kan sagtens have et C program som virker fint og saa efter en opdatering af Windows som smider nye C RTL implementation ind faar du fejl.
Avatar billede arne_v Ekspert
23. december 2009 - 19:25 #3
Din brug af realloc er ioevrigt ikke korrekt. Du skal bruge den returnerede varedi i tilfaelde af at realloc flytter rundt paa data.
Avatar billede arne_v Ekspert
23. december 2009 - 19:35 #4
Du kan f.eks. proeve at koere dette program:

#include <stdio.h>

int main()
{
    int a;
    int b[1];
    a = 123;
    b[1] = 456;
    printf("%d\n", a);
    return 0;
}

Principielt kan der ske hvad som helst naar det koerer, men typisk vil der ske en af 3:

* det crasher fordi b[1] er et sted i memory som man ikke har adgang til
* det udskriver 456 fordi b[1] er a
* det udskriver 123 fordi b[1] er et validt sted i memory forskelligt fra a
Avatar billede mbm2016 Nybegynder
23. december 2009 - 20:05 #5
Hej arne,

Jeg har nu ændre tlit i min kode. Hehh ja jeg kan godt se det med realloc ;)

int * hej = (int *)malloc(sizeof(int)*3);
    *(hej) = 10;
    *(hej+1) = 20;
    *(hej+2) = 30;

    hej = (int *)realloc(hej,sizeof(int));
    if(hej == NULL)
    {
        cout << "Ikke mere hukommelse!";
        exit(0);
    }

    *(hej+3) = 10;
    *(hej+4) = 20;
    *(hej+5) = 30;


    for(int i = 0;i<6;i++)
    cout << *(hej+i) << endl;


Men hvis jeg nu allokerer plads til 5 ints og bagefter bruger realloc til at reducere pladsen til 2 ints, kan dette lade sig gøre?

Hvsi ja kan det så lade sig gøre uden at realloc måske flytter det rundt i hukommelsen?
Avatar billede arne_v Ekspert
23. december 2009 - 20:17 #6
*(hej+3) = 10;
    *(hej+4) = 20;
    *(hej+5) = 30;


    for(int i = 0;i<6;i++)
    cout << *(hej+i) << endl;

er jo stadig gal da de gaar ud over arrayet, som paa det tidspunkt kun har et element.
Avatar billede arne_v Ekspert
23. december 2009 - 20:19 #7
Hvis du spoerger om hvorvidt realloc naar arrayet bliver mindre altid vil genbruge pladsen d.v.s. ikke aendrer pointeren, saa tvivler jeg - C plejer at overlade den slags til implementationen, men for at vaere sikker vil jeg skulle checke C standarden og POSIX stanrdarden.
Avatar billede mbm2016 Nybegynder
23. december 2009 - 21:59 #8
Okay nu tror jeg jeg har koden korrekt:

    int * hej = (int *)malloc(sizeof(int)*3);
    *(hej) = 10;
    *(hej+1) = 20;
    *(hej+2) = 30;

    hej = (int *)realloc(hej,sizeof(int));
    if(hej == NULL)
    {
        cout << "Ikke mere hukommelse!";
        exit(0);
    }

    *(hej) = 10;

    cout << *(hej) << endl;


Er denne kode gangbar?

og lige et spørgsmål mere: Når jeg bruger realloc til at reducere array´ets størrelse til 1 vil data allokeret på pladserne 2 og 3 osv. blive frigjrt for andre applikationer samt sat til 0?
Avatar billede arne_v Ekspert
24. december 2009 - 00:22 #9
Den kode ser OK ud.

Jeg ville bruge array syntax fremfor pointer syntax d.v.s.:

    int * hej = (int *)malloc(sizeof(int)*3);
    hej[0] = 10;
    hej[1] = 20;
    hej[2] = 30;

men det er kun et spørgsmål om at jeg synes at det er pænere.
Avatar billede arne_v Ekspert
24. december 2009 - 00:25 #10
C programmer opererer på virtuel hukommelse. Hver applikation har sit eget virtuelle adresserum. Memory som frigives via free eller realloc er virtuel hukommelse som frigives til anden brug i samme applikation. Styresystemet håndterer så mapningen fra virtuel hukommelse til RAM og page file og allokerer RAM og page fil mellem de forskellige applikationer.
Avatar billede arne_v Ekspert
24. december 2009 - 00:27 #11
Hukommelsen bliver ikke nødvendigvis sat til nul ved frigivelse. Den bliver ikke engang nødvendigvis sat til nul ved allokering med malloc eller realloc !

Man skal bruge calloc for at være sikker på at det er nul.
Avatar billede mbm2016 Nybegynder
24. december 2009 - 13:48 #12
okay mange tak arne jeg giver point ;)
Avatar billede mbm2016 Nybegynder
24. december 2009 - 14:23 #13
Jeg har nu udfra disse funktioner udarbejdet en klasse kaldet List<type>, som jeg synes er bedre end vector<type>

Hvis du har lyst kan du kigge på den:
http://www.magnusbm.dk/kodenlist.htm
Avatar billede arne_v Ekspert
24. december 2009 - 14:34 #14
et svar

jeg kigger lidt paa koden senere
Avatar billede arne_v Ekspert
25. december 2009 - 18:39 #15
Kommentarer til koden:

* jeg er ikke overbevist om at alle de typedef's giver mening - dette er C/C++ ikke Pascal/Modula-2/Ada

* det virker ikke smart at Count of Capacity er public

* når nu det er C++ og ikke C, hvorfor så ikke bruge new/delete fremfor malloc/free

* algoritment med at +10 til Capacity er nok ikke optimal *2 er nok bedre

* mange steder mener jeg at array syntax fremfor pointer syntax vil være mere læseligt

* jeg tror ikke at det er godt at reducere Capacity ved Remove

* undgå at assigne til variable i argumenter, det gør koden meget svær at følge

* din Reverse algoritme kan vist forbedres

* operator == bør nok kalde Equals for at undgå duplikering af kode

* hvorfor returnerer GetType sizeof ??

* nogen kommentarer i koden vill nok være nyttige
Avatar billede mbm2016 Nybegynder
25. december 2009 - 23:27 #16
Hej Arne, mange tak for dine kommentarer.

Jeg har dog nogle spørgsmål.


Hvorfor er det ikke godt at reducere Capacity ved Remove?
Hvad nu hvis det er et system med meget lidt hukommelse. Jeg går ud fra at realloc frigiver hukommelsen, når man reducerer størrelsen på array'et.


Du skriver: undgå at assigne til variable i argumenter, det gør koden meget svær at følge
Skal jeg så overloade kontruktøren, så man kan initialisere både med og uden specifikation af ønsket capacity?


Angående Reverse funktionen, så har jeg siddet og glukket lidt på den, og det ser ikke ud til at det bliver meget bedre det jeg er kommet frem til. Jeg ville være glad for en uddybning her :)


Min GetType funktion returnere størrelsen på den type man har gang i :) Jeg kunne nemlig ikke tænke mig til en smartere løsning?


Endnu engang tak for svarene

/Magnus
Avatar billede arne_v Ekspert
25. december 2009 - 23:42 #17
re Capacity & Remove)

realloc frigiver hukommelsen til C RTL (d.v.s. til nye malloc/new kald), men formentlig ikke til OS.

Argumentet for ikke at gøre det er at:
- sandsynligvis er den hukommelses mængde vi snakker om ubetydelig
- sandsynligvis skal der tilføjes senere, så den her frigivelse resulterer sandsynligvis i et stort antal kopieringer frem og tilbage fordi Capacity hele tiden ændres
Avatar billede arne_v Ekspert
25. december 2009 - 23:44 #18
re undgå assigne i argumenter)

Default argumenter såsom:

List<T>::List(Amount startcapacity = 10)

er helt fint.

Men:

Array = (T*)realloc(Array,sizeof(T)*(Capacity = Capacity+10));

er svær at læse, da man nem overser at Capacity faktisk ændres.
Avatar billede arne_v Ekspert
25. december 2009 - 23:46 #19
re reverse)

Du kopierer data 3-4 gange i din implementation.

Det må være nemmere at:
- bytte først og sidst
- bytte næstførst og næstsidste
...
Avatar billede arne_v Ekspert
25. december 2009 - 23:47 #20
re GetType)

Så kald den GetElementSize eller noget lignende.

Med GetType forventer man vel at få noget som identificerer typen.
Avatar billede mbm2016 Nybegynder
25. december 2009 - 23:53 #21
Hej arne tak for svarene.

Det vil sige at jeg bare skal hive tildelingen af capacity ud, så det er mere læsbart, og lave tildelingen ovenover?

Jeg må indrømme at din pseudo kode til reverse funktionen forvirrer mig lidt, men det er nok fordi jeg har siddet i loddetinsrøg hele dagen ;) (Det er midnat ;))

Jeg har nogle flere spørgsmål :)

Hvis jeg skal bruge nøgelordene new og delete, hvordan kan jeg så lave min insert funktion hvis jeg ikke måtte bruge malloc, memmove osv?

Hvis jeg allokerer sådan her:
char * chars = new char[100]; // Allokere plads til hundrede

hvis jeg så lige bagefter går sådan her:
chars = new char[200]; // Allokere plads til 200


Kommer der så plads til 300? Og er det så det samme som at bruge realloc, og kan man godt reducerer char array'et f.eks sådan her:
char * chars = new char[100];
chars = new char[10];

puha det var mange spørgsmål ;)

Men hvis man ikke spørger lærer man ikke en skid ;)

/Magnus
Avatar billede arne_v Ekspert
25. december 2009 - 23:58 #22

Det vil sige at jeg bare skal hive tildelingen af capacity ud, så det er mere læsbart, og lave tildelingen ovenover?


Ja.


Hvis jeg skal bruge nøgelordene new og delete, hvordan kan jeg så lave min insert funktion hvis jeg ikke måtte bruge malloc, memmove osv?

Hvis jeg allokerer sådan her:
char * chars = new char[100]; // Allokere plads til hundrede

hvis jeg så lige bagefter går sådan her:
chars = new char[200]; // Allokere plads til 200


Kommer der så plads til 300? Og er det så det samme som at bruge realloc, og kan man godt reducerer char array'et f.eks sådan her:
char * chars = new char[100];
chars = new char[10];


Nej. En new er en malloc ikke en realloc. Så du vil selv skulle kopiere.
Avatar billede arne_v Ekspert
25. december 2009 - 23:59 #23
Hm - DIV er vist bedre end SPAN !!

Men du kan nok gætte hvad der skal stå.
Avatar billede mbm2016 Nybegynder
26. december 2009 - 00:05 #24
Ja hehh, Span kan ikke lide linjeskift -> http://www.eksperten.dk/guide/1325

Jeg forstår ikke helt hvad det er du mener med at kopiere?

Og er det noget som helst forkert ved at bruge malloc og realloc?

Jeg kan ikke se hvordan jeg kan videreføre/bruge realloc's funktionalitet, når jeg kun har new og delete at operere med?
Avatar billede arne_v Ekspert
26. december 2009 - 00:09 #25

Jeg må indrømme at din pseudo kode til reverse funktionen forvirrer mig lidt, men det er nok fordi jeg har siddet i loddetinsrøg hele dagen ;) (Det er midnat ;))


Eksempel:

#include <iostream>
#include <string>

using namespace std;

template<typename T>
void reverse(T *a, int n)
{
    for(int i = 0; i < n/2; i++)
    {
        T tmp = a[i];
        a[i] = a[n - 1 - i];
        a[n - 1 - i] = tmp;
    }
}

template<typename T>
void print(T *a, int n)
{
    for(int i = 0; i < n; i++)
    {
        cout << a[i] << endl;
    }
}

int main()
{
    int ia[] = { 1, 2, 3, 4};
    string sa[] = { "A", "BB", "CCC" };
    print(ia, 4);
    print(sa, 3);
    reverse(ia, 4);
    reverse(sa, 3);
    print(ia, 4);
    print(sa, 3);
    return 0;
}
Avatar billede arne_v Ekspert
26. december 2009 - 00:12 #26
Jeg forstår ikke helt hvad det er du mener med at kopiere?


realloc = new + memcopy + delete

Og er det noget som helst forkert ved at bruge malloc og realloc?


De er C funktioner ikke C++ operatorer.

Med new slipper du for cast, gange med sizeof, test for NULL (den smider exception) etc..
Avatar billede mbm2016 Nybegynder
26. december 2009 - 00:22 #27
Det vil sige at hvis jeg skal lave noget realloc skal jeg gære sådan her:

char * chars = new char[100];
char * charsreduced = new char[50];
memcpy(charsreduced,chars,sizeof(char)*50);
delete chars;
Avatar billede arne_v Ekspert
26. december 2009 - 03:19 #28
Ja.

Bortset fra at:
- sizeof(char) altid er 1 og derfor overflødig
- du skal bruge delete[] ikke delete
Avatar billede mbm2016 Nybegynder
26. december 2009 - 11:27 #29
Men er det okay at bruge memcpy memmove osv. bare ikke malloc og realloc?

Og hvorfor skal det være så besværligt at realloc i c++?

Kunne man lave sin egen realloc funktion til c++ sådan her: ?

template <typename T>
T * Realloc(void * pointer,int pointersize, int newsize)
{
    T * charsreduced = new T[50];
    memcpy(charsreduced,pointer,pointersize);
    delete[] chars;
    return charsreduced;
}

Igen igen rigtig mange tak for din tålmodighed ;)
Avatar billede arne_v Ekspert
26. december 2009 - 14:28 #30
Problemet med memcpy / memmove er nok det som jeg ikke nævnte for malloc/free: constructor/destructor.
Avatar billede arne_v Ekspert
26. december 2009 - 14:33 #31
Prøv og kør dette her:

#include <iostream>
#include <cstdlib>

using namespace std;

class X
{
    public:
        X() { cout << "Constructor called" << endl; }
        ~X() { cout << "Destructor called" << endl; }
};

int main()
{
    cout << "malloc & free" << endl;
    X *o1 = (X *)malloc(sizeof(X));
    free(o1);
    X *a1 = (X *)malloc(3*sizeof(X));
    free(a1);
    cout << "new & delete" << endl;
    X *o2 = new X();
    delete o2;
    X *a2 = new X[3];
    delete[] a2;
    return 0;
}
Avatar billede arne_v Ekspert
26. december 2009 - 14:34 #32
memcpy/memmove kan være superfarlig, hvis en class indeholder pointere fordi copy constructoe / assignment operator ikke bliver kaldt.
Avatar billede arne_v Ekspert
26. december 2009 - 14:35 #33
Din kode i #29 forstår jeg ikke.
Avatar billede mbm2016 Nybegynder
26. december 2009 - 17:14 #34
Den kode i 29 skulle være en erstatning for realloc

okay så hvis jeg bruger nøgleordet new, hvordan reallokere jeg så uden brug af memcpy, memmmove etc.?
Avatar billede arne_v Ekspert
26. december 2009 - 20:54 #35
Hvis du bruger en for løkke og klassen har defineret en assignment operator, så tror jeg at det virker som det skal.
Avatar billede arne_v Ekspert
26. december 2009 - 21:40 #36
Prøv og sammenlign:

#include <iostream>
#include <cstring>

using namespace std;

class X
{
    private:
        char *p;
    public:
        X() { p = new char[3]; cout << (long)p << " new" << endl; strcpy(p, "X"); }
        ~X() { cout << (long)p << " delete" << endl; delete[] p; }
        void M() { cout << (long)p << " use" << endl; cout << p << endl; }
};

int main()
{
    X *a = new X[3];
    X *b = new X[2];
    memcpy(b, a, 2*sizeof(X));
    delete[] a;
    for(int i = 0; i < 2; i++) b[i].M();
    delete[] b;
    return 0;
}


med:

#include <iostream>
#include <cstring>

using namespace std;

class X
{
    private:
        char *p;
    public:
        X() { p = new char[3]; cout << (long)p << " new" << endl; strcpy(p, "X"); }
        ~X() { cout << (long)p << " delete" << endl; delete[] p; }
        void M() { cout << (long)p << " use" << endl; cout << p << endl; }
        void operator=(const class X& o) { strcpy(p, o.p); }
};

int main()
{
    X *a = new X[3];
    X *b = new X[2];
    for(int i = 0; i < 2; i++) b[i] = a[i];
    delete[] a;
    for(int i = 0; i < 2; i++) b[i].M();
    delete[] b;
    return 0;
}
Avatar billede mbm2016 Nybegynder
05. januar 2010 - 16:04 #37
Jeps, jeg må indrømme at jeg ikke kan se logikken i koden, ikke fordi den er forkert, men nok fordi min hjerne ikke kan kapere hukommelses programmering i det hele taget. Jeg lukker, bukker og takker for hjælpen arne ;)

Bare læg et svar så får du point ;)
Avatar billede mbm2016 Nybegynder
05. januar 2010 - 16:05 #38
Hvad skete der lige der! ;)

Jeg har givet point ;)
Avatar billede arne_v Ekspert
06. januar 2010 - 03:57 #39
Hm.

Måske kan jeg tilføje lidt mere debug output.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester