Dynamische Speicherverwaltung

Googlehupf

Erfahrenes Mitglied
Hi,

ich hab mir schon ein paar Tutorials durchgelesen, die ich aber nicht im Bezug auf mein Bsp verstehe.

Ich weis nur das malloc() Bytes von z.B. Integer reserviert(Oder?), aber wie und was man genau darunter versteht leider nicht.

Darum hier mal ein Bsp(Fragen stehn in den Comments):

C++:
#include <stdio.h>
#include <stdlib.h>

#define MAX_STRLEN

int get_lineno(FILE *infile);//ermittelt die Länge, also die Zeilen der .txt Datei

void main()
{
  char filename[MAX_STRLEN]="daten_in.txt";
  int file_len = 0;
  FILE *inFile=NULL;
  double *arrayValues=NULL;//was bedeutet das genau mit NULL im Bezug auf Pointer?
  double *actVal = NULL;//gleiche wie oben
  int n=0;
  
  inFile=fopen(filename,"rt");//liest aus .txt datei
  if (inFile != NULL) //inFile wird NULL wenn Datei ende oder ein andere Fehler auftritt oder? Was wären den solche "anderen Fehler" z.b?
  {
    file_len=get_lineno(inFile);//unterprogrammaufruf, file_len=dateilänge, Anzahl der Zeilen
    rewind(inFile);
    arrayValues=malloc(sizeof(double)*file_len);//Wie schon gesagt reseviert der Befehl Bytes(falls das erwähnte stimmt :D) Double-Bytes oder? Aber bitte erklärt einfach die ganze Zeile
    if (arrayValues != NULL)//Warum schreibt man hier arrayValues ungleich NULL?
    {

      actVal=arrayValues;//Warum soll actVal = arrayValeus sein? Was hat das für einen Sinn? Warum nicht mit arrayValues weiter machen?
      for(n=0; n<file_len; n++)
      {
        fscanf(inFile,"%lf",actVal);
        actVal++;//Hier zeigt es immer um eins weiter auf die nächste Speicherstelle in eine Adresse, wo man Werte speichern kann oder?
      }
      actVal=arrayValues;//gleiche wie oben
      for(n=0; n<file_len; n++)
      {
        printf("%lf\n",*actVal);
        actVal++;//gleiche wie oben
      }
      free(arrayValues);//Naja, free=frei Speicherfreigabe vielleicht? Wenn ja was ist darunter genau gemeint?
    }
    else
    {
      printf("Memory allocation failure for Data of File %s !\n",filename);
    }
		fclose(inFile);
  }
  else
  {
    printf("File %s could not be opened!\n",filename);
  }
	//getchar();
}


int get_lineno(FILE *infile)
{
  int len =0;
  double dummy;
  
  while (!feof(infile))
  {
    if (fscanf(infile,"%lf",&dummy) == 1)
    {
      len++;
    }
  }
  return (len);
}

lg Googlehupf
 
Zuletzt bearbeitet:
Hi

zuerst get_lineno: Das funktioniert so nur dann, wenn die Zeile nur aus Kommazahlen besteht,
genau eine pro Zeile. Das sollte man etwas universeller programmieren.
fgets usw.

NULL bei Pointern steht für "zeigt auf nichts".
NULL ist (mit ein paar Besoderheiten) nur ein Name für die Zahl 0.
Da es im RAM aber keine Dresse 0 gibt, auf die gezeigt werden kann,
wurde das als "nichts" festgelegt.
Wenn man NULL nicht am Anfang zuweist, steht irgendeine Adresse im Pointer, ein Zufallswert, der als Adresse eigentlich gar nicht zum Programm gehört. Würde theoretisch nicht stöfen, wenn man erst später eine Adresse reinschreibt (bevor man den Pointer verwendet).
Wenn man aber immer konsequent NULL reinmacht, wenn er auf nichts zeigen soll, kann man das auch in if usw. abfragen.

Zum fopen: Ja, das öffnet die Datei.
Statt "rt" wäre aber "r" angebrachter. Für read. Wozu das t?

Das if...==NULL darunter: Nein, da gehts nicht um Dateienden usw.
Nur darum, ob fopen geklappt hat.
Wenn man einen Dateinamen zum read angibt, zu dem es keine Datei gibt,
das wäre so ein NULL-Fall.
Wenn fopen aber funktioniert hat, bekommt man die Adresse (Pointer) auf eine FILE-Variable,
in der für die Lesefunktionen Infos zur Datei sind.

Unterprogrammaufruf: Das stimmt soweit alles.
Allerdings ist es (für andere Leser außer dich) verwirrend,
die Zeilenanzahl als Dateilänge zu bezeichnen.
Nenns doch zeilenanz oder so.
Bei Dateilänge denkt man zuerst immer an die Byteanzahl in der Datei.

