PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : newbie - strings



flasheye
13-04-2001, 23:21
Moin,

kann mir jemand sagen, wie ich einen Text in einen String packen kann?

BSP:
char var1[] = " ";

var1[] = "schnick schnack";


Bei diesem Versuch ernte ich vom Compiler parse error before ']'

DasSein :cool:

tkortkamp
14-04-2001, 00:04
Hier ein Beispiel:

char *test;
test="hallo";

cu,
Tobias

jgbauman
14-04-2001, 00:57
Wenn es doch ein array und kein Pointer sein soll, dann hilft strcpy.



char s[20];
strcpy(s, "Hello world!");

Hierbei ist aber zu beachten, dass genuegend Speicherplatz fuer das Array reserviert wurde.
Besser ist noch strncpy, da damit moegliche buffer overflows vermieden werden koennen.



char s[20];
strncpy(s, "Hello world!", 19);
s[19] = 0;


Und nicht vergessen: das abschliessende Nullbyte braucht auch Speicher und sollte nicht fehlen ;-)

flasheye
14-04-2001, 01:01
Wow, das ging ja fix. Vielen Dank.

flasheye
14-04-2001, 01:09
Aber eine Frage hätt ich ja doch noch.
Was wär denn da der Unterschied, wenn ich einen array definiere oder einen Zeiger verwende?

DasSein

tkortkamp
14-04-2001, 01:30
Hi!
Also... Vorweg sei erstmal gesagt das ich gerade C lerne :D. Kann also falsch sein. ABer soweit ich das jetzt auswendig weiss, kannst du mit einem zeiger auf ein char unendlich lange strings speichern. Berichtigt mich bitte, wenn ich falsch liege.

cu,
Tobias

stiviman
14-04-2001, 18:11
hi

den parse error krigst du weil du "keinem" element im array einen wert zuweist.
var1[0]='a'; würde gehn
var1[]='a'; geht nicht;-)


unterschied zwischen array und zeiger:
wenn du ein array deklarierst:
char var1[10];
werden ab irgendeiner speicherstelle genau 10 bytes fürs array reserviert.
bei einem pointer:
char *var2;
werden nur platz für den pointer reserviert.

mit var2 = "hallo\0"; legst du den string hallo im speicher an und lässt var2 darauf zeigen
mit var1[0]="hallo\n"; weist du dem nullten Element (dass genau ein Byte lang ist) eine speicheradresse zu! (die 4 bytes lang ist) das geht nicht;-)
es würde funktionieren wenn du ein char * array machen würdest ( char *var1[])
es würde kurioserweise auch funktionieren wenn du ein integer-array machen würdest, da ein integer 4 bytes lang ist!!!

jaja, c ist interessant;-)

wir nehmen an die adresse für
char var1[10]; ist 20.
die speicheradresse für
char *var2; ist 40
die speicheradresse (anfang) des strings
"hallo\0" ist 60

Befehl:
var2 = "hallo\0";
Wirkung:
Speicheradresse von var2: immer noch 40
Speicheradresse von String: immer noch 60
Inhalt von var2 (Speicheradresse 40): jetzt 60

Befehl:
var1[0] = "hallo\0";
Speicheradresse von var1[0]: immer noch 20
Speicheradresse von String: immer noch 60
Inhalt von var1 (Speicheradresse 20): -112
Weil: var1 ein chararray ist und pro element nur 1 byte erlaubt sind.
somit ist das erste byte der zahl 60 als var1[0] abgespeichert... zwar kompliziert, aber so ist es.

Und deshalb gibts auch einen speicherzugriffsfehler wenn du versuchst, dass auszugeben, weil es die adresse -112 nicht gibt.
beim kompillieren würdest allerdings noch mit einem warning davon kommen;-)

hinweis zum verstehen:
warum muss man ein char array bei strcpy verwenden?
syntax: strcpy(var1, "hallo");
in der funktion wird der string "hallo" zeichen für zeichen in var1 kopiert. die funktion macht also grob folgendes:

var1[0]='h';
var1[1]='a';
...
var1[5]='\0';

