[C++] Pointers aan elkaar gelijk maken in functie

Pagina: 1
Acties:

  • dr snuggles
  • Registratie: September 2000
  • Niet online
Na heel veel prutsen ben ik achter het probleem van mijn code gekomen. Het probleem heeft te maken met het gelijkmaken van twee pointers. Je kan doen:
• a = b (a verwijst naar b) of
• *a = *b (a neemt de waarde van b aan)

Als je dit gebruikt in wat simpele code dan ziet het er zo uit:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <stdlib.h>

void makeEqual(int* a, int* b);

int main() {
    int* a = new int;
    int* b = new int;

    *b = 5;
    makeEqual(a,b);
    std::cout << *a;
    return 0;
}

void makeEqual(int* a, int* b) {
    a = b;   //alleen binnen de functie zal a gelijk blijven aan b, daarna is het weer een lege pointer
    *a = *b; //overal zal a gelijk worden aan b, waarom nu wel en net niet?
}

Kan iemand mij vertellen waarom a=b zich niet hetzelfde gedraagd als *a=*b in deze code :?

Omdat ik bijna zeker weet dat dit al eens eerder is langskomen hier, ben ik hard wezen zoeken. Helaas heb ik niets soortgelijks kunnen vinden.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:14

.oisyn

Moderator Devschuur®

Demotivational Speaker

a wijst naar een object, en b wijst naar een ander object. Als je a=b doet, dan zal a naar hetzelfde object als b wijzen. Als je *a = *b doet, dan wordt de waarde van het object waar b naar wijst gekopiëerd naar het object waar a naar wijst. De objecten waar a en b naar wijzen zijn nog steeds verschillend, alleen hebben ze dezelfde waarde.

Dit maakt het wellicht wat duidelijker:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int main()
{
    int a = 1;
    int b = 2;

    int * pA = &a;  // de pointer pA wijst nu naar a
    int * pB = &b;  // de pointer pB wijst nu naar b

    *pA = *pB; // *pA is equivalent aan a, *pB is equivalent aan pB
               // dus *pA = *pB is equivalent aan a = b

    std::cout << a << std::endl;    // output 2
    std::cout << *pA << std::endl;  // idem

    b = 3;
    std::cout << a << std::endl;    // output 2
    std::cout << *pA << std::endl;  // idem

    pA = pB;
    std::cout << a << std::endl;    // output 2
    std::cout << *pA << std::endl;  // output 3, want b is 3 en pA wijst naar b    
}

