Forum: Compiler & IDEs Array als Adresse übergeben


von Hans (Gast)


Lesenswert?

Kann mir jemand kurz erklären warum die Übergabe der Adresse des Array 
so nicht funktioniert?
Die Ausgabe ist falsch...

1
#include<stdio.h>
2
3
void test(unsigned char array[]);
4
5
unsigned char testArray[5] = { 3, 4, 5, 6, 7 };
6
7
int main()
8
{
9
  unsigned char mainArray[5];
10
  test(mainArray);
11
  
12
  printf("%u",mainArray[0]);
13
      
14
  return 0;
15
}
16
17
void test(unsigned char array[])
18
{  
19
  array = testArray;
20
}

von Peter II (Gast)


Lesenswert?

Hans schrieb:
> void test(unsigned char array[])
> {
>   array = testArray;
> }

was soll das auch bewirken?

du änderst damit eine Lokale Variabel - mehr nicht. Damit das 
funktioniert muss man ein zeiger auf ein Array übergeben.

> unsigned char mainArray[5];
das kann aber sowieso nicht geändert werden, weil es kein Pointer 
sondern wirklich ein Array ist.

von Oliver S. (oliverso)


Lesenswert?

Weil C grundsätzlich und immer Funktionsparameter als "call by value" 
übergibt.

Oliver

von Hans (Gast)


Lesenswert?

Array werden doch nie mit "call by value" übergeben, oder nicht?
Dann müsste sich dies doch wie ein Pointer verhalten..

von Michael (Gast)


Lesenswert?

Hans schrieb:
> Array werden doch nie mit "call by value" übergeben, oder nicht?

C kennt nur call by value, nichts anderes.

Wie oft willst du das noch hören?

> Dann müsste sich dies doch wie ein Pointer verhalten..

Eben nicht.

von Peter II (Gast)


Lesenswert?

Hans schrieb:
> Array werden doch nie mit "call by value" übergeben, oder nicht?
> Dann müsste sich dies doch wie ein Pointer verhalten..

ja machen sie ja auch.


1
void test(int* i ) 
2
{
3
   i = (int*)0x1234;
4
}

ändert auch nichts, für den Aufrufer. Genau wie bei dir.

von Hans (Gast)


Lesenswert?

Michael schrieb:
> C kennt nur call by value, nichts anderes.

Was?!
http://openbook.galileocomputing.de/c_von_a_bis_z/012_c_zeiger_006.htm

Peter II schrieb:
> ändert auch nichts, für den Aufrufer. Genau wie bei dir.

Wie kann ich dann ein Array zurückgeben ohne ein return value zu 
verwenden?

von Sepp (Gast)


Lesenswert?

Du meintest wohl:
1
#include<stdio.h>
2
3
void test(unsigned char *array);
4
5
unsigned char testArray[5] = { 3, 4, 5, 6, 7 };
6
7
int main()
8
{
9
  unsigned char mainArray[5];
10
  test(mainArray);
11
  
12
  printf("%u",mainArray[0]);
13
      
14
  return 0;
15
}
16
17
void test(unsigned char* array)
18
{  
19
  array = testArray;
20
}

Allerdin gs kanne ich den Zweck nicht genau :-)

von Hans (Gast)


Lesenswert?

Hmm, mit Pointer habe ich es auch schon probiert. Funktioniert auch 
nicht.
Ich verwende den gcc compiler zum testen.

von Peter II (Gast)


Lesenswert?

Hans schrieb:
> Hmm, mit Pointer habe ich es auch schon probiert. Funktioniert auch
> nicht.

du brauchst ein pointer auf ein pointer
1
void test(unsigned char* Array[])

von Sepp (Gast)


Lesenswert?

Hans schrieb:
> Wie kann ich dann ein Array zurückgeben ohne ein return value zu
> verwenden?

Kommst Du aus der Delphi Welt?

von Karl H. (kbuchegg)


Lesenswert?

Peter II schrieb:
> Hans schrieb:
>> Hmm, mit Pointer habe ich es auch schon probiert. Funktioniert auch
>> nicht.
>
> du brauchst ein pointer auf ein pointer
>
>
1
> void test(unsigned char* Array[])
2
>

Nein. bracuht er nicht.
Er braucht die Erkenntnis, dass Arrays nicht als ganzes zuweisbar sind.
1
void test(unsigned char array[])
2
{  
3
  array[0] = testArray[0];
4
  array[1] = testArray[1];
5
  array[2] = testArray[2];
6
}