deshalb muss es ein array sein. und deshalb ist es nicht so gut wenn dass array zB nur 3 elemente hätte, da strcpy nicht überprüft ob genug platz ist. in so einem fall entsteht ein buffer-overflow (oder ein speicherzugriffsfehler)

---------------------------
das wars;-)
tschau

flasheye
16-04-2001, 13:55
Moin moin,

ich hab zwar nicht alles verstanden, aber ein Stück weiter bin ich nu schon. Vielen Dank.

Also noch mal zum Verständnis. Auf arrays kann demnach nur über seine Indizes zugefgriffen werden, ich dachte mir sowas schon.
Und dieser Bufferoverflow entsteht, wenn ich nun versuche in den array mehr Zeichen reinzuschieben, als er aufnehmen kann. Dem kann ich aber entgegenwirken, wenn ich strncpy() verwende?.

Diese Geschichte mit den Speicheradressen habe ich noch nicht so ganz geschnallt. Was heisst, die Speicheradresse von var1[10] ist 20 und die anderen 40 und 60. Wie muss ich das verstehen? Nehmen wir an ich hätte 100 Kästchen (Matheheft). Den char array mache ich zehn Zeichen lang, also mit Nullbyte am Ende 11 Kästchen; eine int variable wäre also 4 Kästchen lang? Wäre dann das erste Kästchen des arrays auf der 20. Stelle? :confused:

Irgendwie verstehe ich auch nicht wie da jetzt eine -112 zustande kommt? :confused:

stiviman
16-04-2001, 20:42
es geht darum: dass ist momentan noch nicht so wichtig, und auch nicht schlimm wennstes noch nicht so ganz verstehst. aber eins is ganz leicht zu kapieren:

ein char ist (per definition in linux) genau 1 BYTE lang.
ein int ist (per definition in linux) genau 4 BYTE lang. (ich glaub sogar 8, aber weis nicht genau, jedenfalls mehr als ein char!)

( es gibt nen operator sizeof. den kannst anwenden auf irgendeine variable. der gibt dir die anzahl der reservierten bytes zurück. also sizeof(int) würde 4 ergeben. sizeof(char) ergibt 1 usw...

ein array "arbeitet" nicht byte für byte, sondern eher element für element.
du hast jetzt dein matheheft und fängst links oben beim ersten kästchen zum zahlen an.
deklarierst du ein int-array, werden im matheheft sizeof(int) * AnzahlElemente Kästchen(Bytes) reserviert.
machst du dass zb so:
int i[9]; werden 4*10 Kästchen reserviert, also 40 (4* 10 deshalb, da ja mit 0 zu zählen begonnen wird)
bei
char c[9]; werden 1*10 Kästchen reserviert, also 10 (sizeof(char) = 1)
zu den kästchen:
nehmen wir an das array beginnt im matheheft(im speicher) beim 1. kästchen. wenn das ein chararray ist, und du aufs 5. element zugreifst (also c[4]), dann greifst du auf das 5. kästchen zu. (4 und 5 deshalb, da man beim array ja mit 0 zu zählen beginnt)
machst du das ganze mit nem int-array (also i[4]) greifst du auf das 20. kästchen zu. (5*4 -> 5. element, sizeof(int) = 4)

und alles andere is eh unwichtig

flasheye
17-04-2001, 22:05
Ah jetzt, ja. Eine Insel.

Und der Zeiger char *var zeigt dann auf die erste Stelle des eigentlichen strings, wobei ich mir um ihm vorher keine Gedanken machen muss, wie gross er nacher tatsächlich ist? Heisst das, das bei dieser Variante kein Bufferoverflow entstehen kann?

Und dann hätt' ich noch eine andere Frage. Den Bereich, den ein Programm zur Laufzeit zur Speicherung von Variablen verwendet ist der Stack. 1. Wie gross ist der unter C? Bei Turbo Pascal damals waren es 64kb. 2. Stimmt es, dass die Werte, auf die pointer zeigen, ausserhalb des Stack liegen?

Als dann, bye.

DasSein

jgbauman
18-04-2001, 00:15
kleine Korrektur, aber wichtig:
int i[9] reserviert 9 ints, also 9*4 Bytes und nicht 10 * 4 Bytes.

Ansprechbar als i[0] bis i[8]

stiviman
18-04-2001, 18:59
ups, natürlich werden nur soviele elemente reserviert wie angegeben sind;-)) (aber wenn man so viel schreibt....*g*)
ich halte mich jetzt zurück:
@flasheye: da du strcpy bei char * praktisch nicht anwendest können auch keine overflows entstehen
wie groß der stack ist weis ich nicht, bis jetzt hat er immer gereicht;-)

