Toon posts:

[C++] parameter referencing

Pagina: 1
Acties:

Verwijderd

Topicstarter
Stel ik heb een C functie:

void(char *p)
{
printf("%s\n", p);
}

Deze geeft een pointer naar een array van karakters door. Nu vraag ik me iets af. Ik moet hier voor mijn studie gebruik maken van 'call by reference'. Kan dit ueberhaupt wel met een karakter van arrays of een pointer?

Oftewel: kan men in C++ een pointer via 'call by reference' doorgeven aan een functie? :?

Of probeer ik nu iets dat gewoonweg niet kan? :Y)

  • whoami
  • Registratie: December 2000
  • Laatst online: 22:57
arrays worden altijd via reference doorgegeven, aangezien een array zowiezo een pointer is naar de geheugenlocatie van het eerste element van die array.

Als je dus:
code:
1
void GeefArrayDoor(int[]);

definieert, dan wordt de array die je zal doorgeven in uw code, automatisch by reference doorgegeven:
code:
1
2
3
int tabel[10];

GeefArrayDoor(tabel);

Is dus een pass by reference.

https://fgheysels.github.io/


Verwijderd

Topicstarter
Hmmm *voelt zich nu ontieglijk dom* :o

Thanx :+

  • ^Mo^
  • Registratie: Januari 2001
  • Laatst online: 04-11-2025
void DoSomething( const char *&p); werkt ook... 't ziet er wel een beetje exotisch uit... :) (laat const weg als var gewijzigd moet/kan worden...)

"There are 10 kinds of people in the world, those who understand binary and those who don't" | Werkbak specs


Verwijderd

Topicstarter
Op woensdag 13 februari 2002 07:24 schreef _Mo_ het volgende:
void DoSomething( const char *&p); werkt ook... 't ziet er wel een beetje exotisch uit... :) (laat const weg als var gewijzigd moet/kan worden...)
Hey thanx, dat zocht ik eigenlijk *D

Nu werkt het :Y)

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 12-09 23:01
Mag ik vragen waarom je een pointer by reference zou willen doorgeven? Dit is toch erg dubbelop, aangezien een reference parameter gezien mag worden als een 'automatische pointer'?
Stel ik heb een C functie
Ik neem aan dat je weet dat in C call by reference niet bestaat?

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.


  • Tomatrix
  • Registratie: Juni 1999
  • Laatst online: 27-02-2025
Op woensdag 13 februari 2002 08:45 schreef farlane het volgende:
Ik neem aan dat je weet dat in C call by reference niet bestaat?
Ik wist dat eigenlijk niet. Heb er zelfs hele hoofdstukken over gehad toen ik C leerde, maar die waren dus eigenlijk overbodig?

Verwijderd

Topicstarter
Call by reference bestaat in C++, niet in C. Maar aangezien C++ een superset van C is, kan ik nog steeds over een C functie spreken die ik wil omzetten naar een C++ functie.

Dit was ook de bedoeling. Ik volg op het moment een opleiding tot Software Engineer, en kreeg daarbij de volgende opgave:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/*
// FILE : LES0316.cpp
//
// Vraagstuk les 3
//
///////////////////////////////////////////////////////
// Werken met strings in dynamisch gealloceerd geheugen
///////////////////////////////////////////////////////
//
//
//
*/

#include <stdio.h>  /* prototype i/o functies     */
#include <string.h> /* prototype string functies  */
#include <alloc.h>  /* prototype malloc en free   */

/* prototyping */
void   string_invoer(char **);
void   string_voeg_toe(char ** , char );
void   string_concatenate(char *, char *, char **);

void main()
{
   char *p1, *p2, *p3;      /* pointer naar array van characters */

   /* Het dynamisch geheugen voor de arrays worden in main gealloceerd, 
    de plaats waar deze gealloceerde geheugenruimte weer wordt teruggegeven, 
    is ook in main. Met andere woorden: malloc en free staan in dezelfde 
    functie. Dit is een goede vorm van symmetrie
   */
   p1 = (char *) malloc(1);
   p2 = (char *) malloc(1);  
   p3 = (char *) malloc(1);

   /* p1, p2 en p3 worden geinitialiseerd als lege strings */
   *p1 = *p2 = *p3 = 0;

   string_invoer( &p1 );
   string_invoer( &p2 );
   string_concatenate(p1, p2, &p3);

   printf("\nString1         : %s", p1);
   printf("\nString2         : %s", p2);
   printf("\nString1 + String2 : %s", p3);

   free( p1 );
   free( p2 );
   free( p3 );
   getchar();
}


