Adressierung und andere Probleme
-
Hallo,
ein kleines Beispiel wo ich so meine Probleme mit der Adressierung habe.
Ich erzeuge in der Funktion "lesen_config" Speicher fülle Ihn und gebe die Anzahl auch zurück.typedef struct { int filenr; int valuenr; int bit; char bit_0_text[50]; char bit_1_text[50]; int refresh; int flanke_bit_0; int flanke_bit_1; } block; int main(int argc, char *argv[]) { int anzahldateien = 0; char* filenamen = NULL; int anzahlbloecke = 0; block* variablenblock; i = lesen_config ("mein_configname", &anzahldateien, &filenamen, &anzahlbloecke, &variablenblock); } int lesen_config (char* configname, int* anzahldateien, char** dateinamen, int* anzahlbloecke, block** statusblock)
Und jetzt die Probleme mit der Adressierung bzw. Parameterübergabe an andere Funktionen. (es kommt nur darauf an ob ich die Adressierung richtig habe bzw. den Aufruf der lesen_config - Funktion)
z.B. *dateiname = realloc(*dateiname, *anzahldateien * laengeinbyte) oder strcpy(&((*dateinamen)[*anzahldateien - 1]), "was ich kopieren will"); oder (*statusblock)[*anzahlbloecke - 1].filenr = zahl; *anzahlbloecke++;
sind diese 4 Zeilen richtig oder schreibe ich z.B. die "zahl" in den Adressspeicher oä.
Sobal ich die Adresse der Adresse an eine Funktion übergebe...dann ist es AUS mit dem Verständnis.
Danke
worst_case
-
Hallo...
für die 'Dateinamen' solltest Du das in etwa so machen:
#include <stdio.h> #include <stdlib.h> #include <string.h> int lesen_config(char ***); int main(void) { char **dateinamen = NULL; int i; i = lesen_config(&dateinamen); while (i-- > 0) puts(*dateinamen++); return 0; } static char *my_strdup(char *str) { char *t = malloc(strlen(str) + 1); if (t) strcpy(t, str); return t; } int lesen_config(/* ... */ char ***dateinamen /* ... */) { *dateinamen = realloc(*dateinamen, sizeof(**dateinamen) * 3); (*dateinamen)[0] = my_strdup("Zeile 1"); (*dateinamen)[1] = my_strdup("Zeile 2"); (*dateinamen)[2] = my_strdup("Zeile 3"); return 3; }
Den Rest habe ich mir nicht mehr angeschaut...
-
ups, jetzt geht es dahin. Null Durchblick
Ich hab hier ein paar Fragen.
1. Die Dateinamen werden aus einer Datei gelesen. Deshalb wollte ich nach
jedem lesen speicher reservieren, da ich in der ersten Zeile nicht weiß wie
viel Dateinamen noch kommen.sizeof(**dateinamen) *3
geht nicht. Ist klar..konntest du nicht wissen.
2. was ergibt
sizeof(**dateinamen)
Es ist doch nirgens eine Größe angegeben
3. was bedeutet
char***
Es werden ja immer mehr Adressen der Adressen usw.
4. Es würde genügen wenn du die Abfragen bzw. Zuweisungen von den jeweiligen
char **
mal dir ansiehst (ich hab da wenigstens ein bißchn Ahnung)
Danke
worst_case
-
Oki... Dann schaun wir uns mal die neue Version von 'lesen_config()' an. Zum Test werden Strings über stdin eingegeben. Das simuliert das Lesen der Dateinamen.
int lesen_config(/* ... */ char ***dateinamen /* ... */) { int anz = 0; char *p, line[100]; while (p = fgets(line, sizeof line, stdin)) { *dateinamen = realloc(*dateinamen, sizeof(**dateinamen) * ++anz); (*dateinamen)[anz-1] = my_strdup(p); } return anz; }
Gespeichert werden die Eingaben/Dateinamen mit Hilfe der Funktion 'my_strdup()'. Das Hauptprogramm und alles andere bleibt gleich.
Edit: Die Strategie den Speicher zu allozieren ist nicht optimal. Ebenso fehlt ein Test auf einen NULL-Wert bei realloc()....
-
Hallo,
ich habe mir Gestern und Heute Gedanken über dein Programm gemacht.
Es will es mal kurz mit meinen Worten erkären, damit ich sehe ob ich es auch richtig interpretiere (schönes Wort)Also.....
char **dateinamen = NULL;
erzeugt einen Vector für char-Adressen. Die Adresse des Vector mit "NULL" initialisiert
int lesen_config(char ***);
Es wird die Adresse des Vectors mit char Adressen übergeben
*dateinamen = realloc(*dateinamen, sizeof(**dateinamen) * ++anz);
Es wird Speicher für jeweils eine Adresse im Vector reserviert.
(*dateinamen)[anz-1] = my_strdup(p);
Funktion ist klar. Der Rückgabewert...also die Adresse des "Dateinamen (String)" wird in den Vector geschrieben.
d.h.
Im Vector stehen die Adressen des Strings der Dateinamen. Also die Strings sind nicht hintereinander angeordnet (laut Adresse), sondern beliebig je nach freien Speicher. Und nur über den Vector (der die Adressen enthält) kann ich auf den Speicher des String's Dateiname zugreifen.
Was hat diese Methode für einen Vorteil gegenüber der Methode
char* dateinamen
übergebe an die Funktion
lesen_config (char** dateinamen)
reserviere Speicher
*dateiname = realloc(*dateiname, *anzahldateien * laengeinbyte)
und beschreibe Wert
strcpy(&((*dateinamen)[*anzahldateien - 1]), "was ich kopieren will");
Natürlich bin ich lernwillig und will das optimum (soweit meine Fähigkeiten), aber ich will nicht bei einem Problem in meinem Programm alles komplett umschmeissen nur weil es besser aussieht. Nebebei will ich wenn möglich alles verstehen, warum und wieso etwas so gemacht wird.
Ich weiß ich nerfe ein wenig, aber wenn ich es verstehe brauche ich seltene das Forum. Es gibt nihct's schlimmeres wenn ein Programm funktioniert und man weiß nicht warum.
Danke
worst_case
-
worst_case schrieb:
...
char **dateinamen = NULL;erzeugt einen Vector für char-Adressen. Die Adresse des Vector mit "NULL" initialisiert
Fast. 'dateinamen' ist ein Zeiger auf einen Zeiger auf Char. Aber Du meinst schon das richtige
int lesen_config(char ***);
Es wird die Adresse des Vectors mit char Adressen übergeben
Ja
*dateinamen = realloc(*dateinamen, sizeof(**dateinamen) * ++anz);
Es wird Speicher für jeweils eine Adresse im Vector reserviert.
Ja
(*dateinamen)[anz-1] = my_strdup(p);
Funktion ist klar. Der Rückgabewert...also die Adresse des "Dateinamen (String)" wird in den Vector geschrieben.
Ja
d.h.
Im Vector stehen die Adressen des Strings der Dateinamen. Also die Strings sind nicht hintereinander angeordnet (laut Adresse), sondern beliebig je nach freien Speicher. Und nur über den Vector (der die Adressen enthält) kann ich auf den Speicher des String's Dateiname zugreifen.
Genau.
Was hat diese Methode für einen Vorteil gegenüber der Methode
char* dateinamen
übergebe an die Funktion
lesen_config (char** dateinamen)
reserviere Speicher
*dateiname = realloc(*dateiname, *anzahldateien * laengeinbyte)
und beschreibe Wert
strcpy(&((*dateinamen)[*anzahldateien - 1]), "was ich kopieren will");
So wir ich das sehe, müssten dann alle Dateinamen gleich lang sein damit man auf einen bestimmten Eintrag zugreifen kann...
Natürlich bin ich lernwillig und will das optimum (soweit meine Fähigkeiten), aber ich will nicht bei einem Problem in meinem Programm alles komplett umschmeissen nur weil es besser aussieht. Nebebei will ich wenn möglich alles verstehen, warum und wieso etwas so gemacht wird.
Umso länger ich über die Sache nachdenke, umso mehr drängt sich mir der Gedanke auf, dass Dein Programm/Problem mit einer anderen Datenstruktur (verkettete Liste?) besser bedient wäre. Schließlich quälen wir uns hier 'nur' wegen der Dateinamen rum. Es sind ja noch andere Dinge/Daten zu beachten....
-
Hi,
wenn ich nun den Speicher löschen will geht das ja nicht nur mit
free(**dateinamen);
sondern ich muss vorher alle Adressen im Vector einzeln ansprechen und löschen
oder ?free((*dateinamen[x..n]);
Ist das richtig ??
worst_case
-
Beim freigeben kann man sich gut an der Syntax beim allokieren orientieren:
T *p, **pp; p = malloc(...); *pp = malloc(...); /* ... */ free(p); free(*pp);
Ich habe mir eine kleine Funktion geschrieben, die die Dateinamen wieder freigibt:
void freigeben(char ***dateinamen, int n) { while (n-- > 0) free( (*dateinamen)[n] ); free(*dateinamen); *dateinamen = NULL; }
Das müsste soweit dann passen...