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?
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?
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.
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.
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.
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.
>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.
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.
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
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.
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).
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.
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:"
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.
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.
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).
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.
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.