C und "call by reference"

Gast #3316782
Lesenswert?

Pass auf, dass Du die C++ Referenz Übergabe nicht mit Call by Reference 
verwechselst.

In C++
1
  void mach_was(uint16_t& array)
2
  {
3

4
  }

In C++ wird "Call by Reference" mit einem Pointer übergeben:
1
  void mach_was(uint16_t* array)
2
  {
3

4
  }

Grüsse,
René
Gast #3316799
Lesenswert?

Ritchie schreibt:

1.8 Arguments - Call by Value
One aspect of C functions may be unfamiliar to programmers who are used 
to some other languages, particulary Fortran. In C, all function 
arguments are passed ``by value.'' This means that the called function 
is given the values of its arguments in temporary variables rather than 
the originals. This leads to some different properties than are seen 
with ``call by reference'' languages like Fortran or with var parameters 
in Pascal, in which the called routine has access to the original 
argument, not a local copy.

Also scheint's so ohne weiteres nicht zu gehen.
#3316808
Lesenswert?

Bevor (oder damit?) der Arme noch mehr verwirrt wird:

Du übergibst dein Array zwar mittels "call per value", aber aber arrays 
sind in C "Pointer auf das erste Element".

d.H. obwohl die Parameterübergabe als "value" erfolgt, hat deine 
Funktion nacher eine "reference" auf die Array-Inhalte, und kann diese 
ändern.
Gast #3316834
Lesenswert?

>d.H. obwohl die Parameterübergabe als "value" erfolgt, hat deine
>Funktion nacher eine "reference" auf die Array-Inhalte, und kann diese
>ändern.

Tatsächlich, es geht.
Danke.


Jetzt hab ich aber eine neue Anomalie:

Byte * Data;
...
printf("%02i: %02X\t\t", i*8+j, Data);
...

Jetzt sollte eigentlich (der Logik nach was ich heute gelernt habe )die 
Adresse von Data angezeigt werden, oder?
Stattdessen wird (was durchaus wünschenswert ist) der Inhalt auf den der 
Zeiger zeigt, angezeigt.
Oh Mann, das schwächt.
#3316972
Lesenswert?

Stefan Rand schrieb:
> Klaus Wachtler schrieb:
>> Das hilft hier nicht, solange di nicht den restlichen K&R hier
>> reinkopierst, zumindest den Teil mit den Feldern - dort ist es gerade
>> andersrum.
>
> Nein. Auch da wird by value übergeben. Aber eben ein Zeiger.

Darüber kann man jetzt philosphieren.
Daß ein Zeiger übergeben wird, ist sicher richtig und das sollte 
inzwischen auch jeder verstanden haben.

Ein Zeiger auf etwas ist aber nun mal auch eine Referenz (auch wenn in 
C++ eine Referenz im Quelltext dann wieder anders aussieht, aber hier 
geht es ja um C).
Was das Feld angeht, wird es eben damit also per Referenz und nicht per 
Wert übergeben.

Daß dieses technisch gelöst ist, indem ein Zeiger auf das erste Element 
übergeben wird, ist ja kein Widerspruch. Bei C++ sind Referenzen ja 
intern wieder ebenso realisiert, nur daß man den zugehörigen Zeiger 
nicht direkt sieht.

Für den TO ist es nach wie vor so, daß er beim Aufrufer sein Feld in die 
Parameterliste schreibt und die Funktion die Elemente des Originalfeldes 
setzen kann, nicht die Elemente einer Kopie des Feldes (wie es bei call 
by value der Fall wäre, also bei nicht-Array-Parametern).
#3317178
Lesenswert?

Klaus Wachtler schrieb:
> Darüber kann man jetzt philosphieren.

Eigentlich nicht.

call-by-value und call-by-reference sind Sprachfeatures. Und C hat 
letzteres schlicht nicht.

> Was das Feld angeht, wird es eben damit also per Referenz und nicht per
> Wert übergeben.

