Oprettet ons. d. 23. december 2009 kl. 19:16:32

mbm2007
mbm2007 (8.387 point. Point ude: 30)
www.magnusbm.dk

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

Skrevet ons. d. 23. december 2009 kl. 19:23:01| #1

arne_v
arne_v (1.016.169 point)
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.

Skrevet ons. d. 23. december 2009 kl. 19:23:48| #2

arne_v
arne_v (1.016.169 point)
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.

Skrevet ons. d. 23. december 2009 kl. 19:25:14| #3

arne_v
arne_v (1.016.169 point)
Din brug af realloc er ioevrigt ikke korrekt. Du skal bruge den returnerede varedi i tilfaelde af at realloc flytter rundt paa data.

Skrevet ons. d. 23. december 2009 kl. 19:35:36| #4

arne_v
arne_v (1.016.169 point)
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

Skrevet ons. d. 23. december 2009 kl. 20:05:54| #5

mbm2007
mbm2007 (8.387 point)
www.magnusbm.dk
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?

Skrevet ons. d. 23. december 2009 kl. 20:17:46| #6

arne_v
arne_v (1.016.169 point)
*(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.

Skrevet ons. d. 23. december 2009 kl. 20:19:23| #7

arne_v
arne_v (1.016.169 point)
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.

Skrevet ons. d. 23. december 2009 kl. 21:59:31| #8

mbm2007
mbm2007 (8.387 point)
www.magnusbm.dk
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?

Skrevet tor. d. 24. december 2009 kl. 00:22:42| #9

arne_v
arne_v (1.016.169 point)
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.

Skrevet tor. d. 24. december 2009 kl. 00:25:35| #10

arne_v
arne_v (1.016.169 point)
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.

Skrevet tor. d. 24. december 2009 kl. 00:27:01| #11

arne_v
arne_v (1.016.169 point)
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.

Skrevet tor. d. 24. december 2009 kl. 13:48:03| #12

mbm2007
mbm2007 (8.387 point)
www.magnusbm.dk
okay mange tak arne jeg giver point ;)

Skrevet tor. d. 24. december 2009 kl. 14:23:28| #13

mbm2007
mbm2007 (8.387 point)
www.magnusbm.dk
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/ (...)

Skrevet tor. d. 24. december 2009 kl. 14:34:33| #14

arne_v
arne_v (1.016.169 point)
et svar

jeg kigger lidt paa koden senere

Skrevet fre. d. 25. december 2009 kl. 18:39:11| #15

arne_v
arne_v (1.016.169 point)
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

Skrevet fre. d. 25. december 2009 kl. 23:27:02| #16

mbm2007
mbm2007 (8.387 point)
www.magnusbm.dk
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

Skrevet fre. d. 25. december 2009 kl. 23:42:24| #17

arne_v
arne_v (1.016.169 point)
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

Skrevet fre. d. 25. december 2009 kl. 23:44:12| #18

arne_v
arne_v (1.016.169 point)
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.

Skrevet fre. d. 25. december 2009 kl. 23:46:12| #19

arne_v
arne_v (1.016.169 point)
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
...

Skrevet fre. d. 25. december 2009 kl. 23:47:01| #20

arne_v
arne_v (1.016.169 point)
re GetType)

Så kald den GetElementSize eller noget lignende.

Med GetType forventer man vel at få noget som identificerer typen.

Skrevet fre. d. 25. december 2009 kl. 23:53:31| #21

mbm2007
mbm2007 (8.387 point)
www.magnusbm.dk
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

Skrevet fre. d. 25. december 2009 kl. 23:58:12| #22

arne_v
arne_v (1.016.169 point)

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.

Skrevet fre. d. 25. december 2009 kl. 23:59:18| #23

arne_v
arne_v (1.016.169 point)
Hm - DIV er vist bedre end SPAN !!

Men du kan nok gætte hvad der skal stå.

Skrevet lør. d. 26. december 2009 kl. 00:05:52| #24

mbm2007
mbm2007 (8.387 point)
www.magnusbm.dk
Ja hehh, Span kan ikke lide linjeskift -> http://www.eksperten.dk/ (...)

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?

Skrevet lør. d. 26. december 2009 kl. 00:09:12| #25

arne_v
arne_v (1.016.169 point)

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;
}

Skrevet lør. d. 26. december 2009 kl. 00:12:52| #26

arne_v
arne_v (1.016.169 point)
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..

Skrevet lør. d. 26. december 2009 kl. 00:22:10| #27

mbm2007
mbm2007 (8.387 point)
www.magnusbm.dk
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;

