Ratlosigkeit mit char array
-
in der tat geht es, jedoch ist dein array nur 19 zeichen lang..
aber wenn ich ein array oben mit der Länge 20 initialisiere, will ich doch auch auf die Stelle 19 zugreifen können, also auf das letzte Zeichen.
Damit hat man doch normalerweise auch keine Probleme oder?
edit: also um nochmal den unterschied zu erfragen:
wieso klappt alles ohne funktionsaufruf (currentValue = 49;) aber
nicht mit dem aufruf: currentValue = setValue(i);Ich meine die Funktion setValue greift doch nirgends auf das array zu..
Und deshalb halte ich die Theorie mit dem Speicher auch für nicht zutreffend.
-
wenn du 20 Zeichen haben willst, muss das Array halt char name[21] sein! Du musst IMMER wenn es sich um ein String handelt die Null mit einplanen, das MUSST du dir merken... es kommen die Verrücktesten Ausgaben wenn du das nicht beachtest! Nur wegen der einen '\0'.
PS: Das 20. Zeichen muss nicht unbedingt initialisiert werden, da es eine globale Variabel ist, wird sie von Anfang an mit Null initialisiert, sonst nicht!
-
okay.. ich merk's mir
habe aber noch immer nicht verstanden:
currentValue = 49;
geht wunderbar, auch wenn ich es so mache wie im ersten post, also alles mit 19 statt 18 usw..
nur
currentValue = setValue(i);
geht nicht, wobei eben setValue() nicht im geringsten auf das array zugreift.
D.h. ich verstehe nach wie vor nicht, wieso es hier Probleme mit dem Speicherzugriff oder Nullterminierungen gibt...
-
TLEP schrieb:
es kommen die Verrücktesten Ausgaben wenn du das nicht beachtest! Nur wegen der einen '\0'.
#include <stdio.h> char count[20]; int value1 = 0; int value2 = 0; int value3 = 0; int main(void) { for ( int i=19; i>=0; i-- ) count[i] = '0'; value1 = 1819043144; value2 = 1867980911; value3 = 6581362; printf( "%s\n", count ); return 1; }
:xmas1:
Die 20 chars und die Integer-Variablen liegen im Speicher direkt hintereinander. Jedes char belegt 1 Byte, jedes int (bei mir) 4 Bytes. Wenn printf was ausgeben will, gehts von der Startadresse im Speicher los und gibt jedes Byte/Zeichen aus, bis es auf ein Null-Byte trifft. Meine Zahlen hab ich so gewählt, dass sie den ASCII-Code von sinnvollen Buchstaben enthalten. Ist recht einfach, wenn du weißt, wieviele Bytes ein Datentyp hat.
Ein int hat (bei mir) 4 Bytes, also passen 4 ASCII-Zeichen rein. In value1 hab ich 'H' 'e' 'l' 'l' reingepackt. Da printf im char-Array kein Null-Byte findet, wandert es ja weiter im Speicher, direkt dahinter liegt halt value1. Also gibt es auch die Bytes von value1 aus, weil es nicht wissen kann, ob das jetzt nun eine Zahl ist oder sonstwas, es findet ja einfach nur Byte für Byte im Arbeitsspeicher vor.edit2: TLEP hats gut erklärt!
-
Das ist so:
du deklarierst die Variablenchar count[20];
int currentValue = 0;
int value;die werden mit Null initialisiert und stehen im Heap( oder zu deutsch Halde^^) so:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | 0 ... | - - - char - array- - - - - - - - - - | |currentValue| ...
nun schreibst du das komplette Array mit 48 (Zeichen '0'):
48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 | 0 0 0 0... |---------char-array-------------------------------------------------------| |currentValue-| ...
nun setzt du das 20. zeichen auf 49 und gibst die Sache aus. Diese Ausgeben funktioniert unter C so: es werden alle Zeichen auf dem Bildschirm ausgegeben bis ein 0 kommt! Es wird jetzt also folgendes gedruckt:
48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 49 | 0 0 0 0
entscheidend ist die 0 von dem currentValue Speicherbereich!
bei der Zweiten Variante setzt du genau diesen Speicherbereich auch auf 49! Jetzt zur ausgabe: Dazu muss man wissen das ein int normaler Weise 32 Bit hat und auf den meinsten Architekturen als Big-Endian gespeichert werden ( das meist-signifikante Byte zuerst )
sprich binär '49' ist dann00110001 00000000 00000000 00000000
und jetzt steht im Speicher:
48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 49 | 49 0 0 0und daher kommt die zweite '1', weil die 49 jetzt nochmal da drin steht!
-
was willst du damit sagen?
Ich kann das Programm 100 mal ausführen, das Array ist immer sauber eine Kette von Nullen..Leute bitte lest euch doch mal aufmerksam durch, was ich sage :p
Ich zweifel ja nicht daran, dass ihr es checkt, aber sorry, ich glaube nicht an eure Speicherprobleme und Nullterminierungsgeschichten...
Nehmt den Code von meinem allerersten Post!
Und ersetzt das currentValue = setValue(i) durch ein currentValue = 49;
Ergebnis: Alles funktioniert wunderbar...
Also bidde...Ich bin zwar Anfänger, aber wie erklärt ihr das?
Es liegt, ich sage es nochmal, am aufruf der Funktion!
-
hdi.loggedout schrieb:
was willst du damit sagen?
Ich kann das Programm 100 mal ausführen, das Array ist immer sauber eine Kette von Nullen..Mist, bei mir hat's funktioniert! Was für'n Compiler hast du, und was für ein System?
hdi schrieb:
Also bidde...Ich bin zwar Anfänger, aber wie erklärt ihr das?
Es liegt, ich sage es nochmal, am aufruf der Funktion!
Hehe, es liegt indirekt an der Funktion, die Ursache findest du in TLEPs letztem Post.
edit: Hab am obigen Code noch Kleinigkeit verändert, probiers noch mal
-
hmm...
also ich halte noch dagegen
^^
Er hat mir lediglich gezeigt (schön übrigens, danke :)), wie der Stack/Heap funktioniert.
Aber nach seiner Theorie müsste auch:
currentvalue = 49;
den Fehler ausgeben, da das Array nicht null-terminiert ist.
Das tut es aber nicht...
Und die Funktion setValue(), falls sie indirekt, wie du sagtest, dafür verantwortlich ist... WO?
Sie hat mit dem Array doch absolut goar nix am hut
ps badestrand:
auch diese funktion gibt schön die nullen aus
Jedoch ändere ich immer die for-schleife..
int i = 19 kann mein compiler nicht in der schleifen direkt (outside C99-mode), ich deklariere int i = 19 davor und rufe dann die for-schleife einfach so auf:for (; i >= 0, i--)
...falls es deshalb nicht klappt ?
-
Das, wenn du die Funktion nicht aufrufst, alles klappt, ist Zufall!!! Wenn zufällig im Speicher danach keine Null stehen würde, wird es nicht mehr funktionieren, glaub uns! Die abschließende Null ist essenziell!!! Sorry mir ist es klar, das es daran liegt! Was muss ich machen um es die zu zeigen??
-
hdi schrieb:
Und die Funktion setValue(), falls sie indirekt, wie du sagtest, dafür verantwortlich ist... WO?
Sie hat mit dem Array doch absolut goar nix am hut
Ja, aber wie TLEP schön dargestellt hat, ist currentValue erst 0 und stellt damit das Null-Byte, welches den String terminiert, später dann 49, wobei Byte-mäßig erst die 49 (also '1') und dann ein (bzw mehrere) Null-Byte kommt.
Mach mal aus der Zeile
currentValue = setValue(i);
eincurrentValue=6581362;
. Ich wette, dann kommen die '0'en und dann "rld"hdi schrieb:
ps badestrand:
auch diese funktion gibt schön die nullen aus
Jedoch ändere ich immer die for-schleife..
int i = 19 kann mein compiler nicht in der schleifen direkt (outside C99-mode), ich deklariere int i = 19 davor und rufe dann die for-schleife einfach so auf:for (; i >= 0, i--)
...falls es deshalb nicht klappt ?
Ne, daran dürfte es nicht liegen
Was gibt denn bei dir sizeof(int) so aus?
edit x: Wenn sizeof(int) bei dir auch 4 ist, was gibt denn
printf( "%i %i %i %i\n", &count[0], &value1, &value2, &value3 );
bei dir aus? Interessiert mich einfach, warum das bei uns unterschiedlich läuft
-
Also, du meinst höchstens Zufall, weil mein Programm durch die Anzahl/Folge der Deklarationen so gemacht ist, dass er eine '0' findet, oder?
Denn wenn du meinst, dass es bei jeder Ausführung schief gehen könnte...
Ich habe es gerade 50 mal ausgeführt und alles passt..Gut, angenommen ich glaube euch mal, obwohl ihr eindeutig überkrasse naps in C seid (
), dann fände ich's noch cool, wenn ihr mir erklärt, wieso
eben bei Verwendung der funktion es schief geht, und wieso ohne nicht (wegen Zufall, wie gesagt siehe oben...)Und generell wegen Strings und Nullterminierung usw:
Ich kann doch den letzten Wert eines Strings verändern, ohne dass etwas passiert oder nicht?
Du sagst zwar nein, und das soll ich mir merken, aber ich hab schon viele Programme geschrieben, und auch sehr komplexe mit hunderten von Variablen/Puffern etc, und ich konnte z.B in einem Puffer:char array[1024];
wild rumschreiben wie ich bock hatte, auch in array[1023], und es ist nie irgendwas schief gegangen...Ich hab da tausende von Bytes Daten durchgejagt, was ja auch nix anderes ist als Zeichen, und es ging alles wunderbar...
Du machst mir echt Angst, weil ich bin grad total verwirrt ^^
edit: @badestrand:
also bei
currentValue = 49;
schreibt er anders in den Heap (little/big endian) als mit
currentValue = funktion(..);
?
-
OK, tut mir leid, aber meine Erklärung ist doch falsch! Es ist die Funktion, die die zweite '1' erzeugt! Also^^: Es Prozess hat seinen Heap und seinen Stack! Dafür gibt es einen Speicher bereich: z.B.
0 0 0 0 0 0 0 0 0 0 0 0 | 12 54 76 34 76 124 54 23 .... | Heap -----------------| Stack -> ->
Die Pfeile deuten die Aufbaurichtung an! Wenn du jetzt eine Funktion aufrufst, werden, die der Funktion übergebenen Parameter auf dem Stack abgelegt! Also bei uns hier das i, speziell 49! Und daher kommt letzten Endes ein '1' !
Ok, das sollte jetzt aber stimmen :>
-
Ne stimmt ja schon, du kannst reinschreiben, was du willst
:xmas1:
Das Ding ist nur, dass Null-terminierende Strings eben recht "primitiv" sind, weil sie davon ausgehen, dass das Ende vom String mit einer 0 abgeschlossen ist. Darauf verlassen sich halt auch alle String-Ausgabefunktionen und laufen solange den Arbeitsspeicher durch, bis sie auf ein Null-Byte stoßen. I.d.R. passiert das recht schnell, aber es liefert halt meist nicht das gewünschte Ergebnis
Deshalb ist es "besser", wenn man einenchar mein_string[20];
hat, die ersten 19 Zeichen (0 bis inklusive 18) für Zeichen zu nutzen und das letzte auf 0 zu setzen - eben damit man die String-Funktionen verlässlich nutzen kann.Mein Code-Beispiel sollte übrigens die '0'en und dann "Hello World" ausgeben, was bei mir auch geklappt hat - naja, weiß der Henker , andere Compiler, andere Sitten
hdi schrieb:
also bei
currentValue = 49;
schreibt er anders in den Heap (little/big endian) als mit
currentValue = funktion(..);
?
Ne, er schreibt schon das selbe/gleiche (:D) rein, nur sieht man dann, dass es nix mit der Funktion zu tun hat, sondern mit der Belegung von currentValue
hdi, magst du dann mal die Ausgabe von
#include <stdio.h> #include <sys/types.h> #include <stdlib.h> char count[20]; int value1 = 0; int value2 = 0; int value3 = 0; int main(void) { printf( "%i %i %i %i\n", &count[0], &value1, &value2, &value3 ); int i=19; for ( ; i>=0; i-- ) count[i] = '0'; value1 = 1819043144; value2 = 1867980911; value3 = 6581362; printf( "%s\n", count ); return 1; }
posten?
-
also..TLEP und badestrand, könnt ihr euch darauf einigen, ob es jetzt an der funktion liegt oder generell an der belegung von currentValue?
Damit ich mir das richtig einbrenn
ps: bin noch immer total verwirrt, ich werde morgen mal mir nochmal nen überblick schaffen und auch meine programme anschauen..
Wäre nett, wenn ihr hier nochmal reinkucken würdet dann.
Weil diese Nullterminierung, und wann das jetzt zum Fehler führt und wann nicht, überfordert mich gerade
Ich mach jetzt mein Drecks-Array einfach 21 lang, passt :xmas2:
edit: hier die ausgabe badestrand:
134518320 134518308 134518312 134518316
00000000000000000000
-
hdi schrieb:
Du machst mir echt Angst, weil ich bin grad total verwirrt ^^
Das wollte ich nicht^^
Badestrand hat Recht, immer wenn du Text speichern willst, an die abschließende Null Denken! Wenn es sich um einem Buffer handelt, der keine Text enthält, sondern z.B. Bytes dann ist es nicht so wichtig! Allerdings verlassen sich auch einige Funktionen darauf, grade wenn ich an Socketprogrammierung denke!
-
hdi schrieb:
also..TLEP und badestrand, könnt ihr euch darauf einigen, ob es jetzt an der funktion liegt oder generell an der belegung von currentValue?
Es liegt am Funktionsaufruf. Dabei wird (mindestens) die Rücksprungadresse auf den Stack gelegt, und zwar offenbar an die Stelle, an der vorher Deine terminierende Null (zufällig) stand.