Zum malloc:
Zunächst einmal zwei Vor-Informationen:
a) Pointer können ja (wie wahrscheinlich bekannt) auf schon vorhandene Variablen zeigen,
so zB.:
C++:
int a;
int *b;
b = &a;
b) Ein Array ist im Grunde auch ein Pointer.
Bei einem Array ist die Variable selbst ein Pointer auf das erste ([0]) Arrayelement.
Die einzelnen Arrayelemente sind im Speicher direkt hintereinander,
ohne etwas dazwischen.
Und wenn man jetzt array[2] nimmt, ist das "das Startelement und zwei Variablen weiter"
(array[0] ist das Startelement und 0 weiter...deshalb beginnts bei [0]...)

Wenn man also ein int-Array hat, angenommen mit 4 ints (zu je 4 Byte):
Das "Startint" hat zB. die Adresse 100 (und besetzt auch 101, 102 und 103)
Das Nächste ist ab 104, das Dritte ab 108, das letzte ab 112

Wenn man jetzt auf meinarray[2] zugreift, ist meinarray zuerst mal ein Pointer
auf die Adresse 100. Ein int hat 4 Byte, und man muss zwei int weiter.
Daraus rechnet sich der Computer dann 108 aus, und nimmt das int von der Adresse her.

Bei deinem malloc hast du jetzt kein Array, aber einen Pointer.
Nur einen Pointer. Dem du jetzt mit malloc ein neues Array erzeugst,
wirklich Speicher für die Variablen reservierst.

Du willst die Kommazahlen in der datei abspeicher, jede Zeile hat eine.
Also sinds soviel doubles wie Zeilen.
Wieviel byte ein double hat, bekommt man mit sizeof, und das mal die Anzahl.
Ergibt, wieviel Byte man für dein neues double-Array braucht.

Das if danach: Wenn malloc ein Problem hatte (zB nicht mehr genug freier Speicher im Computer oder so) komt NULL zurück, statt der Startadresse des neuen Speichers.

so, geht gleich weiter.
 
Hi.
Ich weis nur das malloc() Bytes von z.B. Integer reserviert(Oder?),
malloc reserviert / alloziert einfach Speicher. Punkt.
aber wie und was man genau darunter versteht leider nicht.
Was meinst du denn mit wie? Wie es das macht?

int get_lineno(FILE *infile);//ermittelt die Länge, also die Zeilen der .txt Datei
Die Funktion macht nicht mal annähernd das was als Kommentar da steht....

Es muß int main heißen.

double *arrayValues=NULL;//was bedeutet das genau mit NULL im Bezug auf Pointer?
Das bedeutet, dass der Zeiger auf nichts zeigt.

if (inFile != NULL) //inFile wird NULL wenn Datei ende oder ein andere Fehler auftritt oder? Was wären den solche "anderen Fehler" z.b?
inFile ist NULL wenn die Datei nicht geöffnet werden konnte. Siehe Doku zu fopen. In errno steht ein Fehlercode.

arrayValues=malloc(sizeof(double)*file_len);//Wie schon gesagt reseviert der Befehl Bytes(falls das erwähnte stimmt :D) Double-Bytes oder? Aber bitte erklärt einfach die ganze Zeile
Datentypen haben ein bestimmte Größe. Um einen double zu speichern, benötigt man üblicherweise 8 Bytes.

Wenn man 20 double speichern will, braucht man also 20 * 8 Bytes Speicher.

if (arrayValues != NULL)//Warum schreibt man hier arrayValues ungleich NULL?
Weil malloc NULL zurückgibt, wenn es keinen Speicher reservieren konnte.

actVal=arrayValues;//Warum soll actVal = arrayValeus sein? Was hat das für einen Sinn? Warum nicht mit arrayValues weiter machen?
Weil man sich den ursprünglichen Wert (genau den den malloc zurückgegebn hat) speichern muss, damit man irgendwann free damit aufrufen kann.

actVal++;//Hier zeigt es immer um eins weiter auf die nächste Speicherstelle in eine Adresse, wo man Werte speichern kann oder?
Ja, prinzipiell schon. Es zeigt auf den nächsten double Wert in dem Array.

free(arrayValues);//Naja, free=frei Speicherfreigabe vielleicht? Wenn ja was ist darunter genau gemeint?
Da kuckst du einfach mal in eine Referenz. Steht ganz genau da... :google:

Gruß

PS: Da du deine Fragen einfach in den Code geklatscht hast, hab ich den Code einfach zwischen meine Antworten geklatscht... :p
 
Zuletzt bearbeitet:
So, oben noch was hinzufügt.

Der Rest kommt hier:

C++:
actVal=arrayValues;
for(n=0; n<file_len; n++)
{
   fscanf(inFile,"%lf",actVal);
   actVal++;
}
Da werden alle doubles (es sind ja soviele wie Zeilen) eingelesen
und in arrayValues gespeichert.
Dieser Code wäre das Gleiche:
C++:
for(n=0; n<file_len; n++)
{
   fscanf(inFile,"%lf", &actVal[n]);
}
So ist es klarer, oder?
So, wie es bei dir ist, holst du dir die Adresse des Startelements vom Array.
Liest das double dorthin ein. Und gehst mitdem actual-Pointer ein double weiter.
Einlesen, weiter...so oft, wie Zeilen in der Datei sind.


