string Wert auf char* Array
-
Hi, also ich MUSS! ein Programm schreiben, indem ich ein char* array deklarieren muss, und Strings auf dieses einlese. Ich habe eigentlich gedacht da ein char Pointer prinzipiell das gleiche ist wie ein char[] Array müsste ich das ganz einfach über strcpy(..) lösen können, aber mein Programm funktioniert nicht. Das erste Zeichen das auf mein char* Array geschrieben wird, ist eine komische Zeichnkette (irgendwas mit NO..), das 2e und 3e Zeichen danach funktioniert komischerweise, und beim 4en krieg ich dann einen Laufzeitfehler.
Die Sache die mich am meisten verwirrt ist warum es beim 2en und 3en kopiervorgang funktioniert und dann nicht.
Ich hoffe ihr könnt mir helfen hier ist mein Code:
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { printf("Sorting Strings with Pointers!\n"); int n; printf("How many Strings do you want to input?\n"); scanf("%i",&n); char * pStringField[n]; int i = 0; char str[100]; // hab ich definiert weil ich ja nicht direkt auf einen char * einlesen kann for(; i < n; i++) { scanf("%s",str); strcpy(pStringField[i],str); printf("%s\n",pStringField[i]); } return EXIT_SUCCESS; }
-
Deine Zeile 15 funktioniert glaube ich nicht. Die Zahl in Klammern muss eine konstante Zahl sein. Es gibts irgendeine Erweiterung die sowas erlaubt, aber es bricht einen Haufen C-Prinzipien.
Stattdessen nimm malloc.char **pStringField = malloc(sizeof *pStringField * n);
Natürlich kannst du direkt auf ein char * einlesen.
char *str = malloc(100); scanf("%100s", str);
Die 100 sorgt dafür, dass maximal 100 Zeichen eingelesen werden. Ohne diese Begrenzung provozierst du einen Pufferüberlauf.
Übrigens wenn du eh immer nur feste Längen für deine Strings nimmst, was eine ganz schlechte Idee ist, dann kannst du auch sowas machen:
char **pStringField = malloc(sizeof *pStringField * n); for (int i = 0; i<n; i++){ pStringField[i] = malloc(100); scanf("%100s", pStringField[i]); }
-
Seit C99 muss das glaube ich keine konstante Zahl mehr sein, oder liege ich da falsch? :xmas1:
-
Genmutant schrieb:
Seit C99 muss das glaube ich keine konstante Zahl mehr sein, oder liege ich da falsch? :xmas1:
Hab ich hier auch schon öfter gelesen. Ich weiß aber nicht, ob das noch unter Ansi C läuft.
-
Vermutlich eher Ansi C99.
Also, falsches Forum
-
Vielen Dank hat mir sehr geholfen!
Das einzige was ich nicht ganz verstehe ist hier:
char **pStringField = malloc(sizeof *pStringField * n);
was genau sagt mir der doppelte Pointer? also char ** ?
sry soweit sind wir in der Schule noch nicht.. wär sehr nett wenn mir das noch jemand schnell einer erklären könnte.
aber danke schonmal!
-
char **strings bedeutet soviel wie ein Zeiger auf einen Zeiger auf ein char. Wenn du char * als String betrachtest hast einen Zeiger auf einen String, bzw mehrere wenn du es entsprechend belegst.
Es gibt auch eine starke Ähnlichkeit zwischen char **strings, char *strings[] und char strings[][]. Ist nicht ganz dasselbe, aber hilft manchmal sich die Entsprechung vorzustellen.
-
KnufflPuffl schrieb:
was genau sagt mir der doppelte Pointer? also char ** ?
Liest sich als Zeiger auf einen Zeiger vom Typ char. Hast du ein char** Array, kannst du darin also char* Zeiger Speichern.
Guckst du Beispiel:int main() { char* a = "aaa", *b = "bbb", *c = "ccc", *nix = NULL; char** abc = malloc (4 * sizeof(char**)); int i=0; abc[0] = a, abc[1] = b, abc[2] = c, abc[3] = nix; while ( abc[i] != nix ) puts(abc[i]), i++; free(abc); return 0; }
-
Hey nochmals danke, dass hab ich glaub ich sogar verstanden..
Das heißt ich habe einen Pointer der auf einen anderen Pointer zeigt (in meinem Fall eben der String) und durch malloc kann ich eben mehr Speicher reservieren, sodass ich im Prinzip ein Array initialisiert habe.
Demnach wäre char ***strings, sowas in der Art wie ein 2-Dimensionales Array, lieg ich da richtig, oder ist das komplett daneben?
-
Man kann es als 2-dimensionales Array von Strings betrachten. Oder als 3-dimensionales Array von chars. Oder als Liste von Stringarrays. Gibt sicher noch einen Haufen anderer Interpretationen.
-
KnufflPuffl schrieb:
Demnach wäre char ***strings, sowas in der Art wie ein 2-Dimensionales Array, lieg ich da richtig, oder ist das komplett daneben?
Ein char** s ist ja schon zweidimensional, wenn man so will. Du kannst es wie eine Tabelle von Zeichen betrachten:
s[zeile][spalte]
, wobei die Spaltenanzahl varieren kannn.
Mit nem char*** z kannst du mehrere Zeiger solcher Tabellen speichern, kannst dir die Tabellen übereinander denken, eine Art dritte Dimension ( z Koordinate, Höhenkoordinate ).char* ebene[] = {"Ebene 1", "Ebene 2", "Ebene 3", "Ebene 4"}; char* a = "aaa", *b = "bbb", *c = "ccc", *nix = NULL; char** abc = malloc (4 * sizeof(char**)); char*** z = malloc (4 * sizeof(char***)); char** p; int i=0, j=0; abc[0] = a, abc[1] = b, abc[2] = c, abc[3] = nix; z[0] = z[1] = z[2] = z[3] = abc; // Hier sind alle 'Ebenen' gleich. while ( j<4 ) { p = z[j]; puts(ebene[j]); while ( p[i] != nix ) puts(p[i]), i++; i=0,j++; } free(abc); free(z);
Sicher kann man das auch anders interpretieren. Man kann ein 3D Array auch zwei-oder eindimensional betrachten, etc.
-
Also ich hab das ganze jetzt mal so versucht wie ihr mir das geraten habt, es hat schon geholfen, aber leider nicht ganz.
Das gute ist, das die komische Zeichenkette vom ersten Versuch weg ist (NO..) da nimmt er jetzt den richtigen Wert. Das Problem ist aber das ich nach dem 3en Eingabeversuch noch immer nen Laufzeitfehler kriege.
Ich hab den Code so verändert:
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { printf("Sorting Strings with Pointers!\n"); int n; printf("How many Strings do you want to input?\n"); scanf("%i",&n); char **pStringField = malloc(sizeof *pStringField * n); int i = 0; char *str = malloc(sizeof(100)); for(; i < n; i++) { scanf("%100s",str); strcpy(pStringField[i],str); printf("%s\n",pStringField[i]); } return EXIT_SUCCESS; }
Hmm hab keine Ahnung woran das liegen könnte, könnte mir höchstens vorstellen dass ich irwie nen ungültigen Speicherbereich anspreche, aber ich hab doch genug Speicher reserviert.
-
Dir fehlt noch Speicher. Du benutzt strcpy(pStringField[i],str);, aber in pStringField[i] ist garkein Speicher reserviert. Du musst noch ein pStringField[i] = malloc(100); oder so hinzufügen.
-
nwp2 schrieb:
Dir fehlt noch Speicher. Du benutzt strcpy(pStringField[i],str);, aber in pStringField[i] ist garkein Speicher reserviert. Du musst noch ein pStringField[i] = malloc(100); oder so hinzufügen.
super toll, das funktioniert jetzt wunderbar.
Das heißt jetzt quasi hier:
char **pStringField = malloc(sizeof *pStringField * n)
wird nur der Speicher für das eigentliche Feld reserviert, nicht aber für die einzelnen Elemente richtig?
Wenn das so ist frage ich mich nur warum das dann für die ersten 2 Aufrufe überhaupt geklappt hat?!
Jedenfalls vielen Dank!
-
Yup, so ist es.
Speicher wird Seitenweise reserviert, eine Seite hat meist 4kb. Das heißt du kannst mit Glück bis zu 4095 Bytes hinter dem Speicherbereich schreiben. Wenn die nächste Seite auch reserviert ist auch noch weiter. Oder du kriegst schon beim ersten nicht reservierten Byte einen Segmentation Fault wenn dieses Byte zufällig auf einer neuen nicht reservierten Seite liegt.
-
KnufflPuffl schrieb:
Das heißt jetzt quasi hier:
char **pStringField = malloc(sizeof *pStringField * n)
wird nur der Speicher für das eigentliche Feld reserviert, nicht aber für die einzelnen Elemente richtig?
Du reservierst:
n == 1: Speicher für einen Zeiger auf ein Array(Feld),
n > 1: Speicher für n Zeiger auf n Arrays(Felder).
Den Speicher für die 'eigentlichen' Felder reservierst du erst innerhalb der for Schleife.KnufflPuffl schrieb:
Wenn das so ist frage ich mich nur warum das dann für die ersten 2 Aufrufe überhaupt geklappt hat?!
Weil in den ersten 2 Aufrufen keine Speicherschutzverletzung eingetreten ist.
-
nwp2 schrieb:
Speicher wird Seitenweise reserviert, eine Seite hat meist 4kb.
Aber doch nicht mit malloc
char* a, *b; a = malloc (1); b = malloc (1); printf("%d\n", b-a); // Differenz == 4kb? :confused: return 0;
-
nwp2 schrieb:
Yup, so ist es.
Speicher wird Seitenweise reserviert, eine Seite hat meist 4kb. Das heißt du kannst mit Glück bis zu 4095 Bytes hinter dem Speicherbereich schreiben. Wenn die nächste Seite auch reserviert ist auch noch weiter. Oder du kriegst schon beim ersten nicht reservierten Byte einen Segmentation Fault wenn dieses Byte zufällig auf einer neuen nicht reservierten Seite liegt.
Achso ist das, sprich das war nur Glück ^^
Jedenfalls vielen Dank an alle die mir geholfen haben, echt super!
Eine allerletzte Frage hätte ich noch (sry intressiert mich nur sehr) also malloc() zählt ja zur dynamischen Speicherverwaltung richtig? sprich der Speicher wird im heap reserviert. Muss ich in diesem Fall, nicht den Speicher auch manuell wieder freigeben? (sonst bleibt der Speicher ja blockiert oder? -> weiß nur dass es in c++ so mit new und delete ist).
Tut mir leid falls ich schon nerve ^^
-
KnufflPuffl schrieb:
nwp2 schrieb:
Yup, so ist es.
Speicher wird Seitenweise reserviert, eine Seite hat meist 4kb. Das heißt du kannst mit Glück bis zu 4095 Bytes hinter dem Speicherbereich schreiben. Wenn die nächste Seite auch reserviert ist auch noch weiter. Oder du kriegst schon beim ersten nicht reservierten Byte einen Segmentation Fault wenn dieses Byte zufällig auf einer neuen nicht reservierten Seite liegt.
Achso ist das, sprich das war nur Glück ^^
Jedenfalls vielen Dank an alle die mir geholfen haben, echt super!
Eine allerletzte Frage hätte ich noch (sry intressiert mich nur sehr) also malloc() zählt ja zur dynamischen Speicherverwaltung richtig? sprich der Speicher wird im heap reserviert. Muss ich in diesem Fall, nicht den Speicher auch manuell wieder freigeben? (sonst bleibt der Speicher ja blockiert oder? -> weiß nur dass es in c++ so mit new und delete ist).
Tut mir leid falls ich schon nerve ^^
Ok hat sich schon erledigt, hab grad gegoogelt wegen dynamischer speicherverwaltung.. geht ja mit free(..)..
Dann bleibt mir nur noch übrig euch allen ganz herzlich zu danken!
-
KnufflPuffl schrieb:
Eine allerletzte Frage hätte ich noch (sry intressiert mich nur sehr) also malloc() zählt ja zur dynamischen Speicherverwaltung richtig? sprich der Speicher wird im heap reserviert. Muss ich in diesem Fall, nicht den Speicher auch manuell wieder freigeben? (sonst bleibt der Speicher ja blockiert oder? -> weiß nur dass es in c++ so mit new und delete ist).
Genau so ist es. Für jedes malloc muss ein free aufgerufen werden:
for(i=0; i < n; i++) { free(pStringField[i]); // Zeilen löschen } free (pStringField); // Zeiger auf Zeilen löschen.
-
jap habe ich jetzt genauso implementiert.
Nochmals danke!
Btw: muss ich den Thread hier irwie als beantwortet markieren oder so?