Das Feld wird eben nicht übergeben. In abstrakt-wolkiger Denkweise: 
klar.

Aber soweit wir hier über C-Programmierung reden und nicht über 
irgendwelche Designdokumente wird da ein Zeiger übergeben. Kein Feld.

Und das sollte man auf dieser Ebene besser auch nicht vermischen. Denn 
das führt bei Leuten, die dieses C-eigene, völlig unintuitive Prinzip 
nicht komplett verdaut haben, immer wieder zu Mißverständnissen.
Gast #3317323
Lesenswert?

Stefan Rand (srand) schrieb:

Klaus Wachtler schrieb:
>> Darüber kann man jetzt philosphieren.

> Eigentlich nicht.

Eigentlich schon.

> call-by-value und call-by-reference sind Sprachfeatures. Und C hat
> letzteres schlicht nicht.

Es hat aber einen Meachanismus, der genau das gleiche bewirkt. Manche 
Bücher unterscheiden deshalb nicht bei call-by-reference zwischen C und 
C++ siehe Beispielsweise hier

http://openbook.galileocomputing.de/c_von_a_bis_z/012_c_zeiger_006.htm

"In solch einem Fall bietet es sich an, statt der Variablen radius 
einfach nur die Adresse der Variablen als Argument zu übergeben. Die 
Übergabe von Adressen als Argument einer Funktion wird call-by-reference 
genannt. Das Prinzip sehen Sie im abgeänderten Programmbeispiel:"
Gast #3317444
Lesenswert?

Hobbyprogrammierer schrieb:
>>d.H. obwohl die Parameterübergabe als "value" erfolgt, hat deine
>>Funktion nacher eine "reference" auf die Array-Inhalte, und kann diese
>>ändern.
>
> Tatsächlich, es geht.

Das ist übrigens ein Grund warum es "const" gibt, damit Du dem Compiler 
sagen kannst dass Du zwar den Pointer auf das erste Array-Element 
übergibst, aber nicht willst dass darüber dann die Array-Elemente 
(versehentlich) modifiziert werden.
Gast #3317456
Lesenswert?

Hobbyprogrammierer schrieb:
> Byte * Data;
> ...
> printf("%02i: %02X\t\t", i*8+j, Data);
Byte *Data; -> Ist ein Pointer (Zeiger) der auf den Anfang(Adresse) der 
Speicherzellen von Data zeigt.

Im printf wird die Adresse der Speicherzelle von Data ausgegeben.

Besseres Beispiel, vielleicht verständlicher(?):
1
char *bp; /* Buffer pointer , zeigt jetzt ins nirgendwo */
2

3
bp = (char *)malloc(sizeof(char)*10); /* hat jetzt die Startadresse 
4
die von malloc geliefert wurde, oder NULL. 
5
Wir nehmen mal an, dass malloc != NULL geliefert hat.*/
6

7
printf("%x", bp); /* Gibt die Adresse von bp aus */
8

9
*bp = 'A';  /* Schreibt das Zeichen 'A' an die Startadresse von bp*/
10
*(bp+1) = NULL; /* String terminieren */
11
printf("%s",*bp); /* Gibt den Inhalt von bp aus */

Hoffe, dass ich etwas zur Verwirrung beitragen konnte.
Moderator #3317471
Lesenswert?

MAD schrieb:
> *bp = 'A';  /* Schreibt das Zeichen 'A' an die Startadresse von bp*/
> *(bp+1) = NULL; /* String terminieren */
> printf("%s",*bp); /* Gibt den Inhalt von bp aus */
>
> Hoffe, dass ich etwas zur Verwirrung beitragen konnte.

Ja, das konntest du ganz gewiss ;-)