[ Voor 52% gewijzigd door .oisyn op 28-02-2007 16:54 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • dr snuggles
  • Registratie: September 2000
  • Niet online
Bedankt voor het duidelijk maken. Ik snap je post volledig, maar mijn fout nog steeds niet. Waarom verschilt in onderstaande code de output :?
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void makeEqual(int* a, int* b); 

int main() { 
    int* a = new int; 
    int* b = new int; 

    *b = 5; 
    makeEqual(a,b); 

    std::cout << *a;  //output 0  <----vreemd!
    return 0; 
} 

void makeEqual(int* a, int* b) { 
    a = b;   
    std::cout << *a;  //output 2    
}

[ Voor 113% gewijzigd door dr snuggles op 28-02-2007 16:59 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:14

.oisyn

Moderator Devschuur®

Demotivational Speaker

a en b in makeEqual() zijn lokale kopieën van de pointers van a en b in main(). Alleen de verwijzing zelf is een kopie, de objecten waar ze naar wijzen zijn geen kopieën

[ Voor 5% gewijzigd door .oisyn op 28-02-2007 16:55 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • dr snuggles
  • Registratie: September 2000
  • Niet online
Aha, dus als ik *a=*b doe, dan krijgt de globale a een nieuwe inhoud, doe ik a=b dan krijgt de lokale a een nieuwe inhoud. Net zoals bij functies zonder pointers. Nooit geweten.

Dank je!

[ Voor 11% gewijzigd door dr snuggles op 28-02-2007 17:07 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:14

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ik betwijfel of je het nu snapt, want er is niet zoeits als een lokale en globale a en b. a is lokaal voor zowel main() als makeEqual(), en er bestaat geen globale a.

Je moet het onderscheid maken tussen het objecten die de verwijzing in zich hebben (de pointers dus, a en b in jouw code), en de objecten waarnaar verwezen wordt (deze hebben in jouw code geen naam, ze zijn alleen gealloceerd door de "new int"). Een pointer is ook gewoon een variabele met een inhoud. Alleen is die inhoud geen getal zoals bij een int, maar is die inhoud een verwijzing (een geheugenadres). De makeEqual() kopiëert de inhoud van pointer b naar pointer a middels de a=b statement. Maar met *a=*b kopieer je juist de inhoud van het object waar b naar wijst naar het object waar a naar wijst. Omdat zowel de pointers in makeEqual() als in main() dezelfde geheugenadressen gebruiken, zijn de veranderingen dus zichtbaar, ookal gebruikt makeEqual() kopieën van de geheugenadressen in main()!

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • dr snuggles
  • Registratie: September 2000
  • Niet online
Blijkbaar begreep ik het toch inderdaad niet.

Dit gaat bijvoorbeeld ook fout om een reden die ik niet begrijp:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Koelkast {
   public:
      bool nogMelk; 
};

void erIsMelk(Koelkast* pWit) {   //pWit is een kopie van pWit uit de main functie
    (*pWit).nogMelk = true;       //maar verandert wel de inhoud waar pWit naar verwijst
}

int main() {  
    Koelkast Wit;
    Koelkast* pWit;
    
    *pWit = Wit;

    erIsMelk(pWit);  

    if (Wit.nogMelk) 
       std::cout << werkt;
    else std::cout << werkt niet; //<-- 't werkt dus niet :(
    return 0;  
}  

Ja ik weet dat je beter Koelkast::setMilk kunt maken, maar dit is voor het pointer idee mooi :P

Komt dit nu ook weer omdat de functie met een kopie van de pointer zit te werken :?

[ Voor 31% gewijzigd door dr snuggles op 28-02-2007 20:57 ]


  • robbert
  • Registratie: April 2002
  • Laatst online: 01-12 18:50
dr snuggles schreef op woensdag 28 februari 2007 @ 20:43:
Blijkbaar begreep ik het toch inderdaad niet.

Dit gaat bijvoorbeeld ook fout om een reden die ik niet begrijp:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Koelkast {
   public:
      bool nogMelk; 
};

int main() {  
    Koelkast Wit;
    Koelkast pWit;
    
    *pWit = Wit;

    erIsMelk(pWit);  

    std::cout << Wit.nogMelk;  // dit blijft false :(
    return 0;  
}  

void erIsMelk(Koelkast* pWit) {   //pWit is een kopie van pWit uit de main functie
    (*pWit).nogMelk = true;       //maar verandert wel de inhoud waar pWit naar verwijst
}

Ja ik weet dat je beter Koelkast::setMilk kunt maken, maar dit is voor het pointer idee mooi :P

Komt dit nu ook weer omdat de functie met een kopie van de pointer zit te werken :?
Dit compileert overigens helemaal niet. Wat je in regel 10 doet is nogal raar en je voert nu een Koelkast ipv een Koelkast* aan erIsMelk.

Daarnaast vind ik references een stuk mooier. Bijv:
C++:
1
2
3
4
5
6
7
8
9
10
void erIsMelk(Koelkast &pWit) {
    pWit.nogMelk = true;
}

int main() {  
    Koelkast pWit = Koelkast();
    erIsMelk(pWit);  
    std::cout << pWit.nogMelk;
    return 0;  
}  

[ Voor 21% gewijzigd door robbert op 28-02-2007 20:55 ]


  • dr snuggles
  • Registratie: September 2000
  • Niet online
Ik wilde net zeggen dat er iets fout is met je compiler omdat ie hier wel compileert, maar ik zag dat de code idd incompleet was. Nu zou die 't wel moeten doen :).

Ja by reference is mooier. Alleen wil ik graag weten waarom mijn voorbeeld het niet doet :).

[ Voor 22% gewijzigd door dr snuggles op 28-02-2007 21:01 ]


  • robbert
  • Registratie: April 2002
  • Laatst online: 01-12 18:50
dr snuggles schreef op woensdag 28 februari 2007 @ 20:56:
Ik wilde net zeggen dat er iets fout is met je compiler omdat ie hier wel compileert, maar ik zag dat de code idd incompleet was. Nu zou die 't wel moeten doen :).

Ja by reference is mooier. Alleen wil ik graag weten waarom mijn voorbeeld het niet doet :).
Je zou dan dit moeten doen:
C++:
1
pWit = &Wit;

pWit is nu een pointer naar Wit. In jouw voorbeeld geef je pWit de waarde van Wit.

Daarnaast zou ik dat Wit opject ook effe netjes initialiseren, dus:
C++:
1
Wit = Koelkast();

[ Voor 17% gewijzigd door robbert op 28-02-2007 21:18 ]


  • dr snuggles
  • Registratie: September 2000
  • Niet online
Aha, pWit kreeg dus slechts de waarde van Wit, ipv dat hij hiernaar verwees.

M'n huidige code ombouwen naar functies met references zal erg veel werk worden. Maar in de toekomst zal ik alleen maar references gaan gebruiken. Stukken handiger!

Bedankt robbert! :)

  • robbert
  • Registratie: April 2002
  • Laatst online: 01-12 18:50
dr snuggles schreef op woensdag 28 februari 2007 @ 21:27:
Aha, pWit kreeg dus slechts de waarde van Wit, ipv dat hij hiernaar verwees.

M'n huidige code ombouwen naar functies met references zal erg veel werk worden. Maar in de toekomst zal ik alleen maar references gaan gebruiken. Stukken handiger!

Bedankt robbert! :)
Wat ik hier boven doe is overigens geen referentie. Je hebt 2 verschillende &'en in c++. Je hebt enerzijds de & welke de pointer van een variabele geeft, wat ik hier boven doe. En je hebt de & van references wat ik in die erIsMelk functie doe.

