Moin Freunde, bekomme Ich irgendwie die Anzahl der Einträge raus?
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
|
Anzeige
|
Größe von einem "struct Array" bestimmen?!Moin Freunde, bekomme Ich irgendwie die Anzahl der Einträge raus?
Nein, in der Funktion nicht, denn da ist es kein Array mehr, sondern nur noch ein Zeiger. Wenn du die Groesse brauchst, musst du sie der Funktion als extra Parameter mit uebergeben. Die Groesse kannst du nur in dem Scope, in dem du das Array erstellt hast, ermitteln. Du kannst auch als letzten Eintrag im Array
{NULL , 0xff}
nehmen
Andererseits ist es in C eigentlich immer gut, die Arraygröße mit an die
Funktionen zu übergeben.
Dirk B. schrieb: > Du kannst auch als letzten Eintrag im Array > {NULL , 0xff} > nehmen > > Andererseits ist es in C eigentlich immer gut, die Arraygröße mit an die > Funktionen zu übergeben. Wie schon Bjarne sagen: "Rohe C/C++-Arrays sind so blöd, dass sie ihre eigene Länge nicht kennen".
Gast
#5293034
Wilhelm M. schrieb: > Wie schon Bjarne sagen: "Rohe C/C++-Arrays sind so blöd, dass sie ihre > eigene Länge nicht kennen". Müssen sie auch nicht. Wenn man das wirklich haben will, kann man sich ja problemlos ein struct typedefen, wo die Länge drinsteht. Dann muß man halt den Verwaltungs-Overhead mitbezahlen. Zudem ist die Länge ja auch keineswegs immer eindeutig. Beispielsweise habe ich öfter den Fall, wo Funktionen Pointer akzeptieren nebst einer Länge. Das ist aber nicht etwa die physikalische Buffergröße des dahinterliegenden Arrays bzw. Heap-Bereiches, sondern die Nutzdatenlänge, welche im allgemeinen echt kleiner als die Buffergröße ist - und sich außerdem erst zur Laufzeit bestimmt. Der verarbeitenden Funktion kann das aber egal sein. Natürlich hat man dann den Overhead, um sicherzustellen, daß die Nutzdaten nicht größer als der Buffer werden, aber das ist einmalig bei der Validierung der Fall, und danach bei der Verarbeitung entfällt jeder Verwaltungs-Overhead. Genau das scheint der typische Fall zu sein, was auch der wesentliche Grund ist, wieso C das so handhabt und nicht etwa nach Art von Pascal-Strings die Länge irgendwo unter der Haube mit durchreicht. Nop schrieb: > Wilhelm M. schrieb: > >> Wie schon Bjarne sagen: "Rohe C/C++-Arrays sind so blöd, dass sie ihre >> eigene Länge nicht kennen". > Zudem ist die Länge ja auch keineswegs immer eindeutig. Sollte sie aber sein ;-)) > Beispielsweise > habe ich öfter den Fall, wo Funktionen Pointer akzeptieren nebst einer > Länge. Das ist aber nicht etwa die physikalische Buffergröße des > dahinterliegenden Arrays bzw. Heap-Bereiches, sondern die > Nutzdatenlänge, welche im allgemeinen echt kleiner als die Buffergröße > ist - und sich außerdem erst zur Laufzeit bestimmt. Dann hast Du eben einen Buffer mit einer (Maximal)Größe, dass Du für eine dynamische Struktur wie etwa eine Queue, Stack, etc. verwendest. Das Problem des TO ist, dass er erkennen muss, was das "Zerfallen" eines Array-Bezeichners zu einem Zeigertyp ist (decay of array designator).
Gast
#5293143
Wilhelm M. schrieb: > Dann hast Du eben einen Buffer mit einer (Maximal)Größe, dass Du für > eine dynamische Struktur wie etwa eine Queue, Stack, etc. verwendest. Eben, aber zur Verarbeitung ist die meistens kleinere Nutzgröße relevant, weil danach Datenmüll folgen kann. Würde damit gearbeitet, d.h. bis ans Ende der Buffergröße, dann wären funktionale Fehler die Folge. Deswegen hat man kein Problem, wenn man beim Befüllen sicherstellt, daß die Nutzgröße kleiner gleich der Buffergröße ist, aber das ist eben nur an einem Punkt nötig und nicht überall danach. Dann aber entfällt auch die Notwendigkeit, die physikalische Arraygröße überhaupt weiterzureichen. Ein Problem hat man dann nur, wenn man einen Buffer herumreicht, bei dem jeder noch seinen Senf zusätzlich anhängen kann (d.h. nicht an vordefinierte Stellen), das riecht dann mit rohen Arrays schnell nach Overflow. Das ist aber auch kein besonders glückliches Design und sollte nach Möglichkeit vermieden werden. Abgesehen davon bin ich bei der Ausnutzung statischer Arraygrößen (via sizeof-Division) eh vorsichtig, weil einem sowas ganz schnell knallt, sobald man das dann z.B. im Mockup auf dem PC doch mal auf dynamisch allozierten Speicher umstellt. Dann lieber mit Größen-Defines, denen es egal ist, ob sie ein Array deklarieren oder als Futter für calloc dienen. > Das Problem des TO ist, dass er erkennen muss, was das "Zerfallen" eines > Array-Bezeichners zu einem Zeigertyp ist (decay of array designator). Ja gut, das muß man einmal verstehen. In dem Fall wäre aber ohnehin die Technik mit einem Sentinel-Eintrag am Ende die einfachste, und die wurde ja auch schon vorgeschlagen. Nop schrieb: > Wilhelm M. schrieb: > > Abgesehen davon bin ich bei der Ausnutzung statischer Arraygrößen (via > sizeof-Division) eh vorsichtig, weil einem sowas ganz schnell knallt, > sobald man das dann z.B. im Mockup auf dem PC doch mal auf dynamisch > allozierten Speicher umstellt. Dann lieber mit Größen-Defines, denen es > egal ist, ob sie ein Array deklarieren oder als Futter für calloc > dienen. Auch wenn ich mal sehr stark vermute, dass es sich hierbei um reinen C-Code handelt, so wäre die Lösung in C++ eben std::array für statische Arrays: dort ist die Größe Bestandteil des DT, und damit hat man kein Problem und keine Overhead. Und wenn man es eh generisch schreibt, kann man auch std::array durch std::vector im Aufrufer austauschen, ohne eine weitere Zeile zu ändern ... > bekomme Ich irgendwie die Anzahl der Einträge raus?
Ja. Mit einem simplen Macro:
Gast
#5293279
Wilhelm M. schrieb: > so wäre die Lösung in C++ eben std::array für statische > Arrays: dort ist die Größe Bestandteil des DT, und damit hat man kein > Problem und keine Overhead. Nein, das wäre keine Lösung. Siehe Vorposting, wo ich ausgeführt habe, daß nicht die Buffergröße entscheidend ist, sondern die Nutzdatengröße, welche kleiner gleich der Buffergröße ist. > Und wenn man es eh generisch schreibt, kann man auch std::array durch > std::vector im Aufrufer austauschen, ohne eine weitere Zeile zu ändern Wenn man Arrays nimmt, dann macht man das, weil man keine dynamische Speicherverwaltung haben will. Auch nicht hinter dem Rücken des Programmierers. Daher ist auch das keine Lösung. Dann müßte man sich schon Objekte basteln, die eine Art getter/setter haben, bei dem die Nutzdatenlänge reingepackt wird. Aber das kann man dann auch in C haben, wahlweise per struct oder per Parameter-Übergabe an die Funktion, die auch den Pointer bekommt (was das üblichere Idiom ist).
Gast
#5293281
Rufus Τ. F. schrieb: > Ja. Mit einem simplen Macro: Für den Fall, daß es sich dabei um eine globale Variable handelt. Aber dann braucht man das auch nicht als Parameter an die Funktion zu übergeben, sondern kann das gleich mit Globals machen. Einen Pointer zu übergeben, aber die Größe als globales Define zu realisieren, ist nicht sonderlich wartungsfreundlich. Eigentlich sogar ein Codesmell, finde ich. Rufus Τ. F. schrieb: > Ja. Mit einem simplen Macro: > #define MENUEANZAHL ((sizeof mainMenue) / sizeof menue_t) Ich würde diese Schreibweise wählen: #define SIZE_OF_ARRAY(array) (sizeof(array)/sizeof((array)[0])) Aber das ist eine Feinheit. Wilhelm M. schrieb: > Auch wenn ich mal sehr stark vermute, dass es sich hierbei um reinen > C-Code handelt, so wäre die Lösung in C++ eben std::array für statische > Arrays: dort ist die Größe Bestandteil des DT, und damit hat man kein > Problem und keine Overhead. std::array ist nur dann eine Lösung, wenn die Menüs, die an die Funktion übergeben werden, immer die gleiche Anzahl von Einträgen haben. Das wird hier wohl eher nicht der Fall sein. J. F. schrieb: > Rufus Τ. F. schrieb: >> Ja. Mit einem simplen Macro: >> #define MENUEANZAHL ((sizeof mainMenue) / sizeof menue_t) > > Ich würde diese Schreibweise wählen: > > #define SIZE_OF_ARRAY(array) (sizeof(array)/sizeof((array)[0])) > > Aber das ist eine Feinheit. ... und das geht eben nur (s.o.), wenn array nocht nicht zu einem Zeigertyp "zerfallen" ist. Yalu X. schrieb: > Wilhelm M. schrieb: >> Auch wenn ich mal sehr stark vermute, dass es sich hierbei um reinen >> C-Code handelt, so wäre die Lösung in C++ eben std::array für statische >> Arrays: dort ist die Größe Bestandteil des DT, und damit hat man kein >> Problem und keine Overhead. > > std::array ist nur dann eine Lösung, wenn die Menüs, die an die Funktion > übergeben werden, immer die gleiche Anzahl von Einträgen haben. Nö, jedes Menu kann eine unterschiedliche, aber zur Laufzeit konstante Anzahl von Elementen haben. > Das wird > hier wohl eher nicht der Fall sein. Glaube ich kaum, sonst wären nach Standard-C auch keine rohen Arrays möglich. Wilhelm M. schrieb: > ... und das geht eben nur (s.o.), wenn array nocht nicht zu einem > Zeigertyp "zerfallen" ist. Richtig, wie vorher schon angemerkt wurde. In meinen Augen ist es aber (in reinem C) akzeptabel wenn man einem kleinen Modul (welches die Daten des Arrays auswertet) die statische Definition global verarbeiten kann. Ich würde hier nicht von einem Code-Smell reden. J. F. schrieb: > Wilhelm M. schrieb: >> ... und das geht eben nur (s.o.), wenn array nocht nicht zu einem >> Zeigertyp "zerfallen" ist. > > Richtig, wie vorher schon angemerkt wurde. In meinen Augen ist es aber > (in reinem C) akzeptabel wenn man einem kleinen Modul (welches die Daten > des Arrays auswertet) die statische Definition global verarbeiten kann. > Ich würde hier nicht von einem Code-Smell reden. Das wollte ich auch nicht damit sagen. Jedoch kann ich mir wiederum viele Leute vorstellen, die nun glauben, diese Macro sei universell einsetzbar! Und genau das ist das Problem darin. genau dafür gibt es in C++ std::size<>: das erkennt den potentiellen Fehler, weil es für Zeigertypen nicht spezialisiert ist. Wilhelm M. schrieb: > Das wollte ich auch nicht damit sagen. Das war auch nicht auf dich bezogen, ging aber aus dem Kontext nicht hervor. > genau dafür gibt es in C++ std::size<>: das erkennt den potentiellen > Fehler, weil es für Zeigertypen nicht spezialisiert ist. Richtig, ein Grund warum ich C++ schöner finde. Der Threadersteller läßt uns aber nach wie vor im Dunkeln welche Sprache er in welcher Revision benutzt. Ich packe Arrays gerne in Structs. Ungetestet:
Wilhelm M. schrieb: > Yalu X. schrieb: >> Wilhelm M. schrieb: >>> Auch wenn ich mal sehr stark vermute, dass es sich hierbei um reinen >>> C-Code handelt, so wäre die Lösung in C++ eben std::array für statische >>> Arrays: dort ist die Größe Bestandteil des DT, und damit hat man kein >>> Problem und keine Overhead. >> >> std::array ist nur dann eine Lösung, wenn die Menüs, die an die Funktion >> übergeben werden, immer die gleiche Anzahl von Einträgen haben. > > Nö, jedes Menu kann eine unterschiedliche, aber zur Laufzeit konstante > Anzahl von Elementen haben. Wie müsste denn die Funktion test() deklariert werden, dass wahlweise ein std::array<menue_t,5> oder ein std::array<menue_t,6> als Argument übergeben werden kann? Man könnte test() zwar als Template-Funktion mit der Array-Größe als Parameter realisieren, das bläht aber ganz ordentlich, wenn man es mit vielen verschiedenen Array-Größen zu tun hat und test() eine etwas größere Funktion ist.
Gast
#5293690
Das Problem in C ist eigenlich, dass der Pointer zwei verschiedene Bedeutungen haben kann: a) Eine Liste von Menüeinträgen. Hier bieten sich 0-Terminierte Listen an, wenn man über genügend C-Erfahrung verfügt, statische Analysetools hat und weiss, was man tut. Der meiste konservative Code zerfällt dann in fast nichts, analog zu den einfachen STringroutinen. b) Einen konkreten Menüeintrag. Hier ist die Gesamtliste aber egal. Von daher hast Du das Problem nicht, wenn Du einigermaßen Erfahrung hast. Fall nicht, musst Du Dir die Informationen der Arrays wrappen. Das geht auch elegant, aber Du brauchst jede Menge Code mehr. Yalu X. schrieb: > Wilhelm M. schrieb: >> Yalu X. schrieb: >>> Wilhelm M. schrieb: >>>> Auch wenn ich mal sehr stark vermute, dass es sich hierbei um reinen >>>> C-Code handelt, so wäre die Lösung in C++ eben std::array für statische >>>> Arrays: dort ist die Größe Bestandteil des DT, und damit hat man kein >>>> Problem und keine Overhead. >>> >>> std::array ist nur dann eine Lösung, wenn die Menüs, die an die Funktion >>> übergeben werden, immer die gleiche Anzahl von Einträgen haben. >> >> Nö, jedes Menu kann eine unterschiedliche, aber zur Laufzeit konstante >> Anzahl von Elementen haben. > > Wie müsste denn die Funktion test() deklariert werden, dass wahlweise > ein std::array<menue_t,5> oder ein std::array<menue_t,6> als Argument > übergeben werden kann? > > Man könnte test() zwar als Template-Funktion mit der Array-Größe als > Parameter realisieren, das bläht aber ganz ordentlich, wenn man es mit > vielen verschiedenen Array-Größen zu tun hat und test() eine etwas > größere Funktion ist. Genau! Wir sind hier im Unterforum PC-Programmierung, und da ist die Code-Größe dann wohl egal. Bei µC hätte ich diese meine Antwort so nicht gegeben. Und außerhalb des µC sollte man dann, also bei variablen Größen, eben besser auf den fast immer optimalen Container std::vector<> gehen. Wobei der Code-Bloat eigentlich nur dann eintritt, wenn man fürchterlich ungeschickt vorgeht: also etwa eine Funktion test() schreibt, die sehr(!) lang ist und man sie nicht weiter untergliedert. Meistens ist es ja so, dass die öffentliche Schnittstelle als template gestaltet wird, intern dann aber was anderes abläuft, was oft nicht von den template-Parametern abhängt. Aber wie gesagt: das sollte einen eigentlich nur auf dem µC tangieren, wobei die heutigen Flash-Größen auch das Argument regelmäßig ad absurdum führen. Oft ist der RAM-Verbrauch auf µC der limitierende Faktor. Hat der TO eigentlich schon mal verlauten lassen, ob er nun C oder C++ will? Also das sollte für C sein. Hatte gedacht das man die Größe von dem Pointer Array raus bekommt. Von nem normalen Array das ich übergebe klappt das ja weil es eben nicht als pointer zerfällt.
Gast
#5293796
Jan H. schrieb: > Von nem normalen Array das ich übergebe klappt das ja weil es eben > nicht als pointer zerfällt. ??? Jan H. schrieb: > Hatte gedacht das man die Größe von dem > Pointer Array raus bekommt. Von nem normalen Array das ich übergebe > klappt das ja weil es eben nicht als pointer zerfällt. Du redest wirr. Jedes Array zerfaellt zu einem Pointer, wenn es an eine Funktion uebergeben wird. Egal ob es ein Array von Pointern ist, oder nicht. Ja, du bekommst die Groesse des Arrays raus, aber nur bevor du es der Funktion uebergibst. In der Funktion geht das dann nicht mehr. Geht:
Geht nicht:
Mach doch einfach mal ein vollstaendiges minimal Beispiel, damit wir nachvollziehen koennen was du willst/meinst. Kaj G. schrieb: > Jan H. schrieb: > Hatte gedacht das man die Größe von dem > Pointer Array raus bekommt. Von nem normalen Array das ich übergebe > klappt das ja weil es eben nicht als pointer zerfällt. > > Du redest wirr. Jedes Array zerfaellt zu einem Pointer, wenn es an eine > Funktion uebergeben wird. Egal ob es ein Array von Pointern ist, oder > nicht. > > Ja, du bekommst die Groesse des Arrays raus, aber nur bevor du es der > Funktion uebergibst. In der Funktion geht das dann nicht mehr. } > > Mach doch einfach mal ein vollstaendiges minimal Beispiel, damit wir > nachvollziehen koennen was du willst/meinst. Ich habe es aber schon mal mit nem Array hin bekommen.. CheckSize (char a[]) return (sizeof(a) /siueof(a|0]))
Beitrag #5293904 wurde von einem Moderator gelöscht.
Jan H. schrieb: > Ich habe es aber schon mal mit nem Array hin bekommen.. Nein, hast du nicht.
Der Compiler sagt dir schon, dass das Unfug ist.
Haette das Array jetzt zufaellig genau 8 Elemente, dann wuerde es fuer Dich so aussehen, als ob es klappen wuerde. Tut es aber nicht. Yalu X. schrieb: >> Nö, jedes Menu kann eine unterschiedliche, aber zur Laufzeit konstante >> Anzahl von Elementen haben. > > Wie müsste denn die Funktion test() deklariert werden, dass wahlweise > ein std::array<menue_t,5> oder ein std::array<menue_t,6> als Argument > übergeben werden kann? > Man könnte test() zwar als Template-Funktion mit der Array-Größe als > Parameter realisieren, das bläht aber ganz ordentlich, wenn man es mit > vielen verschiedenen Array-Größen zu tun hat und test() eine etwas > größere Funktion ist. Außerdem kann ich dann nicht mehr zur Laufzeit das Menü auswählen, denn ich muss ja dann bereits zur Compilezeit festelegen, welche Menügröße für diesen konkreten Aufruf gilt. Jan H. schrieb: > Ich habe es aber schon mal mit nem Array hin bekommen.. Dann war das kein C. > CheckSize (char a[]) > return (sizeof(a) /siueof(a|0])) a ist hier, auch wenn es irreführenderweise so aussieht, kein Array, sondern ein Zeiger. Du hast also die Größe eines Zeigers durch die Größe von dem, worauf er zeigt, dividiert. Merke: Arrays ohne Größe gibt es nicht, also kann char a[] keine Array-Definition sein. Die einzige Stelle, wo man die Größe weglassen kann, ist beim Definieren einer Array-Variable mit gleichzeitiger Initialisierung. Dann ergibt sich die Größe aus dem Initializer. Antwort schreibenBitte melde dich an, um einen Beitrag zu schreiben. |
Anzeige
|