Funktionsaufruf in C mit array type pointer

Gast #6759175
Lesenswert?

Hallo zusammen,

ich versuche inerhalb einer Funktion den Inhalt eines Arrays mit fester 
Länge das per typedef definiert wurde zu ändern. Hier das vereinfachte 
Problem:
1
#include <stdio.h>
2
#include <stdint.h>
3

4
typedef uint16_t AT_eightWords[8];
5

6
void Update(AT_eightWords * eW)
7
{
8
    eW[0] = 42;
9
    eW[1] = 43;
10
    eW[2] = 44;
11
    eW[3] = 45;
12
}
13

14
AT_eightWords GLOBAL_eW;
15

16
int main()
17
{
18
    printf("Hello World\n");
19
    
20
    Update(&GLOBAL_eW);
21
    
22
    printf("%d %d %d %d", GLOBAL_eW[0], GLOBAL_eW[1], GLOBAL_eW[2], GLOBAL_eW[3]);
23

24
    return 0;
25
}

Der Compiler meint zu "eW[0] = 42;":
1
error: assignment to expression with array type

Mit
1
    *eW[0] = 42;
2
    *eW[1] = 43;
3
    *eW[2] = 44;
4
    *eW[3] = 45;
meckert der Compiler nicht aber es ergibt sich die Ausgabe "42 0 0 0"

Wie geht es richtig?
Beitrag #6759195 wurde von einem Moderator gelöscht.
(Firma: egal) #6759395
Lesenswert?

Walter T. schrieb:
> Ich habe das ungewöhnliche Typedef übersehen.
Der dürfte auch das problem sein. Das wäre dann ja quasi sowas hier und 
das passt nicht wirklich:
1
void Update(uint16_t[8] * eW)