/* Het invoeren van karakters totdat newline teken ingevoerd */
void string_invoer(char **p)
{
   char c;
   printf(" \nGeef de string op: " );

   while ( (c = getchar() ) != '\n')
   {
    /* het laatst ingevoerde karakter wordt aan de string toegevoegd */
    string_voeg_toe(p, c);
   }
}   


/* Het karakter c wordt aan de string p toegevoegd */
void string_voeg_toe(char **p, char c)
{
   /* nieuwe stringruimte = lengte p + 1 (voor c) + 1 ('\0') */
   char *pt = (char *) malloc( strlen( *p ) + 2 );

   /* de originele string kopieeren naar nieuwe ruimte */
   strcpy( pt, *p);

   /* het nieuwe karakter toevoegen als laatste karakter */
   pt[ strlen( *p ) ] = c;
   pt[ strlen( *p ) + 1 ] = 0;
  
   /* het geheugen van de oorspronkelijke string is niet meer nodig */
   free ( *p );

   /* voor de nieuwe string blijft p als pointer gelden */
   *p = pt;
}


/* 2 strings s1 en s2 achter elkaar zetten */
void string_concatenate(char *s1, char *s2, char **dest)
{
   char *st = (char *) malloc( strlen(s1) + strlen(s2) + 1 );
                 
   strcpy(st, s1);
   strcat(st, s2);

   /* het geheugen voor dest, in main gealloceerd, is niet meer nodig */
   free ( *dest );

   /* voor de nieuwe string blijft dest als pointer gelden */
   *dest = st;
}

De vraag was om call by reference te implementeren en alles om te zetten naar C++, dus als volgt:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// FILE : LES0316.cpp
//
// Vraagstuk les 3
//
///////////////////////////////////////////////////////
// Werken met strings in dynamisch gealloceerd geheugen
///////////////////////////////////////////////////////
//
//
//

#include <iostream.h>

// prototyping
void string_invoer(char *&);
void string_voeg_toe(char *&, char );
void string_concatenate(const char *&, const char *&, char *&);

void main()
{
   char *p1, *p2, *p3; // pointer naar array van characters

   // Het dynamisch geheugen voor de arrays worden in main gealloceerd,
   // de plaats waar deze gealloceerde geheugenruimte weer wordt teruggegeven,
   // is ook in main. Met andere woorden: new en delete staan in dezelfde
   // functie. Dit is een goede vorm van symmetrie

   // p1, p2 en p3 worden automatisch geinitialiseerd als lege strings
   p1 = new char(0);
   p2 = new char(0);
   p3 = new char(0);

   string_invoer( p1 );
   string_invoer( p2 );
   string_concatenate(p1, p2, p3);

   cout << "\nString1        : " << p1;
   cout << "\nString2        : " << p2;
   cout << "\nString1 + String2 : " << p3;

   delete p1;
   delete p2;
   delete p3;

   getchar();
}


// Het invoeren van karakters totdat newline teken ingevoerd
void string_invoer(char *&p)
{
   char c;
   cout << " \nGeef de string op: ";

   cin.get(c);
   while ( c != '\n')
   {
    // het laatst ingevoerde karakter wordt aan de string toegevoegd
    string_voeg_toe(p, c);
    
    cin.get(c);
   }
}


// Het karakter c wordt aan de string p toegevoegd
void string_voeg_toe(char *&p, char c)
{
   // nieuwe stringruimte = lengte p + 1 (voor c) + 1 ('\0')
   char *pt = new char[strlen( p ) + 2 ];

   // de originele string kopieeren naar nieuwe ruimte
   strcpy(pt, p);

   // het nieuwe karakter toevoegen als laatste karakter
   pt[ strlen( p ) ] = c;
   pt[ strlen( p ) + 1 ] = 0;

   // het geheugen van de oorspronkelijke string is niet meer nodig
   delete p;

   // voor de nieuwe string blijft p als pointer gelden
   p = pt;
}