und das die vermaledeite Parametersyntax
1
void test(unsigned char array[])
nichts anderes als syntaktischer Zucker für
1
void test(unsigned char * array)
darstellt. Die beiden Formen sind nur unterschiedliche Schreibweisen für 
dasselbe.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Hans schrieb:
> Michael schrieb:
>> C kennt nur call by value, nichts anderes.
>
> Was?!
> http://openbook.galileocomputing.de/c_von_a_bis_z/012_c_zeiger_006.htm

Ändert nichts.
Der Zeiger wird per value übergeben.

Das man den Zeiger dazu benutzen kann, um mit seiner Hilfe auf die 
Variable des Aufrufers durchzugreifen, ändert daran nichts, das der 
Zeiger selbst per value übergeben werden. Der Zeiger ist in diesem Sinne 
quasi ein Hilfsmittel, um damit call-by-reference zu simulieren. Echtes 
call-by-reference funktioniert aber syntaktisch anders.
AM Beispiel C++
1
void foo( int & i )
2
{
3
  i = 5;
4
}
hier ist i eine Referenz. Innerhalb der Funktion benutzt du als ganz 
normale Variable, der du etwas zuweisen kannst. Da diese Referenz beim 
Aufruf an die Variable des Aufrufers gebunden wird, ändert damit eine 
Zuweisung an i die Variable des Aufrufers.
Das wäre ein echter call-by-Referenz. Das dieser Mechanismus unter der 
Decke vom Compiler mittels Zeiger realisiert wird, ist ein Detail, das 
dich als C++ Programmierer nicht zu kümmern braucht.
Ganz anders in C. Dort gibt es keinen echten call-by-refence. Er wird 
dadurch simuliert, das man der Funktion einen Zeiger auf die Variable 
des Aufrufers gibt
1
void foo( int * i )
2
{
3
  *i = 5;
4
}
5
6
int main()
7
{
8
  int j;
9
10
  foo( &j );
11
}
aber schon alleine dadurch, dass hier spezielle Syntax notwendig ist, um 
die Adresse der Variable des Aufrufers zu bestimmen, bzw. in der 
Funktion die Derferenzierung vorzunehmen, zeigt schon, das hier kein 
echter call-by-reference vorliegt. Denn bei einem echten 
call-by-reference benötigt man das nicht.
1
void foo( int & i )
2
{
3
  i = 5;
4
}
5
6
int main()
7
{
8
  int j;
9
10
  foo( j );
11
}

Ein echter call-ba-reference zeichnet sich dadurch aus, dass in der 
Argumentliste einfach nur die Kennung vorliegt, dass eine Referenz 
erwartet wird. Alles andere ist syntaktisch identisch zum call-by-value 
Fall

: Bearbeitet durch User
von Michael (Gast)


Lesenswert?

Hans schrieb:
>> C kennt nur call by value, nichts anderes.
>
> Was?!

Ja!

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

Das ist keine call by reference. Das ist das Nachahmen von call by 
reference mit Sprachmitteln, die da wären: call by value und Zeiger.

von Hans (Gast)


Lesenswert?

Karl Heinz schrieb:
> Er braucht die Erkenntnis, dass Arrays nicht als ganzes zuweisbar sind.

Es ist mir schon klar, dass der gesamte Inhalt eines Arrays nicht so 
kopiert werden kann. Aber es wird doch eh nur ein Zeiger auf das erste 
Element von der Funktion zurückgegeben.
Wieso kann ich dann nicht einfach die Startadresse von testArray als 
Pointer an array übergeben?

von ImLichteArbeitender (Gast)


Lesenswert?

Das man C ausschliesslich Call-By-Value ausdrücken kann ist definitiv 
falsch. Mit '*' (bzw. '&') werden Zeiger, also Referenzen deklariert.

Das aber ist nicht das Problem des TO.

Der springende Punkt ist ein bestimmter Satz im Kernighan&Ritchie in dem 
es sinngemäß heisst, das der Name einer Array-Variablen synonym zu einem 
Zeiger auf dieses Array ist. Anders ausgedrückt, wird jede Nennung des 
Namens einer Array-Variablen, falls sie nicht durch andere Operatoren 
noch modifiziert wird, durch einen Zeiger auf das erste Element dieses 
Arrays ersetzt. Man muss das so auffassen, das an der Stelle des Namens 
ein Literal erscheint, nämlich die Adresse des ersten Elementes.

Diese Aussage impliziert, dass die Nennung des Namens eines Arrays 
nicht mit der Adresse einer Variablen gleich zu setzen ist, die einen 
Zeiger enthält.
In der Verwendung des Namens gleicht dieser den Namen von 
Zeigervariablen in einer bestimmten Hinsicht. Man kann dereferenzieren 
bzw. den Index-Operator "[]" darauf verwenden.
In einer anderen Hinsicht aber entspricht er nicht den Namen von 
Zeigervariablen. Er kann nicht verwendet werden um den Wert selbst zu 
verwenden, da eben auch keine Variable existiert, die diesen Zeigerwert 
enthält.

