Archief - C++ : Paar simpele vraagskes

Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.

Da Turtle

Legacy Member
1. wat betekend het * bij volgende declaratie (iets met poiner?) :
int *x, *y;
2. wat is het verschil tussen :
int x;
en
x = new int;
?

thx

WHiSPy

Legacy Member
Da Turtle zei:
1. wat betekend het * bij volgende declaratie (iets met poiner?) :
int *x, *y;
2. wat is het verschil tussen :
int x;
en
x = new int;
?

thx

1) Daar wordt een pointer naar een integer gedeclareerd. Dat is dus een verwijzing naar een variable van het type integer in het geheugen.

2) Dat eerste is de aanduiding dat een type van het type int is en het 2e is een het instantieren van een nieuwe variable van het type int. In casu is dat voor een integer hetzelfde, maar voor meeste classes is dat niet het geval. (die 2e declaratie is zelfs fout, aangezien ge een constructor aanroept en ge moet aanduiden dat ie geen parameters moet meegeven: new int(); )

SlasZ

Legacy Member
WHiSPy zei:
1) Daar wordt een pointer naar een integer gedeclareerd. Dat is dus een verwijzing naar een variable van het type integer in het geheugen.

2) Dat eerste is de aanduiding dat een type van het type int is en het 2e is een het instantieren van een nieuwe variable van het type int. In casu is dat voor een integer hetzelfde, maar voor meeste classes is dat niet het geval. (die 2e declaratie is zelfs fout, aangezien ge een constructor aanroept en ge moet aanduiden dat ie geen parameters moet meegeven: new int(); )


die 2e is wel juist op voorwaarde dat x een pointer is (dus int *x = new int).
x is dan gewoon een pointer naar een integer en die wordt opgeslagen op de heap. OPGEPAST: alle geheugen die je reserveert op de heap (dus met new of malloc) moet manueel vrijgemaakt worden met delete (of free), anders blijft die geheugenruimte onbeschikbaar ookal heb je die waarde niet meer nodig (= geheugenlek)

bij int x wordt x opgeslagen in de stack-frame van die functie, en worden automatisch vrijgemaakt als die functie gedaan heeft.

edit:
WHiSPy zei:
In casu is dat voor een integer hetzelfde, maar voor meeste classes is dat niet het geval.

dit is voor een integer niet hetzelfde:

doe maar eens
Code:
int *x = new int;
x[0] = 10;
cout << x << endl;
cout << x[0] << endl;
de eerste regel toont het geheugenadres, de 2e regel de waarde (10).

Da Turtle

Legacy Member
ok, thx

kversta nog nie veel van die pointers :sad:. Wat de zin ervan is enal .. mja, thx voor de reacties, kversta wel wat je bedoeld hoor, thx. Kben gewoon nie mee wrm da je die pointers kan gebruiken.

SlasZ

Legacy Member
wel er zijn veel redenen.

ten eerste als je een variabele nodig hebt die veel geheugen inneemt (een foto bvb), ben je bijna verplicht een pointer te gebruiken omdat die niet op de stack zal kunnen (die is standaard 1MB groot in windows 2000/xp). Dus van zodra je meer geheugen nodig hebt voor je variabelen in een functie zal je pointers moeten gebruiken geheugen dynamisch (met new) te reserveren.

een ander belangrijk voordeel is het doorgeven van variabelen in functies.
Als je bvb een functie hebt die een foto (een array van bytes) bewerkt, kan je die functie op 2 manieren maken:

Code:
void bewerk_foto(char[] foto)
{

}
hier wordt de hele foto eerst gedupliceerd en opgeslagen in de stack van deze functie, wat extra geheugenruimte & tijd in beslag neemt.
Deze functie een resultaat terug te laten geven is omslachtig en vereist werken met klassen.

of

Code:
char* bewerk_foto(char* foto)
{
}

hier wordt enkel de pointer (dus de lokatie in het geheugen waar die foto staat) meegegeven, en de functie werkt rechtstreeks daar op. Geen nodeloos gecopieer, en alle veranderingen aan die foto kunnen ofwel rechtstreeks in de originele opgeslagen worden, of er kan een nieuwe variable gemaakt worden die dan alle veranderingen bevat en teruggegeven wordt.

er zijn nog voordelen, maar dit zijn de belangrijkste.
de nadelen zijn dat je gemakkelijk geheugenlekken hebt als je vergeet het geheugen weer vrij te maken.
het is ook mogelijk om getallen bij pointers op te tellen (dus om bvb 10 geheugenplaatsen op te schuiven doe je gewoon y = *(x + 10); Maar dit is gevaarlijk omdat het zo mogelijk is om geheugen te gaan lezen die tot een andere variabele of tot geen variabele behoord.

hopelijk is het nu een beetje duidelijk, als je nog vragen hebt, stel maar gerust :)

Silenger.BE

Legacy Member
hier wordt de hele foto eerst gedupliceerd en opgeslagen in de stack van deze functie

