Forum: Compiler & IDEs C und "call by reference"


von Hobbyprogrammierer (Gast)


Lesenswert?

Ich wollte eigentlich, daß mir ein Unterprogramm ein array füllt und es 
leer "call by reference" übergeben. Nun lese ich aber, daß das nur in 
C++ und nicht in C geht. Kann ich gcc dazu bringen, daß es trotzdem 
geht? Oder wie kann ich das machen?

von mar IO (Gast)


Lesenswert?

Hobbyprogrammierer schrieb:
> Ich wollte eigentlich, daß mir ein Unterprogramm ein array füllt und es
> leer "call by reference" übergeben. Nun lese ich aber, daß das nur in
> C++ und nicht in C geht.

Wo/Was hast Du das/da gelesen?

von Oliver (Gast)


Lesenswert?

Ein Array kann man in C grundsätzlich nur als call by reference 
übergeben.
Lies mal in deinem C-Buch nach, warum das so ist.

Oliver

von Rene H. (Gast)


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é

von Hobbyprogrammierer (Gast)


Lesenswert?


von Hobbyprogrammierer (Gast)


Lesenswert?

Jedenfalls hat der Threadstarter von obengenanntem Link im Prinzip das 
gleiche Problem wie ich.

von Hobbyprogrammierer (Gast)


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.

von Klaus W. (mfgkw)


Lesenswert?

Hobbyprogrammierer schrieb:
> Jedenfalls hat der Threadstarter von obengenanntem Link im Prinzip das
> gleiche Problem wie ich.

nein, hat er nicht.

Du willst ein Feld übergeben; das ist in C immer als CBR übergeben.
In dem anderen Thread ging es um andere Variablen (nicht Felder),
die sind in C immer CBV.

von Εrnst B. (ernst)


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.

von Rene H. (Gast)


Lesenswert?

Rene H. schrieb:
> In C++ wird "Call by Reference" mit einem Pointer übergeben:

Natürlich meinte ich beim zweiten Beispiel:

In C......

Grüsse,
René

von Klaus W. (mfgkw)


Lesenswert?

Hobbyprogrammierer schrieb:
> Ritchie schreibt:
>
> 1.8 Arguments - Call by Value...
Das hilft hier nicht, solange di nicht den restlichen K&R hier 
reinkopierst, zumindest den Teil mit den Feldern - dort ist es gerade 
andersrum.

Dein Zitat hier ist nur zur Verwirrung gut, sorry.

von Hobbyprogrammierer (Gast)


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.

von Hobbyprogrammierer (Gast)


Lesenswert?

Die Verwirrung ist perfekt; letzter Post war ein Irrtum.

von Stefan R. (srand)


Lesenswert?

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.

von DirkB (Gast)


Lesenswert?

Hobbyprogrammierer schrieb:
> Jetzt sollte eigentlich (der Logik nach was ich heute gelernt habe )die
> Adresse von Data angezeigt werden, oder?

Für Zeiger gibt es bei printf den Formatspecifier %p.
Ein Zeiger ist kein (unsigned) int

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Dann ist es formaljuristisch auf allen Plattformen korrekt.

Solange aber sizeof (int) == sizeof (int *) ist, funktioniert die 
--unsaubere-- Variante auch.

Den Irrtum hat der Hobbyprogrammierer ja auch schon selbst bemerkt.

von Klaus W. (mfgkw)


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).

von Stefan R. (srand)


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.

von Gelegenheitsprogrammierer (Gast)


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:"

von Jasch (Gast)


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.

von MAD (Gast)


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.

von Yalu X. (yalu) (Moderator)


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).

von Rufus Τ. F. (rufus) Benutzerseite


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.

von Garden (Gast)


Lesenswert?

Zu Pointern, Adressen, ... hilft vielleicht folgendes Video:

http://et-tutorials.de/3368/pointer-in-c/

von Rolf Magnus (Gast)


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.