jgbauman
19-04-2001, 11:59
Ueber die theoretischen Grenzen des Stacks unter linux solltst Du dir keine Sorgen machen. Praktisch hast Du soviel Stack zur verfuegung wie freien Speicher (inklusive Swap)

Nochmal ein paar Klarstellungen.
Alle Variablen die am Anfang einer Funktion deklariet werden, werden auf dem Stack gespeichert.
Fuer alle globalen Variablen wird beim Programmstart der Speicherplatz reserviert und mit Nullbytes gefuellt (nicht Stack).
Fuer alle Stringkonstanten ("Hello World!"+Nullbyte) die im Quelltext vorkommen wird aehnlich wie bei den globalen Variablen der Speicherplatz beim Programmstart reserviert und mit den Texten gefuellt.

Weiterer Speicher kann dynamisch mit malloc() angefordert und mit free() wieder freigegeben werden. (nicht Stack)

Ein Pointer/Zeiger speichert die Adresse einer anderen Variablen. Dabei ist es egal ob diese statisch alloziiert wurde, auf dem Stack liegt oder mit malloc und free reserviert wurde.
Ein Pointer kann ja auch ungueltige Adressen speicherm, was dann halt zu Programmfehler fuehrt.

Solange ich von einem gueltigem Pointer lese, brauche ich mir keine Gedanken ueber overflows zu machen.
Aber sobald ich in den Speicher schreibe muss ich immer sicherstellen, das an dieser Adresse auch genuegend Speicher reserviert wurde.

[code]
int main(){
char s[10];
char *p1="Hello world!";
char *p2="123456789"
char *p3;

// p1 und p2 zeigen jeweils auf statisch allozierte Strings
// p3 enthalt irgeneinen wert, wahrcheinlich ein ungueltiger Pointer
// s hat platz fuer 10 Zeichen (einschliesslich Nullbyte), d.h. Strings mit 9 sichtbaren Zeichen
p3=p2; // Nur die Adresse wird kopiert, no problems
p2="weiter"; // p2 wird die Adresse des statisch (vor dem Programmstart) alloziertem und initialsiertem "weiter" uebergeben
// p1 Zeigt immer noch auf "Hello Wolrd!"
// p2 zeigt auf "weiter"
// p3 zeigt auf "123456789
strcpy(s,p2); // Die Zeichenfolge "weiter" + Nullbyte wird in das Array s kopiert
strcpy(s,p3); // Die Zeichenfolge "123456789" + Nullbyte wird in das Array s kopiert
p2=s; // Die (Start)Adresse des Arrays s wird in p2 gespeichert, p2 ziegt auf den Inhalt von s, momentan "123456789" + Nullbyte ('\0')
strcpy(s,p1); // Buffer overflow, da "Hello world!" + Nullbyte laenger als 10 Zeichen ist.
p2=(char*)malloc(100); // Es wird Platz fuer 100 Zeichen reserviert und die Adresse in p2 gespeichert
// Falls kein Speicher mehr frei ist, wird NULL zurueckgeliefert
strcpy(p2,p1); // Die Zeichenkette "Hello wolrd!" +Nullbyte wird in den reservierten Speicher kopiert

// wenn wir den speicher nicht mehr brauchen geben wir in wieder frei
free(p2); // Achtunf ab jetzt nicht mehr auf den Speicher zugreifen, auf den p2 zeigt, da er uns nichtmehr gehoert (SEGMENTATION FAULT wahrscheinlich)


}

flasheye
19-04-2001, 21:33
Auch hier ein dickes Lob jgbaumann, vielen Dank.