Etwas klarer wird das vielleicht, indem man in dem Code des TO die 
Array-Namen, so wie es der Compiler macht durch die Addressen des ersten 
Elementes ersetzt.
1
#include<stdio.h>
2
3
void test(unsigned char array[]); 
4
5
// Die Adresse des ersten Elementes von testArray sei einmal mit 0x1234 angenommen.
6
unsigned char testArray[5] = { 3, 4, 5, 6, 7 }; 
7
8
int main()
9
{
10
  // Die Adresse des ersten Elementes von mainArray sei einmal mit 0x5678 angenommen.
11
  unsigned char mainArray[5];
12
13
  test(0x5678);
14
  
15
  printf("%u", * ((char *) (0x5678 + 0)));
16
      
17
  return 0;
18
}
19
20
void test(unsigned char array[])
21
{  
22
  // Beim Aufruf wurde der Zeiger 0x5678 übergeben.
23
  0x5678 = 0x1234;
24
}

Man sieht, dass man hier versucht ein Literal an ein Literal zuzuweisen. 
Das geht natürlich nicht.

von Karl H. (kbuchegg)


Lesenswert?

Hans schrieb:
> Karl Heinz schrieb:
>> Er braucht die Erkenntnis, dass Arrays nicht als ganzes zuweisbar sind.
>
> Es ist mir schon klar, dass der gesamte Inhalt eines Arrays nicht so
> kopiert werden kann. Aber es wird doch eh nur ein Zeiger auf das erste
> Element von der Funktion zurückgegeben.

Wo wird da irgendwas zurückgegeben?

> Wieso kann ich dann nicht einfach die Startadresse von testArray als
> Pointer an array übergeben?

Kannst du doch.
Aber halt nur innerhalb der Funktion.

Du wunderst dich doch auch nicht, dass in
1
void foo( int j )
2
{
3
  j = 8;
4
}
5
6
int main()
7
{
8
  int k = 5;
9
10
  foo( k );
11
}

k nicht den Wert 8 kriegt.

Durch
1
void test(unsigned char* array)
2
{  
3
  array = testArray;
4
}
hast du lediglich dem lokalen Pointer array innerhalb der Funktion einen 
anderen Wert gegeben. Mehr ist nicht passiert.

Lös dich von der Vorstellung, dass es in C echtes Call-by-Reference 
gäbe. Das gibt es in C nicht. Alles wird in C per Value übergeben. Das 
inkludiert natürlich auch einen Pointer, der ebenfalls per Value 
übergeben wird.

von Karl H. (kbuchegg)


Lesenswert?

ImLichteArbeitender schrieb:
> Das man C ausschliesslich Call-By-Value ausdrücken kann ist definitiv
> falsch. Mit '*' (bzw. '&') werden Zeiger, also Referenzen deklariert.

Ein Zeiger ist keine Referenz.

Bitte verwirr denn TO nicht noch mehr.

von Grillo (Gast)


Lesenswert?

Ein Problem ist auch, das mainArray ein Array ist.
Arrays kann man nach der Definiton weder in der Adresse noch in der 
Größe ändern.

Wenn mainArray ein Pointer wäre, dann könnte man da was machen.

von Michael (Gast)


Lesenswert?

ImLichteArbeitender schrieb:
> Das man C ausschliesslich Call-By-Value ausdrücken kann ist definitiv
> falsch. Mit '*' (bzw. '&') werden Zeiger, also Referenzen deklariert.

Die Aussage war, daß in C kein cbr existiert, sondern nur cbv.

Natürlich kann man alles nachbauen, mehr oder weniger elegant: cbr, 
Exceptions, Klassen und objektorientierte Programmierung, Continuations.

Daß C turing-vollständig ist, ist aber keine spannende Aussage.

von ImLichteArbeitender (Gast)


Lesenswert?

Karl Heinz schrieb:
> ImLichteArbeitender schrieb:
>> Das man C ausschliesslich Call-By-Value ausdrücken kann ist definitiv
>> falsch. Mit '*' (bzw. '&') werden Zeiger, also Referenzen deklariert.
>
> Ein Zeiger ist keine Referenz.

Selbstverständlich ist ein Zeiger eine Referenz. Was sonst? Synonym des 
Wortes "Referenz" ist "Verweis" und was ein Zeiger funktional anderes 
als ein Verweis auf eine Variable in C?

Michael schrieb:
> ImLichteArbeitender schrieb:
>> Das man C ausschliesslich Call-By-Value ausdrücken kann ist definitiv
>> falsch. Mit '*' (bzw. '&') werden Zeiger, also Referenzen deklariert.