free sagt einfach "den Speicher, den ich mit malloc da bekommen habe,
brauch ich jetzt nicht mehr".

Gruß
 
Ok, danke.

Jetzt verstehe ich das Programm. Aber dieses malloc() ist mir noch nicht ganz klar. Wenn ich jetzt das malloc() und die If + else und free() weglasse und dann mit Einzelschritt F11 durchgehe kommt in Zeile 29 eine Fehlermeldung:

Unbehandelte Ausnahme bei 0x61d29348 in dynmem.exe: 0xC0000005:
Zugriffsverletzung beim Schreiben an Position 0x00000000.

Warum kommt die Fehlermeldung?
Ja, weil ich malloc() weggelassen habe schon klar :D
Kann man das net anders erklären?

Zu malloc():

C++:
arrayValues=malloc(sizeof(double)*file_len);

file_len ist ja die Anzahl an Zeilen, also im unserem File auch die Anzahl der double-Zahlen.
file_len=4
sizeof(double) sagt ja wie viel Byte 1 double hat --> 8*4=32 Bytes werden reserviert?

Und die 32 Bytes kommen dann wo hin bzw. was macht man damit?

Du willst die Kommazahlen in der datei abspeicher, jede Zeile hat eine.
Also sinds soviel doubles wie Zeilen.
Wieviel byte ein double hat, bekommt man mit sizeof, und das mal die Anzahl.
Ergibt, wieviel Byte man für dein neues double-Array braucht.

Was meintest du mit double-Array? So ein array mit index und so? z.b: array[100]?

Wenn ja wo bei malloc kommt das vor?
 
Wenn du mit "double abc[100]" ein Array machst,
besorgt der Compiler für dich 800 Byte und füllt die Adresse des ersten in den Pointer abc.

Bei "double *abc" hast du nur den Pointer, ohne die 800 Byte, die deinem Programm gehören.
Die besorgst du mit malloc (Hallo Windows, ich hätte gern 800 Byte vom Speicher für mich).
malloc gibt dir auch wieder die Adresse in abc rein.

Das if-NULL ist dann eben, wenn Windows keine 800 Byte hergegeben hat.

Und free: Da, Computer, hast du deine 800 Byte wieder, brauch ich nicht mehr.


Ein Array ist also nichts anderes als ein Pointer,
nur im einen Fall schon mit Speicherplatz versorgt.
Und egal, mit welcher der zwei Methoden du abc gemacht hast,
kannst du immer mit "abc[...]" auf die einzelnen doubles zugreifen.
 
malloc() in einer Unterprogramm nutzen und dann mittels dem vom Unterprogramm zurückgegebenen Wert, den man von malloc bekommt, im Hauptprogramm freigeben ist ja nicht so schwer.

C++:
wert=malloc(.....);

Aber was macht man wenn man 2 oder mehr Speicher anfordern muss? Ich habe zwar kein konkretes Bsp dafür, aber sagen wir mal ich muss aus einer Textdatei was auslesen und ich speichere alle Ganzzahlen in eine Variable a auf der ein Pointer zeigt und alle Kommazahlen in eine Variable b auf der auch ein Pointer zeigt.

Und für diese 2 Pointer muss ich ja 2mal malloc() verwenden also Speicher anfordern. Aber wo geben ich dann den Speicher frei? Eigentlich ganz am Ende, also im Hauptprogramm am Schluss, aber mit return kann ich ja nur einen Wert übergeben, aber ich bekomme ja 1 Wert vom malloc(pointer a) und 1 Wert von malloc(pointer b), also muss ich 2mal Speicher freigeben.

z.B. so:
C++:
typ zahlen(filename[]...)// für typ halt irgendein datentyp(int*, double*, void...)
{
  int* a;
  double* b;

  a=(int*)malloc(sizeof(int)*anzahl)//anzahl=wie viel ganzezahlen vorkommen.... und a ist der Wert mit dem man den Speicher freigeben muss
  b=(double*)malloc(sizeof(double)*anzahl1)//anzahl1=wie viele kommazahlen vorkommen... und b ist der wert mit dem man den Speicher freigeben muss
  
  while(!feof(file))
  {
     fscanf(.......)  
  }
  
}

Der Code ist nur schnell hingetippt, da ich nur das mit dem malloc zeigen wollte

Wie ich oben schon geschrieben habe, falls ich nur ein malloc nutze kann ich ja den vom malloc bekommenden Wert zurück ins Hauptprogramm geben und damit den Speicher freigeben, aber in dem Bsp da hat man 2.

Die Frage nochmal: Wie gebe ich nun den Speicher frei? Also wie kann ich dem im Hauptprogramm freigeben?

LG
 
Alloziere doch den Speicher einfach in der Hauptfunktion und lass die Funktion nur in die Variablen, die du übergibst hineinschreiben.
Dann hast du das Problem mit der getrennten Anforderung und Freigabe nicht.
 
Zurück