Kortom,
C++:
1
&var

geeft de pointer naar de variabele var.

C++:
1
*var

geeft de waarde van de instantie waar een pointer naar wijst.

C++:
1
void blaat(int &blaat)

is een referentie.

[ Voor 15% gewijzigd door robbert op 28-02-2007 21:33 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:14

.oisyn

Moderator Devschuur®

Demotivational Speaker

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • schoene
  • Registratie: Maart 2003
  • Laatst online: 12:20
dr snuggles schreef op woensdag 28 februari 2007 @ 20:43:
C++:
1
2
3
4
5
6
7
8
9
int main() {  
    Koelkast Wit;
    Koelkast* pWit;
    
    *pWit = Wit;

    //...
    return 0;  
}  
Gezien pWit hier nog niet naar gealloceerd geheugen wijst, is deze code trouwens volledig fout.

[ Voor 11% gewijzigd door schoene op 01-03-2007 08:44 ]


  • elTigro
  • Registratie: November 2000
  • Laatst online: 23-11 10:52

elTigro

Es un Gringo!

schoene schreef op donderdag 01 maart 2007 @ 08:41:
[...]


Gezien pWit hier nog niet naar gealloceerd geheugen wijst, is deze code trouwens volledig fout.
Los daarvan, waarom is de koelkast uberhaupt wit? heb je geen modern metaalkleurig/chroomen model?
Maar goed, Is het probleem van dr Snuggles niet gewoon het standaard probleem tussen
by value en by reference?

Lazlo's Chinese Relativity Axiom:No matter how great your triumphs or how tragic your defeats --approximately one billion Chinese couldn't care less.


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 30-11 00:17
Volgens mij is het het probleem dat je in iedere taal tegenkomt nl het besef van wat pointers eigenlijk zijn. ( Ja, ook VB, Java, C# en weet ik wat hebben pointers, je ziet ze alleen niet of ze hebben een andere naam )

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:14

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ok, poging 3 :P

Stel ik ben een functie. Verder zijn er 10 lege bakjes, genummerd 1 t/m 10. Ik alloceer 2 bakjes (new bakje), die allocaties geven mij de nummers 1 en 2 op aparte briefjes, die verwijzen naar de twee bakjes met hetzelfde nummer. Vervolgens stop ik een rode stuiterbal in bakje 1, en een groene stuiterbal in bakje 2.

Nou ben jij de makeEqual() functie, en ik roep jou aan met de nummers 1 en 2. Ik geef jou niet mijn briefjes, want die zijn van mijzelf, ik roep alleen "1" en "2". Jij schrijft dat op je eigen briefjes. De statement a = b wil zeggen dat jij de "1" op jouw briefje doorkrast en vervangt door een 2. Nu heb je twee briefjes met een 2 erop. Beide briefjes verwijzen naar hetzelfde bakje - die met de groene stuiterbal. *a en *b zijn dan natuurlijk gelijk aan elkaar, want ze wijzen naar hetzelfde object. Máár, ik heb zelf nog een briefje met een 1 en een briefje met een 2. Als ik de inhoud van die twee bakjes controleer zijn ze nog steeds verschillend, jij hebt immers niets aangepast (alleen je eigen briefje).

Nu vergeten we even dat je de 1 hebt doorgekrast op je briefje, en je doet *a = *b. *a wil zeggen hebt object in het bakje waarvan het nummer op het eerste briefje staat (bakje 1, die met de rode stuiterbal), idem voor *b (bakje 2, met de groene stuiterbal). De assignment betekent dus dat je de inhoud van bakje 1 gelijk maakt aan de inhoud van bakje 2. Je verft de rode stuiterbal dus groen. Als ik, nadat jij klaar ben, weer in de bakjes kijk waarvan de nummers op mijn briefjes staan, zie ik dat de inhoud van die bakjes nu hetzelfde is - in beide bakjes zit een groene stuiterbal. Maar, het zijn nog wel steeds verschillende stuiterballen.

Nu ben jij een functie, genaamd stuiter(), die een stuiterbal kan laten stuiteren. Eerst accepteer je een stuiterbal by-value, zoals dat heet. Dus geen pointer of reference. Als ik dan jou aanroep, laat ik een rode stuiterbal zien. Jij maakt een kopie van die stuiterbal en gaat daarmee stuiteren. Ik zie daar niets van, want mijn stuiterbal heb ik nog gewoon in mijn bakje zitten. Maar nu ben je dezelfde functie, maar dan accepteer je een pointer of een reference. De rode stuiterbal zit in bakje 1, dus ik roep "1". Jij schrijft de 1 op een briefje, vervolgens kijk je in het bakje met het nummer dat op het briefje staat (bakje 1 dus). De stuiterbal die daarin zit laat jij stuiteren. Als ik dan weer naar mijn bakje kijk, zie ik de stuiterbal stuiteren. Want ik heb jou verteld in welk bakje mijn stuiterbal zit, ipv dat ik gewoon heb verteld hoe mijn stuiterbal eruit ziet.

Ik hoop dat dit helpt om het te visualiseren :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
robbert schreef op woensdag 28 februari 2007 @ 21:16:
Daarnaast zou ik dat Wit opject ook effe netjes initialiseren, dus:
C++:
1
Wit = Koelkast();
Dat doet dus helemaal niets. Snap je ook waarom?

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • LDenninger
  • Registratie: Augustus 2005
  • Laatst online: 02-08-2024
Als je pointers op een makkelijke en leuke manier wilt leren begrijpen, bekijk dan het "Binky pointer fun" filmpje ! :)

http://cslibrary.stanford.edu/104/

Da's zeg maar "The Muppet show meets pointers" ;)

Edit:
Argh, ik zie dat Oisyn 'm al gepost had :D

[ Voor 11% gewijzigd door LDenninger op 01-03-2007 11:53 ]


  • robbert
  • Registratie: April 2002
  • Laatst online: 01-12 18:50
MSalters schreef op donderdag 01 maart 2007 @ 11:44:
[...]

Dat doet dus helemaal niets. Snap je ook waarom?
Ja, heb allang geen c++ meer geprogrammeerd, maar vond het er zo raar uitzien :) Maar zonder expliciet de default contructor aan te roepen doet die dat dus zelf en alloceert ook natuurlijk gewoon de benodigde geheugen ruimte voor dat object. Ook als je zelf een contructor zonder argumenten definieert wordt dus automatisch aangeroepen. Dus het was inderdaad overbodig.. ;)