Skrevet lør. d. 26. december 2009 kl. 03:19:26| #28

arne_v
arne_v (1.016.169 point)
Ja.

Bortset fra at:
- sizeof(char) altid er 1 og derfor overflødig
- du skal bruge delete[] ikke delete

Skrevet lør. d. 26. december 2009 kl. 11:27:36| #29

mbm2007
mbm2007 (8.387 point)
www.magnusbm.dk
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 ;)

Skrevet lør. d. 26. december 2009 kl. 14:28:01| #30

arne_v
arne_v (1.016.169 point)
Problemet med memcpy / memmove er nok det som jeg ikke nævnte for malloc/free: constructor/destructor.

Skrevet lør. d. 26. december 2009 kl. 14:33:36| #31

arne_v
arne_v (1.016.169 point)
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;
}

Skrevet lør. d. 26. december 2009 kl. 14:34:37| #32

arne_v
arne_v (1.016.169 point)
memcpy/memmove kan være superfarlig, hvis en class indeholder pointere fordi copy constructoe / assignment operator ikke bliver kaldt.

Skrevet lør. d. 26. december 2009 kl. 14:35:18| #33

arne_v
arne_v (1.016.169 point)
Din kode i #29 forstår jeg ikke.

Skrevet lør. d. 26. december 2009 kl. 17:14:41| #34

mbm2007
mbm2007 (8.387 point)
www.magnusbm.dk
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.?

Skrevet lør. d. 26. december 2009 kl. 20:54:40| #35

arne_v
arne_v (1.016.169 point)
Hvis du bruger en for løkke og klassen har defineret en assignment operator, så tror jeg at det virker som det skal.

Skrevet lør. d. 26. december 2009 kl. 21:40:56| #36

arne_v
arne_v (1.016.169 point)
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;
}

Skrevet tir. d. 05. januar 2010 kl. 16:04:36| #37

mbm2007
mbm2007 (8.387 point)
www.magnusbm.dk
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 ;)

Skrevet tir. d. 05. januar 2010 kl. 16:05:27| #38

mbm2007
mbm2007 (8.387 point)
www.magnusbm.dk
Hvad skete der lige der! ;)

Jeg har givet point ;)

Skrevet ons. d. 06. januar 2010 kl. 03:57:02| #39

arne_v
arne_v (1.016.169 point)
Hm.

Måske kan jeg tilføje lidt mere debug output.

Skriv et indlæg




Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] [img]link til billede[/img]
Web- og emailadresser omdannes automatisk til links

Log ind

   

   

Seneste spørgsmål

Updater Hybrid App

Oprettet den 18. april 2012 kl. 13.29
sir_madsen giver 100 point for svar | Giv et svar »

Ansi-c win32API - kan ikke oprette Richedit4.1 kontrol

Oprettet den 16. april 2012 kl. 22.13
cblcbl giver 60 point for svar | Giv et svar »

Iphone Objective C - Sætte image på et imageview.

Oprettet den 7. april 2012 kl. 11.36
lasserasch giver 30 point for svar | Giv et svar »



   




Tips & Tricks fra PC World

Teaser billede

Læserne: Her er vores værste it-indkøb

Det er ikke al it-udstyr, som er det rene guld. Her er nogle af læsernes skrækhistorier.


Anmeldelser fra PC World

Teaser billede

Test: Mobil med Ferrari-design - og en Trabant-motor

Motorola har begået endnu en smartphone med lækkert design og potentiale til at være blandt de bedste. Men den når ikke i mål. Se her hvorfor.


Seneste blogindlæg

Teaser billede

Tvangslukke spørgsmål: Hvad er den bedste løsning?

Hej Vi har mange åbne spørgsmål på Eksperten. Vi ville gerne tvangslukke dem - så et spørgsmål efter f.eks. 6 måneder lukkes. Men der er et par uklarheder som ville være gode at få lidt input til:...


Nyheder fra PC World

Teaser billede

Sådan siger du farvel til Facebook

Læs her, hvordan du dropper Facebook og i stedet anvender nogle brugervenlige alternativer, så du stadig kan være social på nettet.


Nyheder fra Computerworld

Teaser billede

Galleri: De fedeste håndholdte gennem 40 år

Her har du de mest banebrydende håndholdte computere gennem alle tider.


Kurser
Samarbejdspartnere

Udgiver · © 2012 IDG Danmark A/S · Hørkær 18 · 2730 Herlev · Tlf.: 77 300 300 · Fax: 77 300 301 · Brug af personoplysninger