Mal abgesehen davon, dass das String-Endezeichen offiziell nicht NULL, 
sondern '\0' heißt (was immerhin durch einen impliziten Cast vom 
Compiler wieder zurechtgebogen wird), tut die Zeile mit dem printf doch 
recht seltsam Dinge (einfach mal ausprobieren).
Persönliche Seite #3317545
Lesenswert?

MAD schrieb:

> > printf("%02i: %02X\t\t", i*8+j, Data);
> Byte *Data; -> Ist ein Pointer (Zeiger) der auf den Anfang(Adresse) der
> Speicherzellen von Data zeigt.

Nein. Data zeigt nicht "auf den Anfang der Speicherzellen von Data".

> Im printf wird die Adresse der Speicherzelle von Data ausgegeben.

Nein. Hier wird der Inhalt von Data ausgegeben.

Um die Adresse der Speicherzelle von Data auszugeben, müsste das hier 
gemacht werden:
1
printf("%08X", &Data);

(statt %x sollte korrekterweise %p verwendet werden)

Im hier gewählten Kontext aber möchte niemand die Adresse von Data 
wissen, da Data selbst ein Pointer ist und dieser interessant ist.

> printf("%x", bp); /* Gibt die Adresse von bp aus */

Gleicher Fehler. Du verwechselst Pointer mit dem, worauf sie zeigen.

Hier wird nicht die Adresse von bp ausgegeben, sondern die Adresse 
dessen, worauf bp zeigt -- also der Inhalt von bp.
Gast #3317678
Lesenswert?

Rufus Τ. Firefly schrieb:
> Dann ist es formaljuristisch auf allen Plattformen korrekt.
>
> Solange aber sizeof (int) == sizeof (int *) ist, funktioniert die
> --unsaubere-- Variante auch.

Allerdings haben Pointer auf manchen Plattformen etwas spezielle 
Schreibweisen, die %p berücksichtigen kann, %i aber nicht. Außerdem 
werden bei %i die Werte dezimal angezeigt und bei hohen Adressen ggf. 
auch negativ.

Klaus Wachtler schrieb:
> Bei C++ sind Referenzen ja intern wieder ebenso realisiert, nur daß man
> den zugehörigen Zeiger nicht direkt sieht.

Sie können so implementiert sein, müssen es aber nicht.

Gelegenheitsprogrammierer schrieb:
> Stefan Rand (srand) schrieb:
>
> Klaus Wachtler schrieb:
>>> Darüber kann man jetzt philosphieren.
>
>> Eigentlich nicht.
>
> Eigentlich schon.

Philosophieren kann man darüber. Wenn man aber doch lieber technisch als 
philosophoisch diskutieren will, bekommt man bei Übergabe eines Arrays 
aus int an eine Funktion einen Zeiger auf einen int und nicht eine 
Referenz auf ein Array aus int.

>> call-by-value und call-by-reference sind Sprachfeatures. Und C hat
>> letzteres schlicht nicht.
>
> Es hat aber einen Meachanismus, der genau das gleiche bewirkt.

Daß es das eben nicht tut, sieht man schon daran, daß sizeof innerhalb 
der Funktion die Größe eines Zeigers und nicht die des Arrays liefert.

> Manche Bücher unterscheiden deshalb nicht bei call-by-reference zwischen
> C und C++ siehe Beispielsweise hier
>
> http://openbook.galileocomputing.de/c_von_a_bis_z/012_c_zeiger_006.htm
>
> "In solch einem Fall bietet es sich an, statt der Variablen radius
> einfach nur die Adresse der Variablen als Argument zu übergeben. Die
> Übergabe von Adressen als Argument einer Funktion wird call-by-reference
> genannt. Das Prinzip sehen Sie im abgeänderten Programmbeispiel:"

Es ist nicht automatisch richtig, nur weil's in irgendeinem Buch steht. 
Zur Vereinfachung kann man es auch anfangs auch abstrahiert als 
"call-y-reference" bezeichnen, aber richtig ist das eigentlich nicht.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren