Array-Größe in Funktion bestimmen
-
Hallo
Ich möchte die Größe eines Arrays bestimmen, soweit so gut, google liefert da eine ganze Menge, z.B.
printf("myArray has %d elements\n", sizeof(myArray) / sizeof(myArray[1]));
was auch einwandfrei klappt.
Wenn ich aber nun in einer Funktion die Größe eines übergebenen Arrays ermitteln will, z. B. so
int foo(char * textInp) { return (sizeof(textInp) / sizeof(textInp[1])); }
funktioniert das ganze nicht mehr?
Kann mir jemand sagen weshalb? Und wie kann ich das Problem beheben?Vielen Dank
Markus
-
Das geht nicht, weil du da nur die Größe eines Pointers siehst (schließlich ist textInp einer). Es gibt keine Lösung dafür, du musst entweder
a) und daa ist das übliche: Die Größe mit übergeben
b) geht nur in manchen Fällen: Falls es spezielel Werte die nicht vorkommen im Array, kannst du mit diesen das Ende markieren, so wie man es mit \0 bei Zeichenketten tut.
-
sizeof(char*)
liefert die Größe eines Zeigers, daher gibt es bei char-Arrays die Konvention, diese mit '\0' (entspricht dem Wert 0) zu terminieren.
Somit brauchen Funktionen, wie strlen o.Ä. nur einen Parameter. Bei anderen Arrays wie einem int* - Array klappt das natürlich nicht, eine 0 kann ja durchaus ein zulässiger Wert sein. In diesem Fall übergibt man einer Funktion für gewöhnlich die Größe des Arrays mit:void foo(int* array, size_t size);
Man, bin ich langsam..
-
int foo(char*textInp) { return (sizeof(textInp)/sizeof(textInp[0])); }
1. Das erste Element eines Arrays ist 0, nicht 1.
2. Du übergibst einen Zeiger, kein Array.
3. Arrays kannst du nicht einfach so übergeben, es sei denn, du forderst Speicher an und kopierst das Array manuell. Sonst geht das nur über Verweise.Meine Lösungsvorschläge:
1. Mach das Array global (unschön, aber es hat seinen Zweck).
2. Gib die Anzahl der Elemente bei der Parameterübergabe an.
3. Verwende Terminierungszeichen zum Markieren des Endes deines Array (in C-Strings 0).
4. Verwende eine globale Konstante, die die Anzahl der Elemente im Array sichert. So sparst du dir die Parameterübergabe, die Konstante kann nur über Umwege verändert werden (mach daher gleich eine Textersetzung mitdefine
) und du hast immer Zugriff auf die Länge, ohne x-Bytes für ein Terminierungszeichen zu verschwenden.
-
Die Alternative (von globalen Variablen mal abgesehen) für das Übergeben der Array-Größe wäre dann evtl noch eine Präprozessor-Anweisung à la
#DEFINE ANZAHL_SCHLUEMPFE 200
Macht natürlich nur Sinn bei Arrays mit wirklich fester Größe und stellt im Vergleich zur "fest angenommen" Kodierung der Arraygröße in der aufgerufenen Funktion lediglich einen Wartbarkeitsvorteil dar.
Sollten Schlumpfine und Schlaubischlumpf Nachwuchs zeugen oder Papa Schlumpf das zeitliche segnen, musst Du dann nur an der Stelle des defines den Wert ändern, statt an mehreren Stellen (Funktionsaufruf und Funktion).
Ansonsten - wie gesagt - bleibt nur die Übergabe der Größe als Funktionsparameter - bietet sich auch der Debugbarkeit halber an.
So hast Du z.B. beim Aufruf der Funktion üblicherweise gleich den entsprechenden Wert parat, bei #defines stellt sich das "eher schwierig" dar.
Am Hochachtungsvollsten
HübschDruck
-
Was hat mich da geritten?
Natürlich heißt es korrekterweise
#define SCHLUMPFCOUNTER 101
Also lowercase define
-
SPAM!
Hm, der Bot-Filter ist anscheinend aus - ich darf keine Kopfrechenaufgaben mehr lösen.
Ich wollt doch so gern Rechenkönigin werden!
-
ok, danke für die Vorschläge. Da das übergebene Array den "Rückgabestring" der Funktion enthalten soll, übergebe ich der Funktion nur ein deklariertes Array, es enthält also noch keine Werte, auch kein terminierendes 0.
Deswegen bleibt mir wohl nur die Übergabe der Arraylänge an die Funktion.Doch eine Frage habe ich noch:
Weshalb funktioniert das außerhalb der Funktion und nicht innerhalb? Denn was weiß der Prozessor (oder wer das das auch genau auswertet) mehr, falls die Grösse ausserhalb der Funktion ermittelt wird? Auch ausserhalb ist doch bloss der Pointer als Startadresse des Arrays bekannt???
-
fdsa schrieb:
Doch eine Frage habe ich noch:
Weshalb funktioniert das außerhalb der Funktion und nicht innerhalb? Denn was weiß der Prozessor (oder wer das das auch genau auswertet) mehr, falls die Grösse ausserhalb der Funktion ermittelt wird? Auch ausserhalb ist doch bloss der Pointer als Startadresse des Arrays bekannt???
Er weiß, dass es ein Verweis auf ein Array ist, welches auf dem Stack liegt. Anfänger haben oft Schwierigkeiten, zwischen Array und Zeiger zu unterscheiden, dabei kann ein Zeiger eben auch auf andere Sachen zeigen. Der Verweis auf das Array hingegen ist konstant und kann nicht neu zugewiesen werden, weshalb dies dem Compiler erlaubt, Informationen über das Array abzusichern.
Dieses Abfragen der Größe eines Arrays geht AFAIK nur bei Arrays auf dem Stack.
-
Ein Zeiger ist ein Zeiger ist ein Zeiger und insbesondere kein Array.
Der Compiler kann (verständlicherweise) nicht anhand einer Adresse bestimmen, wieviel Speicherplatz dahinter definiert wurde, zumindest nicht portabel.
Arrays als Funktionsparameter werden implizit zu Zeigern, per Sprachstandarddefinition, d.h.void funktion(char array[4711]) { size_t st=sizeof(array); }
wird niemals das von Anfängern und diversen Fachbuchautoren beabsichtigte Ergebnis liefern.
-
Wer als Autor ein solches Werk dann als Fachbuch bezeichnet, sollte sich nicht wundern, wenn es im Allgemeinen als Lachbuch angesehen wird
Mal kurz gesponnen:
Angenommen, man packt selbst ausschließlich druckbare Zeichen ins Array.
Könnte man dann - ziemlich unportabel und bestimmt nicht defensiv programmiert - die Größe des Arrays durch Suchen nach dem ersten "nicht druckbaren" Zeichen laut ASCII bestimmen?
-
In irgendeiner Funktion definierst du das Array. Und in der Funktion ist auch die Größe bekannt.
Globale Variablen ausgenommen.
-
PrettyP schrieb:
Wer als Autor ein solches Werk dann als Fachbuch bezeichnet, sollte sich nicht wundern, wenn es im Allgemeinen als Lachbuch angesehen wird
Mal kurz gesponnen:
Angenommen, man packt selbst ausschließlich druckbare Zeichen ins Array.
Könnte man dann - ziemlich unportabel und bestimmt nicht defensiv programmiert - die Größe des Arrays durch Suchen nach dem ersten "nicht druckbaren" Zeichen laut ASCII bestimmen?Die Annahme, dass uninitialisierter Speicher keine druckbaren Zeichen enthält, ist höchst gefährlich. Zum einen gibt es 96 druckbare Zeichen von 256 möglichen Werten eines Bytes, also hat es selbst bei postuliertem Zufall eine Chance von 37,5%, fehlzuschlagen, zum anderen musst du damit rechnen, dass das Array in Speicher gelegt wird, den du vorher schon mal benutzt hast, beispielsweise als String druckbarer Zeichen.
Man kann, wenn man unbenutzte Werte zur Verfügung hat, natürlich seine Daten mit einem solchen terminieren - so geschieht es ja bei Strings. Das muss man vorher aber auch selbst tun.
Ansonsten:
fdsa schrieb:
Denn was weiß der Prozessor (oder wer das das auch genau auswertet
) mehr, falls die Grösse ausserhalb der Funktion ermittelt wird?
Da liegt nämlich der Hase im Pfeffer begraben. sizeof ist keine Funktion, und sizeof-Ausdrücke werden nicht zur Laufzeit ausgewertet. Der Compiler ersetzt zur Compilezeit den sizeof-Ausdruck durch eine Zahl, und das kann er natürlich nur da, wo ihm die Größe des Arrays bekannt ist. Innerhalb einer Funktion, der ein Array als Zeiger übergeben wurde, ist das nicht der Fall.
-
aha, sehr interessant eure infos.
Besten Dank!
Markus