Skrevet ons. d. 23. december 2009 kl. 19:23:01| #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.
Skrevet ons. d. 23. december 2009 kl. 19:23:48| #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.
Skrevet ons. d. 23. december 2009 kl. 19:25:14| #3
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
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
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
*(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
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
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
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
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
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
okay mange tak arne jeg giver point ;)
Skrevet tor. d. 24. december 2009 kl. 14:23:28| #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/ (...)
Skrevet tor. d. 24. december 2009 kl. 14:34:33| #14
et svar
jeg kigger lidt paa koden senere
Skrevet fre. d. 25. december 2009 kl. 18:39:11| #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
Skrevet fre. d. 25. december 2009 kl. 23:27:02| #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
Skrevet fre. d. 25. december 2009 kl. 23:42:24| #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
Skrevet fre. d. 25. december 2009 kl. 23:44:12| #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.
Skrevet fre. d. 25. december 2009 kl. 23:46:12| #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
...
Skrevet fre. d. 25. december 2009 kl. 23:47:01| #20
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
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
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
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
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
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
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
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
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
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
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
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
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
Din kode i #29 forstår jeg ikke.
Skrevet lør. d. 26. december 2009 kl. 17:14:41| #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.?
Skrevet lør. d. 26. december 2009 kl. 20:54:40| #35
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
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
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
Hvad skete der lige der! ;)
Jeg har givet point ;)
Skrevet ons. d. 06. januar 2010 kl. 03:57:02| #39
Hm.
Måske kan jeg tilføje lidt mere debug output.