> Die Aussage war, daß in C kein cbr existiert, sondern nur cbv.

Genau. Und das habe ich als falsch bezeichnet.
Wenn ich den zeiger einer Variablen übergebe, dann ist das eine 
Referenz. Also Call-By-Reference.

Ich mag mich ja irren, aber worin liegt mein Irrtum?
Sowohl sprachlich als auch von der Funktionsweise sehe ich nur 
Bestätigungen meiner Auffassung.

von ImLichteArbeitender (Gast)


Lesenswert?

Ich habe mal den Wikipedia-Artikel 
http://de.wikipedia.org/wiki/Call-by-reference dazu gelesen. So fasst 
Ihr das also auf.

von Michael (Gast)


Lesenswert?

ImLichteArbeitender schrieb:
>> Die Aussage war, daß in C kein cbr existiert, sondern nur cbv.
>
> Genau. Und das habe ich als falsch bezeichnet.

Eben.

> Wenn ich den zeiger einer Variablen übergebe, dann ist das eine
> Referenz. Also Call-By-Reference.

Nein, call by reference bezeichnet ein Sprachfeature, bei dem man nicht 
"zu Fuß" irgendwelche Zeiger übergeben muß.

call by value, call by name, call by reference, call by value-result 
haben klare Definitionen.

> Ich mag mich ja irren, aber worin liegt mein Irrtum?

Daß du das irgendwie als Angriff auf dich und deine Lieblingssprache 
interpretierst. C hat kein call by reference. Ende. Aus.

Das Übergeben von Zeigern by value ist keine call by reference, sondern 
etwas mti im wesentlichen demselben Effekt. Nur halt syntaktisch 
unschön.

von Knut (Gast)


Lesenswert?

@Hans
Ich würde es so machen.

1
#include<stdio.h>
2
3
void test(unsigned char **array);
4
5
unsigned char neuArray[5] = { 3, 4, 5, 6, 7};
6
unsigned char altArray[5];
7
unsigned char *meinP = altArray;
8
9
int main()
10
{
11
  printf("%u\n", meinP[0]);
12
  test(&meinP);
13
  printf("%u\n", meinP[0]);
14
      
15
  return 0;
16
}
17
18
void test(unsigned char **array)
19
{  
20
  *array = neuArray;
21
}

von Quack (Gast)


Lesenswert?

#include<stdio.h>

void test(unsigned char array[]);

unsigned char testArray[5] = { 3, 4, 5, 6, 7 };

int main()
{
  unsigned char* mainArray;
  test(&mainArray);

  printf("%u",mainArray[0]);

  return 0;
}

void test(unsigned char** array)
{
  *array = testArray;
}

von ImLichteArbeitender (Gast)


Lesenswert?

Michael schrieb:
>> Ich mag mich ja irren, aber worin liegt mein Irrtum?
>
> Daß du das irgendwie als Angriff auf dich und deine Lieblingssprache
> interpretierst. C hat kein call by reference. Ende. Aus.

Ich interpretiere das durchaus nicht als Angriff auf mich. Und eine 
Lieblingssprache habe ich nicht. Nur weil ich anderer (und irriger 
Meinung bin) und sie auch vertrete, heisst das ja nicht, dass ich mich 
angegriffen fühle.

Das "Ende. Aus." aber hat mich tatsächlich beleidigt.

Jedenfalls Danke für die Information. Das kein zusätzliches syntaktische 
Element vorkommen darf, sondern die Art und Weise implizit festgelegt 
ist, habe ich zwar mal gewusst und reflektiert aber im Laufe der Jahre 
ist das doch irgendwie verloren gegangen.

von Michael (Gast)


Lesenswert?

ImLichteArbeitender schrieb:
> Das "Ende. Aus." aber hat mich tatsächlich beleidigt.

Was ist denn in dich gefahren?

Schalt den Rechner mal ein paar Stunden ab und beruhige dich erstmal.

von ImLichteArbeitender (Gast)


Lesenswert?

Michael schrieb:
> ImLichteArbeitender schrieb:
>> Das "Ende. Aus." aber hat mich tatsächlich beleidigt.
>
> Was ist denn in dich gefahren?
>
> Schalt den Rechner mal ein paar Stunden ab und beruhige dich erstmal.

Ist denn etwas in mich gefahren? Was könnte das sein? Und ist Unruhe an 
sich etwas, dass man ändern sollte? Wenn wir uns schon gegenseitig 
Empfehlungen aussprechen, dann rate ich Dir zur Lektüre eines 
Psychologie-Buches und eines über die Umgangssprache.

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.