Funktionsaufruf in C mit array type pointer

Gast #6759175
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
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
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
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
Ä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
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
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
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 #6759946
A. S. schrieb:
> 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.

Dieses schrecklich komplizierte Konzept, das im Standard 3 ganze Zeilen 
belegt.
Gast #6759954
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
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
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
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
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

Eine eigene Frage? Dieser Thread ist über 5 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.