[ Voor 9% gewijzigd door robbert op 01-03-2007 12:42 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:14

.oisyn

Moderator Devschuur®

Demotivational Speaker

De bool 'nogMelk' blijft wel ongeïnitialiseerd though :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Yep, als ik zeg dat 't helemaal niets doet, dan bedoel ik ook niets. Je kunt wel expliciet de default constructor aanroepen, maar dat lost het probleem van de ongeinitialiseerde bool niet op.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • robbert
  • Registratie: April 2002
  • Laatst online: 01-12 18:50
MSalters schreef op vrijdag 02 maart 2007 @ 00:24:
Yep, als ik zeg dat 't helemaal niets doet, dan bedoel ik ook niets. Je kunt wel expliciet de default constructor aanroepen, maar dat lost het probleem van de ongeinitialiseerde bool niet op.
Ik reageerde ook hierop:
Snap je ook waarom?
De bool heeft in beide situaties natuurlijk gewoon een bullshit waarde, ligt er maar net aan wat voor een stukje geheugen die krijgt en wat daar toevallig stond. :)

  • CyBeR
  • Registratie: September 2001
  • Niet online

CyBeR

💩

Voor de volledigheid als je makeequal je pointers nog gelijk zou willen maken, zou je kunnen zeggen, iets in de trant van:

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>

