einen schönen guten morgen,
ich habe eine Frage zur Übergabe eines Arrays an eine Funktion.
1
uint16_tarray_au16[5]={0};
Das Array kann ich ja in zwei verschiedenen arten übergeben.
1
function(array_au16);
2
function(&array_au16[0]);
Der Speicher vom array sieht ungefähr wie folgt aus
1
Name Location
2
array_au16 0x2008800
3
array_au16[0] 0x2008800
4
array_au16[1] 0x2008802
5
array_au16[2] 0x2008804
6
array_au16[3] 0x2008806
7
array_au16[4] 0x2008808
bei der ersten Variante, wird die Adresse des Arrays an für sich
übergeben, was auch gleichzeitig die Adresse des 1. Elementes ist.
Bei der zweiten Variante gebe ich explizit die Adresse des 1. Elementes
an.
Ist die Adresse des 1. Elementes immer die selbe Adresse wie die des
Arrays an für sich? Ich würde ja sagen, da ich kein Beispiel kenne, wo
dies nicht so ist.
Oder gibt es auch irgendwelche Konstrukte, wo die Adressen
unterschiedlich sind?
Rene schrieb:> bei der ersten Variante, wird die Adresse des Arrays an für sich> übergeben, was auch gleichzeitig die Adresse des 1. Elementes ist.
Nein, das ist nicht das gleiche. Die Adresse des Arrays verweist zwar
auf die selbe Speicherstelle wie die des ersten Elements, ist aber von
einem anderen Typ. Wenn man ein Array an eine Funktion übergibt,
"zerfällt" es in einen Zeiger auf das erste Element des Arrays. Die
Adresse des Arrays selbst wäre &array_au16.
> Bei der zweiten Variante gebe ich explizit die Adresse des 1. Elementes> an.>> Ist die Adresse des 1. Elementes immer die selbe Adresse wie die des> Arrays an für sich?
Ja, wobei die Varianten, die du zeigst, beide die Adresse des ersten
Elements übergeben.
> Ich würde ja sagen, da ich kein Beispiel kenne, wo dies nicht so ist.> Oder gibt es auch irgendwelche Konstrukte, wo die Adressen> unterschiedlich sind?
Das kann es nicht geben, denn dann würde die Pointer-Arithmetik nicht so
funktionieren, wie sie in C definiert ist.
Sofern sich die Frage auf C bezieht, ja, da ist die Adresse des Arrays
immer mit der Adresse des ersten Elements identisch.
Man kann in C gar keine Arrays an Funktionen übergeben bzw Arrays sind
in C keine vollwertigen Datentypen. Es werden einfach zu Zeigern auf das
erste Element (decay). Für allgemeine Funktionen braucht man im
Regelfall einen weiteren Parameter für die Länge des Arrays.
Harfner schrieb:> Sofern sich die Frage auf C bezieht, ja, da ist die Adresse des Arrays> immer mit der Adresse des ersten Elements identisch.
Gilt auch für C++.
Obwohl es da bessere Möglichkeiten gibt ein solches Array zu übergeben.
Wobei "besser" sich auf die Array Größe bezieht, die wird man in c immer
explizit mit übergeben müssen. Ist damit gerne eine Fehlerquelle mehr.
Rene schrieb:> Der Speicher vom array sieht ungefähr wie folgt ausName Location> array_au16 0x2008800> array_au16[0] 0x2008800> array_au16[1] 0x2008802> array_au16[2] 0x2008804> array_au16[3] 0x2008806> array_au16[4] 0x2008808
das würde ich ja mal in Frage stellen bei einem array aus uint16_t typen
Wenn du die Adresse übergibst, musst du aufpassen. Ich kann nicht sagen,
ob es am C-Standard oder dem Complier lag (Code Composer), aber ich
hatte folgendes Verhalten.
Die Funktion war definiert, sodass sie einen Zeiger auf ein Element des
Arrays übergeben bekommen hat. Es hat keinen Unterschied gemacht, ob ich
array_au16 oder &array_au16[0] in den Funktionsaufruf geschrieben habe.
Später habe ich dann die Funktion dann am Element 2 starten lassen
wollen und mit array_au16[2] aufgerufen. Ich dachte, der Compiler "merkt
das" oder meckert, der Aufruf ohne & und Index "ging ja auch".
Pustekuchen, der Wert in Element 2 wurde als Adresse interpretiert und
die Funktion ist "irgendwo" Amok gelaufen. Ich habe mir dann angewöhnt,
immer mit & und [0] aufzurufen, damit es durchsichtiger wird.
Mikro 7. schrieb:> Natürlich kann man:
nö, man übergibt dabei nur die Adresse des ersten Elements, wurde weiter
oben auch schon geschrieben. Dazu fehlt die Größe des Arrays.
Mann könnte aber eine Kopie übergeben, aber auch dabei müsste man die
Länge mit übermitteln... :-)
M
Patrick schrieb:> Ich dachte, der Compiler "merkt> das" oder meckert, der Aufruf ohne & und Index "ging ja auch".
Er meckert auch. Wenn du es erlaubst. Aber es ist kein Fehler sondern
"nur" eine Warnung.
A b e r: man sollte Warnungen wie Fehler behandeln und deren Ursache
beseitigen. Die kommen ja nicht ohne Grund.
Darum Warnlevel auf Maximum stellen.
&array_au16[2] ist das Gleiche wie (array_au16 + 2)
Maddin schrieb:> Mikro 7. schrieb:>> Natürlich kann man:>> nö, man übergibt dabei nur die Adresse des ersten Elements, wurde weiter> oben auch schon geschrieben. Dazu fehlt die Größe des Arrays.
Nein.
Die Größe ist implizit mit dem Typ verbunden. Du verwechselst erstes
Element und Array: Beide mit der gleichen Adresse aber unterschiedliche
Typen (wie bereits Ralf oben geschrieben hat). Während in C die Übergabe
von Arrays praktisch nicht genutzt wird (die Funktionen ist dann fix an
die Array Größe gebunden) gibt es in C++ mit templates durchaus
Anwendungsfälle.
Die Erfinder von C haben sich imho keinen Gefallen mit dem Array decay
getan (wahrscheinlich um den Entwicklern ein paar Zeichen zum Tippen zu
sparen). Die meisten Entwickler glauben daher dass ein Array
zwangsläufig zerfällt. :(
Mikro 7. schrieb:> Die Größe ist implizit mit dem Typ verbunden. Du verwechselst erstes> Element und Array: Beide mit der gleichen Adresse aber unterschiedliche> Typen (wie bereits Ralf oben geschrieben hat). Während in C die Übergabe> von Arrays praktisch nicht genutzt wird (die Funktionen ist dann fix an> die Array Größe gebunden) gibt es in C++ mit templates durchaus> Anwendungsfälle.
Hä?
OK, niemand verwendet bei der Definition eines "Array"-Paramerter die
"[]" mit Größenangabe in den Klammern.
Wenn man den Weg über einen Pointer geht, sollte die Funktion aber schon
wissen, wie viele Werte sich im Array befinden.
Das gilt aber nicht für "Strings" (array of char): Die haben ja ein
definiertes Endezeichen ('\0').
Durch die Verwendung von Pointern kann man dann auch Variablen als
"array der Länge 1" übergeben.
Diese Methode ist doch üblich, entspricht aber wohl nicht dem, wie es in
anderen Programmiersprachen gemacht wird.
Mit C++ und Templates kenne ich mich nicht aus.
STK500-Besitzer schrieb:> Das gilt aber nicht für "Strings" (array of char): Die haben ja ein> definiertes Endezeichen ('\0').
Das Endezeichen gibtves aber nicht im Zielarray.
Bei strcpy, strcat, … fehlt die Längenangabe des Zielbereichs.
Die vielen Bufferoverflows kommen nicht einfach so.
Dirk B. schrieb:> Das Endezeichen gibtves aber nicht im Zielarray.> Bei strcpy, strcat, … fehlt die Längenangabe des Zielbereichs.>
Nö. Beide o.g. Funktionen kann man keine Stringziellänge übergeben.
Darum muss man sich als Programmierer selber kümmern.
"snprintf" kümmert sich um die Ziellänge und gibt einen negativen Wert
zurück, wenn die übergebene Stringlänge überschritten würde.
Strings sind in C doch auch nichts anderes als "arrays". Die Länge des
Feldes muss man bei der Definition entweder selber festlegen 'char
Stringname["Länge"];', oder sie wird durch einen ersten Satz festgelegt:
'char Stringname[] = "BlaBlaBla";'
Das Array ist dann wegen des Endezeichens immer ein Zeichen länger.
Um diese Strings an eine Funktion zu übergeben, verwendet man ein "char*
" als Parameter im Funktionskopf.
> Die vielen Bufferoverflows kommen nicht einfach so.
Die kommen davon, dass jemand beim Programmieren wieder irgendwas
ignoriert hat.
Mikro 7. schrieb:> Beispiel für Array ohne Zerfall in C:
Gerade bei der Ausgabe einzelner char ist eine feste Array-Größe doch
Quatsch, oder weißt du immer, wie lang dein längster String ist?
Bei der Übergabe von Strings hat man sich bei C ein Endezeichen gegönnt,
weil es im ASCII-oder ANSI-Zeichensatz nicht als druckbares Zeichen
vorkommt.
Für Arrays anderer Typen überträgt man halt deren Länge noch mit dazu.
Wo ist das Problem?
Mikro 7. schrieb:> STK500-Besitzer schrieb:>> Wo ist das Problem?>> Das Thema war wie Arrays übergeben werden können, oder?
ja, aber vielleicht etwas anwendungsbezogener.
Der Threadopener hat ja schon die Pointerversion aufgeführt, und den
Unterschied zwischen den beiden von ihm genannten Versionen erfragt.
In der o.g. Version gibt es keinen Unterschied.
Interessant wird es, wenn man die Daten erst ab einem bestimmten Eintrag
des Arrays übertragen will (z.B.: der vordere Teil wurde schon
anderweitig geparst). Dann ist die Version mit "&Bla[96]" sehr
praktisch.
Mikro 7. schrieb:> Dort wird beschrieben was ein Pointer auf ein Array ist.
Und was nützt mir der Pointer auf ein Array das innerhalb meiner
Funktion nicht bekannt ist?
DPA schrieb:> Ich schon [1]. Speziell bei mehrdimensionalen Arrays variabler länge> sind die extrem praktisch. Es ist zu beachten, dass auch die zu Pointern> zerfallen, aber zu Pointern auf Arrays, statt simple Pointer.
Das war vielleicht etwas zu allgemein geschrieben.
Hier ging es aber auch bisher um eindimensionale.
DPA schrieb:> Was ich auch manchmal mache, sind typdefs bei VM typen, wenn auch recht> selten. Die zerfallen nicht.
Ich verwende haufenweise (packed) structs.
Und wenn man per Pointer auf deren Inhalt zugreifen will unions.
"offsetof()" ist auch eine tolle "Funktion" (eigentlich ein Makro).
STK500-Besitzer schrieb:> Für Arrays anderer Typen überträgt man halt deren Länge noch mit dazu.> Wo ist das Problem?
Das Problem, ist hier das Potential für Irrtümer.
Du sagst es ja selber:
STK500-Besitzer schrieb:> Die kommen davon, dass jemand beim Programmieren wieder irgendwas> ignoriert hat.
Monate/Jahre kann es unentdeckt schlummern.
Bis der Zufall zuschlägt, oder ein Angreifer die Lücke findet.
Leider kommt das so häufig vor, dass es weh tut.
Kann natürlich sein, dass dir das noch nie passiert ist, oder niemals
passieren wird.
Ich halte das für eins der größten Probleme in C.
Hier mal der Arduino C++ Weg(oder einer davon):
Ja, das kostet etwas Code, da die Funktion (evt. mehrfach) überladen
wird.
Zur Belohnung erhält man die Sicherheit nicht über Arraygrenzen hinweg
"fremde" Daten überschreiben zu können. Da man die Größe nicht händisch
anfassen muss, ist auch kein menschlicher Irrtum, an der Stelle,
möglich.
EAF schrieb:> Hier mal der Arduino C++ Weg(oder einer davon):
C++? Und dann auch noch mit Templates?
EAF schrieb:> Ja, das kostet etwas Code, da die Funktion (evt. mehrfach) überladen> wird.
Seit wann unterstützt C Überladungen und dergleichen?
STK500-Besitzer schrieb:> C++? Und dann auch noch mit Templates?STK500-Besitzer schrieb:> Mit C++ und Templates kenne ich mich nicht aus.
Hier hast du jetzt mal eine Vorführung bekommen!
Arrays und Pointer, sind ein guter Grund für "Stop teaching C!"
Nicht, dass es in C++ immer ohne Pointer geht, aber immerhin gibt es in
vielen Fällen robustere Alternativen.
STK500-Besitzer schrieb:> Seit wann unterstützt C Überladungen und dergleichen?
Kaum, bis gar nicht.
Allerdings: In der Arduino Welt ist das schon üblich.
Da das eine C++ Welt ist.
EAF schrieb:> Kaum, bis gar nicht.>> Allerdings: In der Arduino Welt ist das schon üblich.
Dann kann man auch gleich python verwenden.
EAF schrieb:> Arrays und Pointer, sind ein guter Grund für "Stop teaching C!"
Assembler sollte man auch gleich verbieten und seine Verwendung mit
Kerkerhaft bestrafen.
STK500-Besitzer schrieb:> Dann kann man auch gleich python verwenden.
Es kann sein, dass dir C++ nicht schmeckt. Dagegen kann ich auch nichts
sagen.
Aber dem C++ deswegen die Existenzberechtigung abzusprechen, geht
sicherlich zu weit.
Nee... dein Python vergleich ist etwas absurd.
STK500-Besitzer schrieb:> Assembler sollte man auch gleich verbieten und seine Verwendung mit> Kerkerhaft bestrafen.
Warum sofort verbieten?
Ein paar ASM Kenntnisse werden bestimmt nicht schaden.....
EAF schrieb:> DPA schrieb:>> Aber bei C ist das natürlich ok?> Wer tut das denn?> Ja wo isser denn?EAF schrieb:> Arrays und Pointer, sind ein guter Grund für "Stop teaching C!"
Hand an Nase?!
STK500-Besitzer schrieb:> Hand an Nase?!
Das ist doch kein Verbot C zu lernen!
Das ist eine Empfehlung mit C++ statt C zu beginnen.
Dafür gibt es mehrere Gründe, einer davon:
Wer die prozedurale Programmierung einmal so richtig gefressen hat, ist
auf Lebenszeit für die anderen Programmierparadigmen verdorben.
OK, Der Sprung/Weg mag machbar sein, aber die prozedurale Denkweise
liegt da derbe im Weg rum.
Der Weg von C++ zu C ist wesentlich leichter zu gehen, als umgekehrt.
Auch lernt man gefühlte 99% des C gleich mit, wenn man mit C++ beginnt.
Also: "Stop teaching C!"
Ist ein Aufruf an die Ausbilder.
(und auch nicht von mir erfunden)
EAF schrieb:> Arrays und Pointer, sind ein guter Grund für "Stop teaching C!"
Du meinst C-Arrays.
Eines meiner Lieblingszitate (von Kate Gregory), weswegen ich ja hier
regelmäßig was ab bekomme ;-)
> Nicht, dass es in C++ immer ohne Pointer geht, aber immerhin gibt es in> vielen Fällen robustere Alternativen.
std::array<> bzw. für die Arduino-Leute eine kleine Fingerübung für den
Einstieg in templates.
Wilhelm M. schrieb:> Du meinst C-Arrays.
Ach, die finde ich schon ok...
Es ist nur der Umgang damit, welcher die Probleme/Sorgen bereiten kann.
Wilhelm M. schrieb:> std::array<> bzw. für die Arduino-Leute eine kleine Fingerübung für den> Einstieg in templates.
std::array<> steht für die 32Bit Arduinos breit.
Bei den 8Bit muss man da nacharbeiten, die Libstdc++ (oder Teile davon)
hinzufügen.
Der ganze std::irgendwas ++ Kram hat für mich nichts mit C zu tun.
Blödsinn zu behaupten man bräuchte nur das eine lernen um das andere
auch zu können, das sind zwei verschiedene Sprachen für mich.
EAF schrieb:> STK500-Besitzer schrieb:>> Hand an Nase?!>> Das ist doch kein Verbot C zu lernen!> Das ist eine Empfehlung mit C++ statt C zu beginnen.
Die käme in meinem Fall 20 Jahre (fast 30 Jahre) zu spät.
Ist C++ einfacher? Ich fand C als Einstieg für (8-Bit-)Mikrocontroller
sehr einfach, weil es sehr dicht an der Controller-Struktur war.
Ich habe nichts gegen C++. Aber auf einem 8-Bitter? Verplempert man
damit nicht ohne Ende Resourcen?
EAF schrieb:> OK, Der Sprung/Weg mag machbar sein, aber die prozedurale Denkweise> liegt da derbe im Weg rum.
Innerhalb einer Klasse muss man doch wieder prozedural ("Methoden")
programmieren, oder sehe ich das falsch?
STK500-Besitzer schrieb:> Innerhalb einer Klasse muss man doch wieder prozedural ("Methoden")> programmieren, oder sehe ich das falsch?
Mein Reden!
Das prozedurale lernt man gleich mit, wenn man mit C++ anfängt.
STK500-Besitzer schrieb:> Ist C++ einfacher?
Würde ich eher sagen: Nein!
Aber "einfacher" heißt ja auch nicht immer gleichzeitig "besser".
STK500-Besitzer schrieb:> Aber auf einem 8-Bitter? Verplempert man> damit nicht ohne Ende Resourcen?
Nicht automatisch.
z.B. gibt es viele Dinge, welche sich zur Kompilezeit erledigen lassen.
C hat da nur den Präprozessor, keine vollwertige Sprache
C++ bringt da zusätzlich eine "Turing vollständige" weitere Sprache mit,
ich nenne sie mal "Die Template Engine"
STK500-Besitzer schrieb:> Die käme in meinem Fall 20 Jahre (fast 30 Jahre) zu spät.
Das kann sein...
Wenn man 20 Jahre nach C, anfängt C++ zu lernen, ist nicht die Sprache
das Problem, sondern eher die festgefahrenen Denkweisen.
Natürlich sind diese Denkweisen, die prozedurale Sicht, gut und richtig
so. Nur eben nicht auf die OOP zu 100% übertragbar.
Vereinfacht gesagt:
Ein C Programm ist Kontrollfluss orientiert (wenn dies, dann das)
Ein OOP C++ Programm ist Beziehungsorientiert (die Objekte senden sich
Nachrichten)
Mikro 7. schrieb:> Die Größe ist implizit mit dem Typ verbunden.
Nein! Bei der Übergabe eines Array an eine Funktion muß man in C der
Funktion mitteilen wie groß das Array ist. C kann aus dem übergebenen
Zeiger (auf das erste Element) nicht die Länge des Arrays bestimmen.
Mikro 7. schrieb:> (die Funktionen ist dann fix an> die Array Größe gebunden)
Nein ist sie nicht! Man übergibt die Länge des Arrays als 2. Parameter.
z.B.:
1
voidfunction(intarray[],intlaenge){}
Man könnte das Array in einem struct verpacken, dann könnte man das
struct übergeben.
Zeno schrieb:> Nein! Bei der Übergabe eines Array an eine Funktion muß man in C der> Funktion mitteilen wie groß das Array ist. C kann aus dem übergebenen> Zeiger (auf das erste Element) nicht die Länge des Arrays bestimmen.
Da wurde eben das Gegenteil gezeigt.
Allerdings mit dem Nachteil, dass man für jeden Arraytype eine eigene
Funktion schreiben muss.
Vergleichbar mit dem automatischen Überladen bei C++ Templatefunktionen
Ich komme mir richtig dumm vor denn ich verstehs nicht. Wenn ich ein
Array übergeben wollte, dann musste ich zuerst ein neues erstellen und
dieses dann Byte für Byte einlesen.
Alexander schrieb:> Wenn ich ein Array übergeben wollte,
Die Möglichkeiten sind begrenzt!
C und C++, per Pointer oder in eine Struktur verpackt
C++, per Referenz