Hallo,
beschäftige mich gerade mit der Array Programmierung von strings in C,
aber irgendwie will es nicht funktionieren.
Habe viele Beispiele gefunden aber nur für c++.
Wie wird in C die strings in Array geschrieben?
Habe z.B. char string [5]={`test1','test2','test3'}; schon versucht,
aber ohne Erfolg.
iGast schrieb:> char string [5]={`test1','test2','test3'}; schon versucht,> aber ohne Erfolg.
ist ja auch falsch.
char* werte[] = {"test1","test2","test3"};
iGast schrieb:> Welche Bedeutung hat der * bei char?
die gleiche Bedeutung wie bei jedem anderen Datentyp. Damit definiert
man einen Zeiger.
Eventuell ist es zeit für ein C-Buch.
Für den Anfang zu empfehlen: C von A bis Z von Jürgen Wolf
Das umfassende Handbuch für Linux, Unix und Windows
findest du auch kostenlos über die Suchmaschine deines Vertrauens oder
hier http://www.win-tux.de/
lazarus schrieb:> Aber wie immer werden dem Anfänger hier gerne bewusst Steine in den Weg> gelegt.
dein Beispiel ist natürlich viel besser, jedem Anfänger ist sofort klar
war das die 10 hier bedeutet.
char str1[][10]
Peter II schrieb:> dein Beispiel ist natürlich viel besser, jedem Anfänger ist sofort klar> war das die 10 hier bedeutet.>> char str1[][10]
Es ist immerhin besser als euer sinnloses "nim nen Pointer" Gehabe mit
Verweis auf "lies die Grundlagen".
Er hat so ein einfaches, funktionierendes Beispiel. Einmal im Debugger
angeschaut und er weiß bescheid.
Ihr seid halt einfach zu verbildet und habt den Blick fürs Einfache
längst verloren.
lazarus schrieb:> Es ist immerhin besser als euer sinnloses "nim nen Pointer" Gehabe mit> Verweis auf "lies die Grundlagen".> Er hat so ein einfaches, funktionierendes Beispiel. Einmal im Debugger> angeschaut und er weiß bescheid.
und was passt dir daran nicht?
> char* werte[] = {"test1","test2","test3"};
liefert im Debugger genau das gleiche wie dein Programm.
Peter II schrieb:> und was passt dir daran nicht?>>> char* werte[] = {"test1","test2","test3"};>> liefert im Debugger genau das gleiche wie dein Programm.
Er weiß anscheinend noch nicht was ein Pointer ist. Sinnvoller halte ich
den Weg ihm erst mal ein einfaches Beispiel ohne "unbekanntes Sternchen"
zu zeigen. Er kommt schon noch früh genug auf Pointer. Du fängst in der
Mathe doch auch nicht bei den komplexen Zahlen C an, sondern erst mal
mit den natürlichen Zahlen N oder etwa nicht?!
Tja, C ist eine extrem anfängerfeindliche Sprache.
Im einem Zusammenhang ist "char *var[10]" und "char var[][10]" das
gleiche. Im andern Zusammenhang muss man da unterscheiden.
Erstaunlich, dass die Unis ausgerechnet diese Sprache für
Anfängerübungen ausgewählt haben.
char str1[][10] = {"eins", "zwei", "drei", "zehn", "zwanzig",
"dreissig"};
ist ein zweidimensionales array..mit
char str1[] = {"eins"};
wäre es ein einfaches array
das [] dient bei c dafür das C selber die länge des Strings ermittelt,
ist vermutlich die sicherste Art das zu evrwenden, weil es schief geht,
wenn der Strin kurz definiert wird
[10] wiederrum bedeutet das es ei String mit einer Zeichenlänge von 10
Zeichen ist im Gegensatz zu Pascal nicht /0 terminiert(richtig?)
Tombo schrieb:> [10] wiederrum bedeutet das es ei String mit einer Zeichenlänge von 10> Zeichen ist im Gegensatz zu Pascal nicht /0 terminiert(richtig?)
Ist wohl etwas missverständlich.
In C sind die Strings und Stringliterale nullterminiert.
Tombo schrieb:> das [] dient bei c dafür das C selber die länge des Strings ermittelt,
Genauer: Der Compiler ermittelt die Anzahl der Arrayelemente. Mit
Strings hat das zunächst nichts zu tun.
> ist vermutlich die sicherste Art das zu evrwenden, weil es schief geht,> wenn der Strin kurz definiert wird
Das nun nicht.
> [10] wiederrum bedeutet das es ei String mit einer Zeichenlänge von 10> Zeichen ist im Gegensatz zu Pascal nicht /0 terminiert(richtig?)
Es bedeutet, daß das betreffende Array mit Platz für zehn Elemente
angelegt wird, ob die nun initialisiert (d.h. ab Start mit einem Wert
belegt) werden oder nicht.
Empfehlenswert, dringend empfehlenswert ist die Lektüre eines Buchs
über C.
Der Klassiker "Brian Kerninghan & Dennis Ritchie: Programmieren in C"
ist zwar schon recht alt und gibt nicht die neueste Inkarnation des
Sprachstandards wieder, aber damit ist das, was im Buch steht, weder
falsch noch überholt.
Und so grundlegende Sprachelemente wie Pointer, Arrays und deren
Initialisierung sind auch im eng mit C verwandten C++ nicht elementar
anders.
Noch einer schrieb:> Erstaunlich, dass die Unis ausgerechnet diese Sprache für> Anfängerübungen ausgewählt haben.
Die normative Kraft des Faktischen
-oder-
man nimmt das, was man selber kennt.
Vor zig Jahren hatte ein Informatik-Prof die Programmiersprache seines
programmierbaren TI Taschenrechners (der TI-59 wars wohl) als Basis des
Prinzips von Assembler-Programmierung eingesetzt.
Noch einer schrieb:> Erstaunlich, dass die Unis ausgerechnet diese Sprache für> Anfängerübungen ausgewählt haben.
Ja, Praxisorientierung ist im universitären Umfeld auch eher
überraschend.
Vielen Dank an Lazarus für seinen Beitrag. Wie ich sehe ist dies nicht
so einfach wie es manche kommentiert haben. Auch in meinem Buch, und das
ist Einsteiger und Grundlagen wird dies nicht richtig erklärt. Ich
denke, jetzt habe ich es verstanden. Können auch mehrdimensionale Felder
mit strings?
Tombo schrieb:> char str1[][10] = {"eins", "zwei", "drei", "zehn", "zwanzig",> "dreissig"};>> ist ein zweidimensionales array.
Wobei zu beachten ist das die 6 char[10] immer 10 zeichen enthalten. Bei
einem grösseren c-string von z.B. 10 zeichen Würde dass durch den
c-string angefügte nullbyte (11tes zeichen im char array) abgeschnitten.
Grössere char-arrays/c-strings werden genauso abgeschnitten. Kleinere
strings verbrauchen trotzdem 10 zeichen platz. Das obere array
verbraucht 10*6*sizeof(char)=60 bytes speicherplatz.
>mit> char str1[] = {"eins"};> wäre es ein einfaches array
Nein, dass ist der versuch ein char mit einem char[5] zu befüllen.
Das muss so aussehen:
char str1[] = "eins";
Ich versuche mich mal an einer Erklärung für Arrays und Pointer.
Arrays:
Eindimensionale und Mehrdimensionale Arrays sind das selbe. Der Kompiler
kennt ihren type, die Addresse des Ersten Elements, und die Grösse aller
oder von allen auser der letzten Dimension.
Der Compiler kennt bei der Definition immer die Grösse aller
Dimensionen. Das braucht er um die Grösse des benötigten
Speicherbereichs zu Berechnen. Die Grösse des Speicherbereichs ist die
Summe der Grösse der Dimensionen des Arrays mal die Grösse seines
Datentyps.
Wenn man ein Element eines n-Dimensionalen Arrays abfragt Rechnet der
Compiler einfach folgendes (glaub ich zumindest):
Wobei:
n = Anzahl der Dimensionen
i = index in der Arraydimension
d = grösse der dimensionen
Beispile:
1
charx[][5][4];
2
chary=x[2][3][4];
1
n = 4
2
d = {?,5,4}
3
i = {2,3,4}
4
resultat:
5
4 + (4*5)*2 + (5)*3 = 59
Also das Element Nummer 59 man könnte in c nun auch schreiben:
1
char y = x[0][0][59];
und hätte das selbe Element.
Oder anders ausgedrückt: Das speicherlayout von char[5][4] ist identisch
zum Speicherlayout von char[5*4], nur der Datentyp ist etwas anders,
aber den kennt das Programm nach dem Compilieren nichtmehr.
Ein Array besitzt also: Dimensionen, einen Type und eine Startadresse.
Pointer:
Nun zu den Pointern. Ein Pointer zeigt auf eine Speicheradresse. Er hat
einen Datentype. Seine grösse ist immer sizeof(void*). Sein wert ist die
Stelle wo er hinzeigt. Pointer können auch auf Pointer zeigen. Mit
ausname eines Pointers auf void ist jeder Pointer ein Arithmetischer
Datentype (man kann damit rechnen).
Ein Beispiel:
1
charx=123;// Kompiler reserviert speicher für ein char, steicherstelle enthält 123
2
char*y=&x;// Kompiler reserviert speicher für einen Pointer, steicherstelle enthält einen Pointer auf Speicherstelle von x
3
char**z=&y;// Kompiler reserviert speicher für einen Pointer, steicherstelle enthält einen Pointer auf Speicherstelle von y
z zeigt nun auf y welches auf x zeigt.
**z = dereferenzieren von z (zweiter stern), gibt wert von y, und danach
deferenzieren des erhaltenen wertes (*y oder zweiter stern von **z),
gibt wert von x.
Alternative screibweise von **z ist z[0][0].
Man kann einem Pointer die Adresse eines Arrays zuweisen.
Beispiel:
1
charx[5][4][];
2
char*y=x[0][0];
3
char*z=&x[0][0][0];
4
char*w=(char*)x;
Hier haben y, z und w den selben Wert, sie zeigen auf das erste Element
von x.
Pointerarithmetik:
Das ist einfach. Man referenziert mit einem & und dereferenziert mit
einem *. Beim Rechnen wird der Datentyp als Einheit genommen.
Beispiel:
1
constchar*x="test abc";
2
constchar*y=x+5;
3
constchar*z=&y[5];
Hier zeigt x auf das 't' in "test abc".
Es zeigen y und z auf das 'a' in "test abc".
Der Compiler rechnet den Wert von x den Wert von x in beiden fällen +
5*sizeof(char), wobei bei z=&y[5] y[5] den erhaltenen wert
dereferenziert und das & referenziert die stelle wo der wert steht dann
wieder. Natürlich MUSS der Compiler diese überflüssige rechenoperation
wegoptimieren. Das dereferenzieren mit einem [] wird vor der
dereferenzierung mit einem * ausgeführt.
Und jetzt nehmen wir das gesammte gesammelte Wissen und kombinieren
Pointer mit Mehrdimensionalen Arrays auf möglichst komplizierte weise:
1
intmain(){
2
constchar*a[2][3]={
3
{"1","2","3"},
4
{"4","5","6"}
5
};
6
constchar*b[2][3]={
7
{"7","8","9"},
8
{"x0","y1","z2"}
9
};
10
constchar*(*c)[2][3]=&a;
11
constchar*(*d)[2][3]=&b;
12
constchar*(*e[2])[2][3]={c,d};
13
constcharx=**((*e[1])[1]+1);
14
15
printf("x ist: %c\n",x);
16
17
return0;
18
}
Die Ausgabe ist: "x ist: y"
So berechnet das der Compiler:
Das zweite Element von e, also e[1] oder *(e+1) ist ein Pointer auf den
Speicherbereich von d der die Adresse des Arrays von b als pointer
enthalt. Wir dereferenziert d und erhalten die Adresse von b, sie hat
folgenden type: const char*[2][3]. Bei (*e[1])[1] oder b[1] erhalten wir
die Adresse von {"x0","y1","z2"} mit dem type const char*[3]. Der
Compiler Rechnet dabei ((const char*[3])(*e[1])+(1*3)+1) oder ((const
char*[3])(*e[1])+4) oder ((const char**)(*e[1])+4) oder (const
char**)b+4. Das wird dan dereferenziert. Wir erhalten b[1][1] oder
*((const char**)b+4) mit type const char*. Das ist der Eintrag "y1"
(zeigt auf das y von "y1"). Wir dereferenzieren das *"y1" und erhalten
'y'
Und dann ist noch anzumerken, dass Arrays und Funktionspointer eine
besonderheit aufweisen: da ihre Adresse nirgens gespeichert ist kann man
sie strengenommen nicht referenzieren/dereferenzieren:
printf("%p %p %p %p\n",test,&test,test2,&test2);// Alle nummern ausser die letzte sind gleich
Das heist, ein Pointer auf ein Array und die Adresse eines arrays
unterscheiden sich nur dadurch, ob diese tatsächlich irgendwo im
Speicher liegen oder nicht. Es gibt durchaus fälle wo das zu Problemen
führen kann. Bei Funktionspointern waren die c leute aus unerfindlichen
gründen etwas weniger streng:
Daniel A. schrieb:> Und dann ist noch anzumerken, dass Arrays und Funktionspointer eine> besonderheit aufweisen: da ihre Adresse nirgens gespeichert ist kann man> sie strengenommen nicht referenzieren/dereferenzieren:
Das Fachwort dafür heißt "Array to Pointer decay" und ich hätte es
anders beschrieben als "ihre Adresse ist nirgens gespeichert".
Eigentlich sagt die Regel nur aus, dass wenn man den Namen eines Arrays
benutzt, dieser in fast allen Fällen zu einem Pointer auf das erste
Element zerfällt. Ausnahmen sind wenn man den Address-Of-Operator
benutzt, also &array_name liefert auch einen Pointer aufs erste Element.
Die Adresse eines Arrays ist also gleich der Adresse des ersten
Elements. Die andere Ausnahme ist sizeof.
Ähnliches gibts für Funktionen. Wenn man den Namen einer Funktion
benutzt aber dann keinen Funktionsaufruf macht verhält es sich wie ein
Pointer auf die besagte Funktion.
Daniel A. schrieb:> Also das Element Nummer 59 man könnte in c nun auch schreiben:char y => x[0][0][59];und hätte das selbe Element.> Oder anders ausgedrückt: Das speicherlayout von char[5][4] ist identisch> zum Speicherlayout von char[5*4], nur der Datentyp ist etwas anders,> aber den kennt das Programm nach dem Compilieren nichtmehr.
Ach ja?
Ich geb dir mal was zu bedenken, also was ist:
char otto[3];
denn nun?
Wenn ich also bei einer Funktion string_out(char* s) hinschreibe
string_out(otto);
was ist dann otto? Jaja, ein Zeiger ist das, der auf das Feld otto[3]
zeigt.
Und nun die Preisfrage:
was ist otto, wenn ich schreibe:
char otto[5][3];
Nun?
Es mag durchaus sein, daß die Elemente aller finalen Felder direkt
aneinander grenzen, aber das MUSS NICHT zwingend so sein.
W.S.
W.S. schrieb:> Ich geb dir mal was zu bedenken, also was ist:> char otto[3];> denn nun?
Ein char array mit 3 elementen.
> Wenn ich also bei einer Funktion string_out(char* s) hinschreibe> string_out(otto);> was ist dann otto? Jaja, ein Zeiger ist das, der auf das Feld otto[3]> zeigt.
Nein. otto ist immernoch ein char Array mit 3 elementen. otto[3] ist ein
bufferoverflow. s würde die addresse von otto, also eine referenz auf
otto[0], das erste element von otto, enthalten. s bleibt dabei ein
pointer auf chars. Steht oben alles schön nach themen sortiert.
>> Und nun die Preisfrage:> was ist otto, wenn ich schreibe:> char otto[5][3];>> Nun?
Ein Mehrdimensionales Array von char elementen.
> Es mag durchaus sein, daß die Elemente aller finalen Felder direkt> aneinander grenzen, aber das MUSS NICHT zwingend so sein.
Es ist ein mehrdimensionales Array, also muss es so sein. Vermischt du
hier vileicht Mehrdimensionale Arrays und Arrays von Pointern gedanklich
auf falsche weise?
PS: Was meinst du mit final im bezug auf felder und welchen Preis hab
ich gewonnen?
lazarus schrieb:> Peter II schrieb:>> dein Beispiel ist natürlich viel besser, jedem Anfänger ist sofort klar>> war das die 10 hier bedeutet.>>>> char str1[][10]>> Es ist immerhin besser als euer sinnloses "nim nen Pointer" Gehabe mit> Verweis auf "lies die Grundlagen".
Ja, wen interessieren heutzutage schon noch Grundlagen?
Sebastian V. O. schrieb:> Ähnliches gibts für Funktionen. Wenn man den Namen einer Funktion> benutzt aber dann keinen Funktionsaufruf macht verhält es sich wie ein> Pointer auf die besagte Funktion.
Da gibt's aber einen Unterschied zu Arrays. Bei Funktionen kann man
sowohl ein &, als auch ein *, oder sogar beliebig viele davon vor den
Namen schreiben. Rauskommen tut dabei immer ein Zeiger auf die Funktion.
W.S. schrieb:> Es mag durchaus sein, daß die Elemente aller finalen Felder direkt> aneinander grenzen, aber das MUSS NICHT zwingend so sein.
Doch, muss es. Ein Array "Typ[n] arr" ist immer sizeof(Typ) * n Bytes
groß. Dabei spielt es keine Rolle, ob Typ ein char oder selbst wieder
ein Array ist.
Daniel A. schrieb:> Nein. otto ist immernoch ein char Array mit 3 elementen. otto[3] ist ein> bufferoverflow. s würde die addresse von otto, also eine referenz auf> otto[0], das erste element von otto, enthalten.
Das ist nicht das gleiche. Die Speicherzelle, auf die referenziert wird,
ist zwar gleich, aber der Typ ist verschieden. Bestandteil grunsätzlich
jedes Werts in C ist ein Typ. In dem Sinne ist es nicht die Adresse des
Arrays, sondern die Adresse von dessen erstem Element.
Daniel A. schrieb:> Die Grösse des Speicherbereichs ist die> Summe der Grösse der Dimensionen des Arrays mal die Grösse seines> Datentyps.
Das kann sich ja wohl nur um einen Witz handeln.
Falls nicht: Geh' sterben. Aber bitte umgehend.
c-hater schrieb:> Daniel A. schrieb:>>> Die Grösse des Speicherbereichs ist die>> Summe der Grösse der Dimensionen des Arrays mal die Grösse seines>> Datentyps.>> Das kann sich ja wohl nur um einen Witz handeln.>> Falls nicht: Geh' sterben. Aber bitte umgehend.
Lieber nicht... Summe und Produkt kann doch jeder mal verwechseln...
Aber gut aufgepasst!