De compiler zal normaal alles doorgeven met PUSH van vars...
PUSH doen van een block groter dan 32bit... dit kan niet...

Bv

Een string op geheugen locatie 00400000 "TEST"
Als je die niet passed als pointer zal dit zoiets zijn

PUSH offset String

Bij een pointer

DWORD StringPointer = &String;

PUSH [StringPointer]

Code:
PUSH - Push Word onto Stack
        Usage:  PUSH    src
                PUSH    immed   (80188+ only)
        Modifies flags: None
        Decrements SP by the size of the operand (two or four, byte values
        are sign extended) and transfers one word from source to the stack
        top (SS:SP).
                                 Clocks                 Size
        Operands         808x  286   386   486          Bytes

        reg16           11/15   3     2     1             1
        reg32             -     -     2     1             1
        mem16           16+EA   5     5     4            2-4  (W88=24+EA)
        mem32             -     -     5     4            2-4
        segreg          10/14   3     2     3             1

        immed              -    3     2     1            2-3

SlasZ

Legacy Member
je hebt gelijk, arrays worden automatisch als pointers doorgegeven, maar toch wordt heel die array op de stack geplaatst, waarschijnlijk door vele pushes :)

Silenger.BE

Legacy Member
Nee denk dat de compiler dan gewoon ergens in de exe in de data sectie gewoon zorgt voor een lege plaats die als buffer dient. Dus zal em data moven naar die buffer en dan de buffer pointer doorgeven. Wat dus trager is als je die functie meerder maal aanroept met zelfde data, inplaats van een pointer te gebruike.

SlasZ

Legacy Member
nee toch niet, grote datastructuren worden weldegelijk op de stack zelf opgeslagen. ofwel met vele push-es of gewoon een memcopy naar de stack.

enfin, punt is dat pointers sneller zijn om grote objecten door te geven aan functies :woohoo:

Jacko

Legacy Member
Yow Slasz,

Ge hebt gelijk da het interessanter is om grote datastructs by reference door te geven ipv by value (Niet alleen om stack te sparen, ook voor performantie, als ge by value passeert maakt ge een kopie van uw origineel object en werkt ge daarop verder).

Alleen is uw voorbeeld nogal ongelukkig gekozen:
void processArray1 (int* inArray) {...}
void processArray2 (int inArray[]) {...}
void processArray3 (int inArray[20]) {...}
zullen allemaal op exact dezelfde manier gecalld worden (pointer naar de array op stack en callen).

Neem daarentegen een klasse:

class NeigGroot
{
int mVar1;
int mVar2;
...
int mVar672346;
};

Dan zal er wel degelijk een verschil bestaan tussen enerzijds:

// Dupliceert object (ev. op stack)
void processACopyOfMyObject (NeigGroot inGroot) {...}

en anderzijds:

// Geeft enkel pointer door en werkt op originele data:
void processMyObject (NeigGroot& inGroot) {...}
void processMyObject (NeigGroot* inGroot) {...}


Naar de originele poster toe:

* wordt gebruikt om te tonen dat we niet het object gaan bijhouden, maar de plaats in het geheugen waar dit object zich bevindt. Voordeel hiervan is dat dit bij grotere objecten minder plaats inpakt. Huidige architecturen 32 bits voor een * (= pointer).

En ander voordeel is dat verschillende objecten dezelfde data kunnen delen. Indien een van de objecten dit object wijzigt, zien andere objecten die wijzigingen ook.

Bvb:

int a = 5;
int* b = &a; // & neemt het adres van de variabele ipv variabele zelf
int* c = b; // b en c zijn nu allebei pointers naar hetzelfde object.

a = 10;
std::cout << b << std::endl
<< *b << std::endl
<< c << std::endl
<< *c << std::endl;
// Hier krijg je 4 getallen. De tweede en vierde zullen dezelfde zijn (nl 10)
// De eerste en derde zullen ook dezelfde zijn (maar niet wijzigen als a
// verandert) zij bevatten het geheugenadres waarin a opgeslagen wordt.

Hmmm, hopelijk ben je nog mee. Pointer arithmetiek is nie echt simpel in het begin, maar op een gegeven moment heb je het door en dan kan je beginnen goochelen (en sakkeren...)

SlasZ

Legacy Member
Jacko zei:
Yow Slasz,

Ge hebt gelijk da het interessanter is om grote datastructs by reference door te geven ipv by value (Niet alleen om stack te sparen, ook voor performantie, als ge by value passeert maakt ge een kopie van uw origineel object en werkt ge daarop verder).

Alleen is uw voorbeeld nogal ongelukkig gekozen:
void processArray1 (int* inArray) {...}
void processArray2 (int inArray[]) {...}
void processArray3 (int inArray[20]) {...}
zullen allemaal op exact dezelfde manier gecalld worden (pointer naar de array op stack en callen).
inderdaad slecht gekozen maar het hing hem om het punt ;)
Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.
Terug
Bovenaan