// 2 strings s1 en s2 achter elkaar zetten
void string_concatenate(const char *&s1, const char *&s2, char *&dest)
{
   char *st = new char[strlen(s1) + strlen(s2) + 1];

   strcpy(st, s1);
   strcat(st, s2);

   // het geheugen voor dest, in main gealloceerd, is niet meer nodig
   delete dest;

   // voor de nieuwe string blijft dest als pointer gelden
   dest = st;
}

Eigenlijk simpel :)

  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06-2025

drm

f0pc0dert

Een pointer is in feite ook een reference. Of andersom. Het enige verschil is dat bij een pointer het geheugen adres onbeschermd is, en dus is bijvoorbeeld iets als
code:
1
2
3
4
void func ( char *p )
{
  p ++; // de pointer (rvalue) wordt opgehoogd
}

mogelijk. Bij een reference zoals C++ die kent is dit niet het geval, omdat je het dan over de lvalue van het object of primitief hebt. Oftewel:
code:
1
2
3
4
void func ( char &p )
{
   p ++; // de waarde (lvalue) wordt opgehoogd
}

Dit laatste is zoals farlane waarschijnlijk bedoelt niet mogelijk in C, maar een call-by-reference geldt net zo goed bij pointers, dus is wel mogelijk in C.

Kortom:
code:
1
2
3
4
void func ( char *p )
{
   (*p) ++;
}

is hetzelfde als
code:
1
2
3
4
void func ( char &p )
{
   p++;
}

ik hoop dat dit duidelijk is :?

/edit
* drm ziet niet in waarom je pointers by reference door zou willen geven :?

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz


Verwijderd

Topicstarter
Zie mijn laatste reply :)

Het was een opgave.

  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06-2025

drm

f0pc0dert

cr33p:
Zie mijn laatste reply :)

Het was een opgave.
Ik neem aan dat dat een antwoord is op mijn vraag waarom je pointers bij reference mee zou willen geven?

Dan nog blijft de vraag, want dan vraag ik me af waarom dat uberhaupt geimplementeerd is...

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz


Verwijderd

Topicstarter
Op woensdag 13 februari 2002 09:38 schreef drm het volgende:

Dan nog blijft de vraag, want dan vraag ik me af waarom dat uberhaupt geimplementeerd is...
Zodat het mogelijk wordt in de functie string_voeg_toe de pointer naar een ander adres te laten wijzen en de oude geheugenallocatie te ruimen.

Het gaat hier dus om het dynamisch vergroten van een karakterarray via een pointer in C, maar omdat je deze binnen de string_voeg_toe functie moet omzetten, krijg je een dubbele pointer (**p). Met pass by reference kun je direct de pointer bewerken, wat dus uiteindelijk eenvoudiger is.

Maar goed, nu ga ik weer verder. Het probleem is opgelost wat mij betreft :)

  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06-2025

drm

f0pc0dert

cr33p:
Zodat het mogelijk wordt in de functie string_voeg_toe de pointer naar een ander adres te laten wijzen en de oude geheugenallocatie te ruimen.
Aha, op die fiets. Da's inderdaad zo gek nog niet...

Alleen kan je je afvragen of je hier niet met een OO-oplossing beter/netter af bent, maar goed.

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz


Verwijderd

Topicstarter
Tuurlijk kan het allemaal een stuk netter :)

Maar dat 'hoor' ik eigenlijk nog niet te weten ;)

Ik zou gewoon de Standard C++ klassen gebruiken:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//---------------------------------------------------------------------------
#include <iostream.h>
#include <string>
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
    string t;

    t = "Dit is een string.";
    t = t + " Waar heel simpel iets aan toegevoegd kan worden.";

    cout << t;

    getchar();

    return 0;
}

:Y)

Verwijderd