So dürfte das eher hinkommen:
1
uint16_t GLOBAL_eW[8];
2
void Update(uint16_t *eW)
3
{
4
  eW[0] = 42;
5
  eW[1] = 43;
6
  eW[2] = 44;
7
  eW[3] = 45;
8
}
9
int main()
10
{
11
  Update(GLOBAL_eW);
12
...

oder wenn schon unbedingt typedef:
1
typedef uint16_t AT_eightWords;
2
AT_eightWords GLOBAL_eW[8];
3
void Update(AT_eightWords *eW)
4
{
5
  eW[0] = 42;
6
  eW[1] = 43;
7
  eW[2] = 44;
8
  eW[3] = 45;
9
}
10
int main()
11
{
12
  Update(GLOBAL_eW);
13
...
#6759416
Lesenswert?

A. S. schrieb:
> Max schrieb:
>> typedef uint16_t AT_eightWords[8];
>> void Update(AT_eightWords * eW)
>
> Das ist quasi ein Pointer auf ein Array, also ptr auf ptr.

Ein Pointer auf ein Array ja, aber kein Pointer auf einen Pointer.

> Vermutlich willst Du nur ein Array, dann lass das * vor eW weg.

Generell würde ich typedefs für Arrays vermeiden, weil das nur 
Verwirrung stiftet.

Irgend W. schrieb:
> Das wäre dann ja quasi sowas hier und
> das passt nicht wirklich:
> void Update(uint16_t[8] * eW)

Genauer:
1
void Update(uint16_t (*eW)[8])

… ein Zeiger auf ein Array aus 8 chars.
Gast #6759462
Lesenswert?

rmagnus schrieb:
> Generell würde ich typedefs für Arrays vermeiden, weil das nur
> Verwirrung stiftet.

In der Tat.  Eine Variable solchen Typs zu übergeben sieht aus wie ein 
"call by value" ist aber tatsächlich ein "call by reference".  D.h., 
ohne die Definition des Types zu kennen (die Definition der Variable 
reicht nicht!), kann man nicht erkennen, was der Code macht.
#6759569
Lesenswert?

Ändere die Update(AT_eightWords *eW) zu
Zu Update(uint8_t *eW)
Dein Datentyp ist ein 8 Felder großes Array
davon machst du einen Pointer *eW und willst ihn so behandeln als wäre 
er ein einfacher Pointer. Ich denke das geht schief. In der Update () 
brauchst du eigentlich nur einen einfachen uint8_t Pointer.
Gast #6759873
Lesenswert?

Oliver S. schrieb:
> Erst sagen, was da raus kommt, dann ausprobieren.

Die Größe des Arrays. Es ist aber egal, was da herauskommt.

Ein Array und ein Pointer sind bei einer Übergabe äquivalent.

Wenn der TO sich dessen klar wird, kann er auch herausklamüsern, was da 
passiert. Und ja, je nach Konstrukt was anderes. Beim TO

Max schrieb:
> *eW[0] = 42;
> *eW[1] = 43;
> *eW[2] = 44;
> *eW[3] = 45;

ist halt nur der erste Zugriff OK, der zweite zeigt auf Element 0 im 
Array dahinter (also nicht nächstes Element, sondern 8 Elemente, also 
außerhalb es eigentlichen Arrays.

Wenn er nicht nur "quasi" wie ich schrieb, sondern echt einen Ptr auf 
Ptr übergeben hätte, dann wäre auch der erste Zugriff OK, aber danach 
würde er die nächsten X Bytes als neuen Ptr interpretieren.

Egal. Den Mechnismus des TO habe ich erklärt, die Unterschiede zwischen 
Ptr und Array bei der Übergabe mögen Korinthen** unter sich ausmachen.
#6759880
Lesenswert?

A. S. schrieb:
> Oliver S. schrieb:
>> Erst sagen, was da raus kommt, dann ausprobieren.
>
> Die Größe des Arrays. Es ist aber egal, was da herauskommt.

Das ist nicht egal. Wäre es ein Pointer auf einen Pointer, dann käme da 
eben nicht die Größe des Arrays raus.

> Ein Array und ein Pointer sind bei einer Übergabe äquivalent.

Naja, es kommt in der Funktion ein Pointer auf das erste Element an. Das 
Array "zefällt" zu einem Pointer. Aber das gilt nicht rekursiv. Ein 
Pointer auf ein Array bleibt auch nach Übergabe ein solcher und zerfällt 
nicht zu einem Pointer auf einen Pointer.

> Egal. Den Mechnismus des TO habe ich erklärt, die Unterschiede zwischen
> Ptr und Array bei der Übergabe mögen Korinthen** unter sich ausmachen.

Der ist hier allerdings für das Verständnis essenziell.
Gast #6759887
Lesenswert?

Rolf M. schrieb:
> Der ist hier allerdings für das Verständnis essenziell.

Um zu verstehen, was genau der Fehler macht. In beiden Fällen ist der 
Fehler fatal und die Wirkung gleich: Ein unbeteiligter Speicherbereich 
wird verwendet und führt zu undefiniertem Verhalten.

Ich habe natürlich auch überlegt, ob ich dabei schreiben sollte, wo er 
jetzt hingreift. Es hilft dem TO aber nicht beim Verständnis. Und die 
Diskussion, wann ein Array zu einem einzelnen Ptr zerfällt, ist hier 
sicher nicht dem TO angemessen. Anscheinend ja nichtmal den meisten 
Diskutanten.
Gast #6759954
Lesenswert?

mh schrieb:
> Dieses schrecklich komplizierte Konzept, das im Standard 3 ganze Zeilen
> belegt.

Egal. Schau Dir den Thread hier an, wer da alles Probleme hat.

Oder schau Dir an, wie oft Du im Code sowas "int a[100]; ... foo(&a);" 
findest, also dass der Adressoperator auf ein Array gesetzt wird.

Wenn Du eine gute Erklärung hast, verlinke sie gerne. Aber hier ist es 
für den TO und andere mit ähnlicher Lernkurve schwer, noch was 
rauszuziehen.
Gast #6759968
Lesenswert?

A. S. schrieb:
> Wenn Du eine gute Erklärung hast, verlinke sie gerne. Aber hier ist es
> für den TO und andere mit ähnlicher Lernkurve schwer, noch was
> rauszuziehen.

Harte Realiät: Der TO ist idR nach einiger Zeit meist nur noch ein 
Beispiel.

Die Info könnte doch für irgendwen nützlich sein.
Gast #6759998
Lesenswert?

A. S. schrieb:
> mh schrieb:
>> Dieses schrecklich komplizierte Konzept, das im Standard 3 ganze Zeilen
>> belegt.
>
> Egal. Schau Dir den Thread hier an, wer da alles Probleme hat.
>
> Oder schau Dir an, wie oft Du im Code sowas "int a[100]; ... foo(&a);"
> findest, also dass der Adressoperator auf ein Array gesetzt wird.

Bist du sicher, dass du damit keine Probleme hast? Oder was ist deiner 
Meinung nach das Problem in deinem Beispiel?

> Wenn Du eine gute Erklärung hast, verlinke sie gerne. Aber hier ist es
> für den TO und andere mit ähnlicher Lernkurve schwer, noch was
> rauszuziehen.
Der Standard, oder wenn man dazu nicht in der Lage ist, reicht 
https://en.cppreference.com/w/c/language/conversion. Das was auf der 
Seite steht, sollte man als C Entwickler kennen.
Gast #6760005
Lesenswert?

mh schrieb:
> Der Standard, oder wenn man dazu nicht in der Lage ist, reicht
> https://en.cppreference.com/w/c/language/conversion. Das was auf der
> Seite steht, sollte man als C Entwickler kennen.

Der Link ist jetzt Dein konstruktiver Beitrag hier im Thread? Und da 
soll der TO oder jemand anders erkennen, was bei

A. S. schrieb:
> int a[100]; ... foo(&a);"

falsch ist? Jedenfalls erwarte ich da foo(a) oder foo(&a[0]) oder von 
mir aus auch foo(a+0). Oder irgendwas anderes, was foo erwartet. Nur 
"&a" gibt (wenn foo eine Funktion ist) in keinem Fall Sinn.

Ja, Compiler akzeptieren das, doch trägt es zu der Verwirrung bei, der 
der TO in seinem Code erlegen war.
Gast #6760033
Lesenswert?

A. S. schrieb:
> Jedenfalls erwarte ich da foo(a) oder foo(&a[0]) oder von
> mir aus auch foo(a+0). Oder irgendwas anderes, was foo erwartet. Nur
> "&a" gibt (wenn foo eine Funktion ist) in keinem Fall Sinn.

foo(a), foo(&a[0]) und foo(a+0) sind offensichtlich falsch! Mein foo ist 
übrigens void foo(int (*a)[100]).

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