Zweidimensionales array dynamisch erstellen
Hallo Liste! Ich habe folgendes Problem: Ich habe eine Funktion in der in ein 2dimensionales char-Array dynamisch erstellt werden soll. Dabei sieht das Array so aus, denn es nicht dynamisch erzeugt wird: char array[100][BEZEICHNUNG]; Die Bezeichung ist immer fix, nur der Index soll sich ändern. Da aber jedes mal eine unbestimmte Anzahl an Bezeichnungen in die Funktion sind möchte ich nicht Speicherplatz verschwenden und das Array jedes mal dynamisch erstellen. Das ganze sieht dann in etwa so aus: int getAnz(void) { int i; char **array; array = (char*)malloc (sizeof(char*)); array[0] = (char) malloc (sizeof (char)*100); while (getinput) { array = (char*)realloc (array, sizeof (char*)); array[i] = (char)realloc (array, sizeof (char*100); i++; strcpy(array[i], input); } do_something_else(); } Das Problem ist allerdings, dass a) das realloc nur ein einziges mal gut geht, beim zweiten Mal ergibt es einen SIGSEGV und b) auch das strcpy geht schief. Hat da irgendjemand eine Idee warum? Oder vielleicht andere Vorschläge die zur Lösung des Problems beitragen? Auf jeden Fall schon mal jetzt "Danke für die Hilfe" LG Georg
Hallo, On Wed, 16 Apr 2003, Georg Wagner wrote:
Ich habe folgendes Problem: Ich habe eine Funktion in der in ein 2dimensionales char-Array dynamisch erstellt werden soll. Dabei sieht das Array so aus, denn es nicht dynamisch erzeugt wird:
char array[100][BEZEICHNUNG];
Die Bezeichung ist immer fix, nur der Index soll sich ändern. Da aber jedes mal eine unbestimmte Anzahl an Bezeichnungen in die Funktion sind möchte ich nicht Speicherplatz verschwenden und das Array jedes mal dynamisch erstellen. Das ganze sieht dann in etwa so aus:
int getAnz(void) { int i; char **array; array = (char*)malloc (sizeof(char*)); array[0] = (char) malloc (sizeof (char)*100);
while (getinput) { array = (char*)realloc (array, sizeof (char*));
Du verkleinerst hier das array wieder...
Nun ist die Frage, wie bekommst du den input? Falls du den kopieren
willst, wuerde ich wohl sowas machen:
==== minimal getestet ====
#include
Hi, Am Mittwoch, 16. April 2003 21:33 schrieb David Haller:
Hallo,
[...]
Nun ist die Frage, wie bekommst du den input? Falls du den kopieren willst, wuerde ich wohl sowas machen:
Input kommt von einer Oracle Datenbank.
==== minimal getestet ==== #include
#include #include #include #include int main(void) { char ** array = NULL; char * input = NULL; int i=0; int j=0;
while( (input = readline("enter string:")) != NULL) { printf("read string[%i]='%s'\n", i, input); array = (char**)realloc(array, sizeof(char*) * (i+1)); if(!array) { goto cleanup; } array[i] = (char*)calloc(strlen(input)+1, sizeof(char)); if(!array[i]) { goto cleanup; } strncpy(array[i], input, strlen(input)); i++; } errno = 0; /* readline setzt das auf 2, wg. irgendwas anderem */ printf("Read all strings\n");
for(j=0; j
cleanup: for(j=0; j
return errno; }
====
Hm, warum bin ich blos nicht auf die Idee gekommen einen realloc zu verwenden? Eine andere Frage: readline.h ist anscheinend nicht ANSI-C da sie bei mir auf meinem System nicht finden kann.
Achtung: ich bin selber noch C-Anfaenger und habe oben sicher noch ein paar Fehler eingebaut. Und nein, normal verwende ich keine gotos ;)
Das mit den goto's ist kein Problem. Ein Tipp von mir: Wenn du eine strn[cpy,cmp,...] verwendest terminiere die letzte stelle mit \0. Dadurch kannst du sicherstellen, dass kein Schrott mit ausgegeben werden. Du hast einen String mit 20 chars hast und du schreibst genau 20 Zeichen hinein, weiß der Kompiler nicht, wo der String aufhört und ließt einfach so lange im Speicher weiter bis er auf \0 trifft. Fehler habe ich allerdings keine gefunden. Soweit hat es funktioniert. Habe mir noch einmal alle Variablen angeschaut und da war das drinnen was ich mir vorgestellt habe. Danke für deine Hilfe! LG Georg
Hallo, On Wed, 16 Apr 2003, Georg Wagner wrote:
Am Mittwoch, 16. April 2003 21:33 schrieb David Haller:
Hallo,
[...]
Nun ist die Frage, wie bekommst du den input? Falls du den kopieren willst, wuerde ich wohl sowas machen:
Input kommt von einer Oracle Datenbank.
Ahso. Je nachdem, wie du eben an die strings rankommst musst du das eben anpassen. Ich habe eben als "Platzhalter" die libreadline fuer den interaktiven Input verwendet. Du musst das eben anpassen/ersetzen und das Eingabeende und evtl. Fehler abfangen.
==== minimal getestet ==== [..] while( (input = readline("enter string:")) != NULL) { [..] ====
Hm, warum bin ich blos nicht auf die Idee gekommen einen realloc zu verwenden?
Hast du ja, aber flasch ;) Siehe Michael's Mail zu den Fehlern...
Eine andere Frage: readline.h ist anscheinend nicht ANSI-C da sie bei mir auf meinem System nicht finden kann.
Ja, das ist die GNU-libreadline. Wenn die Daten aber eh nicht interaktiv eingegeben werden ist das egal. "readline" ist also kein Platzhalter, sondern eben der Aufruf der Funktion aus der libreadline.
Achtung: ich bin selber noch C-Anfaenger und habe oben sicher noch ein paar Fehler eingebaut. Und nein, normal verwende ich keine gotos ;)
Das mit den goto's ist kein Problem.
Naja, das ist her fuer's aufraeumen recht praktisch ;)
Ein Tipp von mir: Wenn du eine strn[cpy,cmp,...] verwendest terminiere die letzte stelle mit \0.
man calloc ;) calloc() allocates memory for an array of nmemb elements of size bytes each and returns a pointer to the allocated memory. The memory is set to zero. ^^^^^^^^^^^^^^^^^^^^^^^^^^ *g* Falls es calloc nicht auf allen Zielplattformen gibt, kann man das calloc durch malloc+memset ersetzen. Kurz: ich bekomme einen genullten, kontinuierlichen Speicherbereich von strnlen+1 Laenge (oder einen Fehler). Falls "char * input" aber nicht null-terminiert ist, hast du aber sowieso ein Problem, da erstens strnlen "bricht" und zweitens das dann auch kein "C-String" mehr ist. Dann muesste man irgendwie auch noch die Laenge des char-Arrays mitfuehren und ueberpruefen usw. Das haengt also von deiner "getinput" Funktion ab.
Fehler habe ich allerdings keine gefunden. Soweit hat es funktioniert. Habe mir noch einmal alle Variablen angeschaut und da war das drinnen was ich mir vorgestellt habe.
Danke ;) Naja, "vollstaendige" Beispiele sind eben viel leichter nachzuvollziehen und zu ueberprufen... Daher hab ich eben auch 'input = readline("...")' verwendet statt ueber deine "getinput"-Funktion zu spekulieren... Und da dies eine SuSE-Liste ist, kann man die libreadline IMO voraussetzen ;) -dnh -- I'm sorry, I can't be a Jehovah's Witness, as I didn't see Jehovah's accident. -- Chris Suslowicz
Hi, Am Mittwoch, 16. April 2003 22:32 schrieb David Haller:
Hallo,
[...]
Input kommt von einer Oracle Datenbank.
Ahso. Je nachdem, wie du eben an die strings rankommst musst du das eben anpassen. Ich habe eben als "Platzhalter" die libreadline fuer den interaktiven Input verwendet. Du musst das eben anpassen/ersetzen und das Eingabeende und evtl. Fehler abfangen.
Yup, schon erledig.
Hm, warum bin ich blos nicht auf die Idee gekommen einen realloc zu verwenden?
Meinte calloc, sorry.
Hast du ja, aber flasch ;) Siehe Michael's Mail zu den Fehlern...
Eine andere Frage: readline.h ist anscheinend nicht ANSI-C da sie bei mir auf meinem System nicht finden kann.
Ja, das ist die GNU-libreadline. Wenn die Daten aber eh nicht interaktiv eingegeben werden ist das egal. "readline" ist also kein Platzhalter, sondern eben der Aufruf der Funktion aus der libreadline.
Hehe, dann sollte ich die noch dazulinken :), habe dein Beispiel aber schon für meinen Code angepasst :)
Fehler habe ich allerdings keine gefunden. Soweit hat es funktioniert. Habe mir noch einmal alle Variablen angeschaut und da war das drinnen was ich mir vorgestellt habe.
Danke ;) Naja, "vollstaendige" Beispiele sind eben viel leichter nachzuvollziehen und zu ueberprufen... Daher hab ich eben auch 'input = readline("...")' verwendet statt ueber deine "getinput"-Funktion zu spekulieren... Und da dies eine SuSE-Liste ist, kann man die libreadline IMO voraussetzen ;)
Vorraussetzten schon, nur war sie mir bis heute noch nicht bekannt :). Das vollständige Beispiel hat mittlerweile fast 4000 Zeilen, da übersieht man das ganze recht schnell :) LG Georg
Hi, On Wed, 16 Apr 2003, Georg Wagner wrote:
int getAnz(void) { int i; char **array; array = (char*)malloc (sizeof(char*));
Hier allozierst du Platz fuer genau einen Pointer, also fuer array[0]. Ok soweit. Allerdings castest du den Rueckgabewert falsch. array hat Typ "char **", nicht "char *".
array[0] = (char) malloc (sizeof (char)*100);
wieder falscher cast. array[0] hat Typ "char *", nicht "char".
while (getinput) { array = (char*)realloc (array, sizeof (char*));
Und hier allozierst du Platz fuer wieder nur einen Pointer, also array[0] ;-)
array[i] = (char)realloc (array, sizeof (char*100);
Weswegen dieser Zugriff fuer i!=0 dann ins Nirvana schreibt. Ausserdem hast du als ersten Parameter fuer realloc() "array" angegeben. Das willst du hier allerdings gar nicht vergroessern (hast du ja ne Zeile drueber schon, wenns korrekt gewesen waere), sondern du willst "array[i]" vergroessern. Allerdings willst du es gar nicht vergroessern, sonder neu anlegen, also nimmst du malloc(), nicht realloc().
i++; strcpy(array[i], input);
Und hier schreibst du in array[i], hast allerdings in der Zwischenzeit 'i' schon erhoeht, schreibst also in uninitialisierten Speicher. Was du willst ist eine Schleife der Art: int i = 0; array = (char **) malloc (sizeof (char *)); while (getinput) { array = (char **) realloc (array, (i+1) * sizeof (char *)); array[i] = (char *) malloc (100 * sizeof(char)); strcpy (array[i], input); i++; } Ciao, Micha.
Hi, Am Mittwoch, 16. April 2003 21:56 schrieb Michael Matz:
array[0] = (char) malloc (sizeof (char)*100);
wieder falscher cast. array[0] hat Typ "char *", nicht "char".
Hm, sollte der Compiler dann nicht eine Waring ausspucken?
i++; strcpy(array[i], input);
Und hier schreibst du in array[i], hast allerdings in der Zwischenzeit 'i' schon erhoeht, schreibst also in uninitialisierten Speicher. Was du willst ist eine Schleife der Art:
Sorry, hatte zu dem Zeitpunkt leider keine Verbindung mit dem Rechner auf dem der Original Source liegt. War ein Fehler von mir.
int i = 0; array = (char **) malloc (sizeof (char *)); while (getinput) { array = (char **) realloc (array, (i+1) * sizeof (char *)); array[i] = (char *) malloc (100 * sizeof(char)); strcpy (array[i], input); i++; }
Super, jetzt kann ich das morgen in aller Ruhe einbauen und das Menü endlich fertig stellen. LG Georg
Hi, On Wed, 16 Apr 2003, Georg Wagner wrote:
wieder falscher cast. array[0] hat Typ "char *", nicht "char".
Hm, sollte der Compiler dann nicht eine Waring ausspucken?
% cat bla.c
#include
Hallo, On Thu, 17 Apr 2003, Michael Matz wrote:
Und trotz der Warnung oben sollte man immer mit "-W -Wall" uebersetzen, und von Anfang an alles bemaekelte fixen.
ACK. Und zumindest zum ueberpruefen auch '-pedantic'. Das bemaekelt z.B. 'sizeof(blubb)' statt 'sizeof(struct blubb)'. Gerne dann auch mal '-ansi', zumindest um mal zu sehen, ob man noch anderes uebersehen habe, bzw. sowieso, wenn man ANSI-konform programmieren will. Je nach Anwendung kann man da aber z.B. ANSI-spezifische Warnungen ignorieren. Ich bin der Meinung, dass man die Moeglichkeiten Fehler zu erkennen, die ein Compiler oder Linker bietet, durchaus auch wahrnehmen sollte. Man sollte sich dadurch allerdings auch nicht zu Nachlaessigkeiten oder Schlamperei verfuehren lassen. Und falls man mal doch nen Sonderfall braucht, dann lassen sich diese Warnungen AFAIK auch abschalten, bei "unused" z.B. ueber ein "__attribute__((unused))"... ggfs. per define fuer verschiedene Compiler. Bei manchen Anwendungen, v.a. z.B. Hardware-nahes auf $PLATTFORM, da kann, nein eher muss, man dann ANSI-Kompatibilitaet eben ab und an ignorieren, aber da sollte man dann eben auch genau wissen, was man tut. -dnh -- Ihr Scherzkekse! Computer - und das sollte bekannt sein - rechnen garnicht. Sie setzten oder löschen bits. Nicht mehr, nicht weniger. Daß dies gelegentlich wie "Rechnen" oder "Usenet" oder "Display Postscript" aussieht ist eher Zufall, trägt aber zur Erhaltung der Art bei. -- Dietz Proepper in dasr
Hi, Am Donnerstag, 17. April 2003 00:39 schrieb Michael Matz:
% gcc -c bla.c bla.c: In function `f': bla.c:7: warning: assignment from incompatible pointer type bla.c:8: warning: cast from pointer to integer of different size bla.c:8: warning: assignment makes pointer from integer without a cast
I.e. sogar ohne jede -W Option wird hier gewarnt. Insbesondere auch ueber den alles kaputt machenden (char) cast. Was er tut ist, den pointer von malloc in ein char umwandeln, i.e. in irgendwas zwischen 0 und 255, womit dieser Pointer reichlich invalid wird. Deshalb die etwas elaborierten Warnungen fuer Zeile 8. Bei einem Mismatch zwischen (char*) und (char**) sind beides wenigstens noch Pointer, aber eben trotzdem unterschiedlich (deshalb die Warnung in Zeile 7).
Die HP-UX Maschiene auf der ich zur zeit entwickle bleibt ruhig und gibt keine einzige Warning aus und dort wird sogar mit -Wall übersetzt! LG Georg
Hi, On Thu, 17 Apr 2003, Georg Wagner wrote:
Die HP-UX Maschiene auf der ich zur zeit entwickle bleibt ruhig und gibt keine einzige Warning aus und dort wird sogar mit -Wall übersetzt!
Welche gcc Version? Und -W ist auch dabei? Und du hast mein kleines bla.c Beispiel probiert? Das waere dann ..., oeh, interessant. Ciao, Micha.
Hi, Am Donnerstag, 17. April 2003 13:56 schrieb Michael Matz:
Die HP-UX Maschiene auf der ich zur zeit entwickle bleibt ruhig und gibt keine einzige Warning aus und dort wird sogar mit -Wall übersetzt!
Welche gcc Version? Und -W ist auch dabei? Und du hast mein kleines bla.c Beispiel probiert? Das waere dann ..., oeh, interessant.
Nein, sorry, war wieder mein Fehler. Hatte den Source ja nicht bei der Hand wie ich gepostet habe und da habe ich den Cast falsch gehabt. Im eigentlichen Programm war er schon von vornherhein ok. LG Georg
participants (3)
-
David Haller
-
Georg Wagner
-
Michael Matz