Topicstarter
Als ik zelf zo'n programma'tje zou schrijven:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream.h>
#include <string>

using namespace std;

int main(int argc, char* argv[])
{
    string s1, s2, s3;

    cout << "String 1    : ";
    cin >> s1;

    cout << "String 2    : ";
    cin >> s2;

    s3 = s1 + s2;
    cout << "String 1 + 2: " << s3;

    getchar();

    return 0;
}

Dit doet voor de gebruiker gewoon hetzelfde :)

  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06-2025

drm

f0pc0dert

cr33p: Ik zou gewoon de Standard C++ klassen gebruiken
en terecht :Y) :D

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 23:11
Op woensdag 13 februari 2002 09:24 schreef cr33p het volgende:
Call by reference bestaat in C++, niet in C. Maar aangezien C++ een superset van C is, kan ik nog steeds over een C functie spreken die ik wil omzetten naar een C++ functie.
---
Dit was ook de bedoeling. Ik volg op het moment een opleiding tot Software Engineer, en kreeg daarbij de volgende opgave:
Kort vraagje:waar? Dit soort code zou je niet mogen
schrijven. Laat staan aan studenten geven.

Het commentaar over call by reference is een ander teken dat de docent niet goed weet waar hij het over heeft.

Call by reference wordt gebruikt om parameters te veranderen - wat in jouw functie niet gebeuert - of als optimalisatie voor grote objecten - en een pointer is dat ook niet - dus de vraag is onnodig verwarrend.

Een redelijk alternatief voor deze oefening is
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Oefening XIV

// De volgende code compileert maar BigInt::get_long()
// doet het niet. Los het probleem op m.b.v. 
// call by reference.

class BigInt {
private:
  unsigned long l0, l1;
public:
  // Ctors, operators, etc.
  void get_long ( unsigned long return_value )
  {
    if ( l1==0 ) return_value l0;
    throw domain_error("BigInt too large to fit");
  }
};

long voorbeeld = 1;
BigInt bi = 0;
bi.get_long( voorbeeld );
// Bug: voorbeeld is nog steeds 1

Uiteraard zou je in de echte opgave de rest van de class
verder uitwerken.

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


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 04-09 14:38

curry684

left part of the evil twins

Op woensdag 13 februari 2002 09:26 schreef drm het volgende:
Een pointer is in feite ook een reference. Of andersom. Het enige verschil is dat bij een pointer het geheugen adres onbeschermd is, en dus is bijvoorbeeld iets als
Daarentegen is er niets mis met een pointer by reference.
* drm ziet niet in waarom je pointers by reference door zou willen geven :?
Voldoende goede redenen op de goede momenten. Om een voor de hand liggende aan te grijpen: meerdere return values.

Stel bijvoorbeeld dat je een functie wilt hebben die een string uit een queue alloceert en retourneert en je wil daarvan ook de lengte hebben. Implementatie met pointers by reference:
code:
1
2
3
4
5
6
7
8
int ExtractString(char*& p_CharPointer);

...

char*    l_StringBuffer;
int l_StringLength;

l_StringLength = ExtractString(l_StringBuffer);

Andere mogelijkheden zijn er ook wel maar je moet ze toevallig herkennen. Stel bijvoorbeeld dat je een stringclass met copy-on-demand hebt. Je hebt dan in je stringclass zelf alleen een pointer naar een feitelijke stringimplementatie, met daarin een reference count. Het vrijgeven van de string doe je dan over het algemeen met een call naar een tussenfunctie, maar de aanroepende functie (destructor bijvoorbeeld) hoeft geen benul te hebben van of ie de contained string dan vrijgeeft of niet. Bijvoorbeeld:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
MyString::~MyString()
{
ReleaseString(m_String);
}

void ReleaseString(t_String*& p_String)
{
if(!InterlockedDecrement((t_SInt4&)p_String->m_ReferenceCount))
  {
  // Release all reserved memory
  ReleaseMemoryBuffer(p_String->m_String);
  delete p_String;
  p_String = NULL;
  }
}

Hoop dat je er iets van snapt... ps. dit is geen n00b-info meer ;)

Professionele website nodig?

Pagina: 1