Char-Array-Problem mit Größe

Hi, habe folgenden Code:

unsigned char a[] = {55,12,3,74,77,23,4,99,25};
unsigned char *g = a;

printf("%d „,sizeof(a));
printf(“%d ",sizeof(g));

Bekomme als Ausgabe
"9 4 "

Verkürze ich den Array (z.b. auf 3) bekomme ich „3 4“. wenn ich die speichergröße über g ermittle ist sie immer 4. Warum?

Howdy,

unsigned char a[] = {55,12,3,74,77,23,4,99,25};
unsigned char *g = a;

printf("%d „,sizeof(a));
printf(“%d ",sizeof(g));

Verkürze ich den Array (z.b. auf 3) bekomme ich „3 4“. wenn
ich die speichergröße über g ermittle ist sie immer 4. Warum?

weil die Groesse eines Pointers auf deinem System 4 bytes betraegt. In anderen Worten sizeof(g) ist gleich sizeof(pointer to char).

Gruss
norsemanna

ok, danke

und wie kann ich jetzt über den pointer die größe (9) ermitteln?
ich möchte einer funktion einen pointer auf mein a-array übergeben, die dann damit was macht. aber dazu brauch ich die größe. und extra nen neuen parameter hinzufügen halt ich für übertrieben wenn mans auch auslesen kann

Hi,

und wie kann ich jetzt über den pointer die größe (9)
ermitteln?

C/C++ Arrays verwalten ihre Grösse nicht selbst. Weder bei Zugriff auf das Array, noch bei Zugriff über einen Pointer steht also die Grösseninformation zur Verfügung.

Es gibt nur die Option, einen weiteren Parameter vom Typ size_t zu vereinbaren, welcher dann mit (sizeof(array)/sizeof(array_element_t)), hier also sizeof(a)/sizeof(unsigned char) aufgerufen wird.

Und es gibt die Option, einen std::vector zu benutzen, welcher dann die Grösse intern verwaltet.

std::vector

Gruss
Thomas

C/C++ Arrays verwalten ihre Grösse nicht selbst. Weder bei
Zugriff auf das Array, noch bei Zugriff über einen Pointer
steht also die Grösseninformation zur Verfügung.

ok, aber warum funktioniert das dann wenn ich sage „sizeof(a)“ (da kam ja 9 raus)?

gibts irgendwo eine verständliche erklärung (deutsch?) wie c im detail funktioniert (mit speicherverwaltung, etc)?
ich glaube das würde mir sehr weiterhelfen, da es noch so einige lücken zu schließen gibt (mein prof hat das nur ansatzweise angerissen und er konnte das auch nicht besonders gut rüberbringen)

Hi,

ok, aber warum funktioniert das dann wenn ich sage „sizeof(a)“
(da kam ja 9 raus)?

sizeof(a) ist eine zur Zeit der Übersetzung bekannte Zahl, denn a ist ein Array mit bekannter Grösse. Wenn du auf dieses Array mit deinem Pointer zugreifst, steht diesem Typ diese Information aber nicht mehr zur Verfügung. Es ist richtig, dass K&R damals die Sprache so definiert hätten können, dass der Compiler diese Information automatisch propagiert (also z.B. in einer Funktion

int func(int a[])

für a[] die richtige Grösse zur Verfügung steht), aber das ist eben nicht der Fall und somit wirst du mit den Mitteln der Sprache auskommen müssen.

gibts irgendwo eine verständliche erklärung (deutsch?) wie c
im detail funktioniert (mit speicherverwaltung, etc)?

Ich empfehle dir, ein paar grundlegende Bücher über die Programmiersprache C und dann C++ zu lesen. Davon gibt es tausende. Fakt bei jeder Programmiersprache wird aber bleiben, dass du auch nach 20 Jahren Programmierung damit immer noch das eine oder andere nachschlagen werden musst. Und Fakt bleibt auch, dass du um die englische Sprache final nicht herumkommst.

ich glaube das würde mir sehr weiterhelfen, da es noch so
einige lücken zu schließen gibt (mein prof hat das nur
ansatzweise angerissen und er konnte das auch nicht besonders
gut rüberbringen)

Professoren geben dir immer nur den Anreiz, dich in etwas besser einzulesen. Deshalb wird der dir auch niemals eine komplette Programmiersprache beibringen.

Gruss
norsemanna

Hallo Leute

Soviel ich weiss, gibt es auch noch die alte, aber gute „strlen(a)“, die auch mit einem extra Zeiger funktioniert, da das Char-Array ja immer nullterminiert ist.

lG
Martin B

Martin,

Soviel ich weiss, gibt es auch noch die alte, aber gute
„strlen(a)“, die auch mit einem extra Zeiger funktioniert, da
das Char-Array ja immer nullterminiert ist.

dein Kommentar ist off-topic und führt nur in eine falsche Richtung!

Weder ist jedes char-Array null-terminiert (das sind zwangsweise nur solche, die mit einer character string Konstanten initialisiert werden) noch ist das array null-terminiert, welches der Ursprungsposter hier in seinem Beispiel verwendet hat (es könnte sogar sein, dass dort mittendrin eine \0 steht und deshalb strlen ein falsches Resultat liefert).

Zudem hat strlen einen const char* als Parameter, nicht einen const unsigned char*.

Gruss
norsemanna

Hossa :smile:

Beim Compilieren legt der Compiler intern eine Symboltabelle an. Darin trägt er alle wichtigen Informationen über Bezeichner ein, die im Quelltext deklariert werden.

unsigned char a[] = {55,12,3,74,77,23,4,99,25};
unsigned char *g = a;

Dies ergibt zwei Einträge in der Symboltabelle, die in etwa so aussehen:

Bezeichner Datentyp Size ...
a char-array 9 ...
g char-pointer 4 ...

Jeder Compiler macht das ein wenig anders. Jedenfalls wird bei Bezeichnern, die ein Array symbolisieren, die Anzahl der Elemente in die Symboltabelle eingetragen.

Bei sizeof(a) schaut der Compiler in der Symboltabelle unter „a“ nach und liefert dir die 9 Elemente zurück. Bei sizeof(g) schaut er bei „g“ nach und liefert er die 4 aus der Symboltabelle. Wenn du nun dem Zeiger g die Startadresse des Arrays a zuweist, ändert das nichts an der Size, die in der Symboltabelle gespeichert ist. Deswegen kannst du die Größe eines Array nur abfragen, indem du den Bezeichner angibst, der das Array tatsächlich symbolisiert.

Die Symboltabelle ist übrigens auch der Grund, weshalb jeder Bezeichner vor seiner ersten Verwendung im Programm deklariert (=in die Symboltabelle eingetragen) werden muss.

Viele Grüße

unsigned char a[] = {55,12,3,74,77,23,4,99,25};

sizeof(array)
-> liefert nur dann die richtige größe zurück, wenn das array statisch angelegt wird.

unsigned char a[9];
-> hier weiß der Compiler, dass a ein array mit 9 elementen ist, da der speicher des arrays statisch allokiert ist.

b deklarierst du nicht als array, sondern als pointer auf ein array.
Woher soll der Compiler wissen wie groß das zuletzt zugewiesene array ist??

sizeof() gibt dir IMMER die Größe des Speichers an, für den der Bezeichner allokiert wurde.
unsigned char* b;
ist vom Datentyp: Pointer auf unsigned char
und der ist nunmal immer 4 byte groß

unsigned char a[5]
bzw.
unsigned char a[]={1,2,3,4,5}
ist vom Datentyp: Array von 5 Elementen

Was du willst - ein Array einer Funktion übergeben, die dann daraus die Array-Größe ermittelt ist nicht möglich!
Du musst dann die größe als extra Parameter der Funktion übergeben.
Bei (terminierten) Strings kannst du die Größe einfach mit strlen() bestimmen - was aber unsicher ist!

Hi wissensgig,

ich frage mich gerade, was du - zusaetzlich zu den bereits gesagten - beigetragen hast …

unsigned char* b;
ist vom Datentyp: Pointer auf unsigned char
und der ist nunmal immer 4 byte groß

Insbesondere diese Aussage ist nicht korrekt. Es gab/gibt Systeme, auf denen sizeof(unsigned char*) == 2 ist und es gibt auch Systeme, auf denen z.B. sizeof(unsigned char*) == 8 ist.

Bei (terminierten) Strings kannst du die Größe einfach mit
strlen() bestimmen - was aber unsicher ist!

Auch nicht korrekt. Falls der String null-terminiert ist, gibt es nichts unsicheres an strlen. Falls aber zusaetzlich zwischendrinn ein \0 steht, so liefert strlen() nicht das gewuenschte Resultat…
strlen ist nur dann unsicher, wenn der String nicht null-terminiert ist.

Gruss
norsemanna

Ich glaube er meinte, egal ob char a[5] oder char a[9] ist sizeof b immer 4 daher egal was a genau für eine größe hat

mit den nullterminiert hast du unrecht. gefährlich wird das ganze nicht, wenn ein Nullelement in der Reihe ist, sonder kein abschließendes Nullelement existiert.

Wenn du schreibst b=a, sagst du damit, das b die Position von a[0] im Speicher. Du kannst jederzeit b auf eine andere Adresse zeigen lassen.
zB.: b=c wenn c auch ein Array von char ist.

char[3] a; //Array im Stack (3Byte Speicher für a[0]-a[2])
char[3] c; //Array im Stack (dito)
char[] b; //Zeiger auf einen char (4Byte speicher auf 32Bit-System)
//…

b=a; //Jetzt zeigt b auf a
//Alternative: b=&a[0]

b[1]=‚A‘;
// jetzt ist a[1]=‚A‘

b=&c[0]; //einfacher auch b=c;
b[1]=‚B‘;
//jetzt ist auch c[1]=‚B‘, a[1] ist weiterhin ‚A‘

//auch das ist möglich:
b=&a[1];
b[1]=‚C‘;
//jetzt ist a[2]=‚C‘
//man kann also bei b nie genau wissen, wie groß das array ist, auf das es zeigt. char[] b ist gleich char* b und damit ist b nur die adresse eines Beliebigen char wertes. Man kann als „syntaktische Zuckerl“ wie auf ein Array zugreifen. man muss vorher sicher stellen, dass man keinen nicht reservierten speicher zugreift.

b=a;
b=b+2; //Das ist möglich!, da b ein Zeiger ist
//b zeigt jetzt zwei chars weiter als a[0]
//also ist b=&a[2]

b[1]=‚D‘;
//Diese Zeile führt zu nicht vorhersehbaren ergebnissen
b[0] ist a[2] also ist b[1] a[3], was laut definition nicht mehr teil des arrays ist.

Es muss einem klar werden, dass char[] und char[n] (n ist ein Literal zB 3)völlig verschiedene sachen darstellen.
char[] ist char* ist ein Zeiger auf einen char wert.
char[n] sind n char werte im stack. in meinem bsp. ist a eine feste adresse (die differenz zwischen anfang der funktion und a ist immer gleich). Man kann nicht schreiben a=c, das würde bedeuten &a[0]=&c[0];
das ist genauso unmöglich wie:
int a,b;
&a=&b;