void make_equal(int **a, int **b){
        *a = *b;
}

int main(){
        int ra = 1, rb = 2;
        int *a, *b;

        a = &ra; b = &rb;

        printf("a: %d, b: %d, ra: %d, rb: %d\n", *a, *b, ra, rb);

        make_equal(&a, &b);

        printf("a: %d, b: %d, ra: %d, rb: %d\n", *a, *b, ra, rb);

}



Uitvoer:
code:
1
2
3
root@mailsrv01:/tmp# ./test 
a: 1, b: 2, ra: 1, rb: 2
a: 2, b: 2, ra: 1, rb: 2

[ Voor 41% gewijzigd door CyBeR op 02-03-2007 00:57 ]

All my posts are provided as-is. They come with NO WARRANTY at all.


  • robbert
  • Registratie: April 2002
  • Laatst online: 01-12 18:50
offtopic:
Waarom zou je dit soort dingen als root doen? Gewoon toevallig een root shell open staan, of vind je het leuk om alles als root te doen O-)

[2eedit]Hehe, in mijn edit had ik het goed gegokt :P

[ Voor 30% gewijzigd door robbert op 02-03-2007 01:02 ]


  • CyBeR
  • Registratie: September 2001
  • Niet online

CyBeR

💩

robbert schreef op vrijdag 02 maart 2007 @ 01:00:
[...]

offtopic:
Waarom zou je zoiets als root doen?
Omdat ik toevallig een root shell het dichtst bij open had? Ik wist ook dat ik 't weg had moeten editen :P

All my posts are provided as-is. They come with NO WARRANTY at all.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:14

.oisyn

Moderator Devschuur®

Demotivational Speaker

CyBeR schreef op vrijdag 02 maart 2007 @ 00:53:
Voor de volledigheid als je makeequal je pointers nog gelijk zou willen maken, zou je kunnen zeggen, iets in de trant van:
Of
C++:
1
2
3
4
void makeEqual(int *& a, int *& b)
{
    a = b;
}


Of
C++:
1
2
3
4
template<class T> void makeEqual(T & a, T & b)
{
    a = b;
}


;)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1