Frage zu malloc (array)

Hm, also so funktionierts auch noch nicht^^

PHP:
	FILE*pipe=popen("ls -la", "r");
	int counter=1;
	char *buffer = (char*) malloc(sizeof(char)*200);
	while (fgets(buffer, 200, pipe))
	{
		buffer = (char*) malloc(sizeof(char)*200);
		new_value(counter, buffer);
		counter++;
		printf("%s", buffer);
	}

Da wird gar nichts angezeigt bei printf
 
setz das printf mal an den anfang von der schleife.
 
Ich hab das jetzt so verstnanden, dass das nur zutrifft, wenn in jeden Pointer auch nur 4 Chars rein geschrieben werden? Also ich verstehe nicht warum dann 6 Pointer reserviert sind bei 24 Byte?

Nein. In deinem Beispiel oben werden nirgendwo Strings kopiert oder geschrieben!

In deinem Beispiel werden nur Zeiger geschrieben. Deswegen kommst du auch nur mit einem malloc aus! (Wichtig zu verstehen)

Du hast in deinem Programm eine String-Konstante "\ntest".
Die steht meinetwegen an der Speicherstelle 0x00401020.

Bei dieser Zuweisung:
test="\ntest";

Schreibst du eigentlich:
test= (char*) 0x00401020;

Und das an jeder Stelle des Arrays! Das heisst du hast am Ende ein Array mit 15 Zeigern, wo überall 0x00401020 drinsteht. Und diese Adresse belegt für jeden Array-Eintrag genau sizeof(void*) Byte. Also 4.

Deswegen funktioniert das ohne zweites malloc. Allerdings ergibt sich dadurch ein Problem. Wenn du den String auf den test[0] zeigt, änderst, dann verändern sich logischerweise alle. Ist ja derselbe String den du anfässt. Alle Einträge zeigen auf dieselbe Speicherstelle mit "\ntest".

Wenn du aber dein Testbeispiel ungefähr so ähnlich haben möchtest wie dein Problem. Dann müsstest du für jede Array-Zelle:

test[0] = (char*)malloc(strlen("\ntest")+1);
strcpy(test[0], "\ntest");

Dann wird jedesmal eine Speicherstelle reserviert und der String einmalig reinkopiert. Wenn du also ein String davon änderst, bleibt der Rest unberührt.

Und das zweite, wenn ich dann eh auf alles test[?] schreiben kann, was bringt mir dann sozusagen die ganze malloc prozedur? ist das dann noch speicherfreundlich? Ich könnte ja einen kleinen Wert bei malloc angeben und trotzdem alle beschreiben? wie in meinem beispiel?

Folgendes: Du möchtest für jeden Eintrag i auf einen anderen String (Zeile) zeigen. Mit i=0 für die erste Zeile.

Wenn du nur einmalig linear reservierst, und die Strings dort direkt reinschreibst in &test[0] bzw. test, dann fängst der nächste String möglicherweise erst bei &test[24] an, kommt auf die Länge des Strings an.
Dadurch verlierst du die Möglichkeit indiziert auf jede Zeile zuzugreifen.
Um den dritten String zu holen, aus deinem Speicher, müsstest du zweimal strlen() ausführen um die Stelle zu finden, an dem der dritte String anfängt.

Also: Bevor du dich auf die Listen stürzt, die auch Vorteile und Nachteile haben, würde ich mir an deiner Stelle versuchen den Unterschied ganz deutlich zu machen, wann du einen Pointer auf irgendetwas schreibst oder liest, oder wann du direkt einen String schreibst oder liest.

EDIT: Habe gerade keine Zeit für deine weiteren Versuche. Aber vlt. hilft die Erklärung ja. Sonst direkt nachfragen.

EDIT2: Weiter gehts.

char buffer[200] <- Damit reservierst du schon statisch 200 chars (Bytes). Deswegen ist wie gesagt char * buffer; richtig. Damit reservierst du Platz für nur genau einen Pointer, der auf den Platz zeigt, den du später mit malloc() reservierst.

Code:
FILE*pipe=popen("ls -la", "r");
    int counter=1;
    char *buffer = (char*) malloc(sizeof(char)*200);
    while (fgets(buffer, 200, pipe))
    {
        buffer = (char*) malloc(sizeof(char)*200);
        new_value(counter, buffer);
        counter++;
        printf("%s", buffer);
    }

Du reservierst Speicher DIREKT nach dem fgets. Damit zeigt buffer ja schon wieder woanders hin, und printf versucht einen String an einer uninitialisierten Speicherstelle zu finden und anzuzeigen. Da kann alles mögliche stehen.
 
Zuletzt bearbeitet:
Euch beiden erstmal wirklich vielen Dank, so versteht man Dinge einiges schneller, als sich tausend Tutorials durch zu lesen.

Dein erster Teil ATH0, muss ich mir noch ein paar mal durchlesen, vllt ist es auch noch nicht an der Zeit den Teil zu verstehen^^

Das mit dem malloc buffer, ist mit jetzt klar geworden, ist logisch wenn man es verstanden hat.

Ich denke so:

PHP:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>


typedef struct product_data PRODUCT_DATA;

struct product_data {
int product_code;
char *product_value;
PRODUCT_DATA *next;
};

PRODUCT_DATA *products_head = NULL;
PRODUCT_DATA *products_tail = NULL;
PRODUCT_DATA *newproduct;

void new_value(int number, char*value)
{
	newproduct = malloc(sizeof(PRODUCT_DATA));
	
	newproduct->product_code = number;
	newproduct->product_value = value;
	newproduct->next = NULL;
	
	if (!products_head) products_head = newproduct;
	else products_tail->next = newproduct;
	
	products_tail = newproduct;
}

char*read_value(int number)
{
	PRODUCT_DATA *product;
	product = products_head;
	while (product) 
	{
		if (product->product_code==number)
		{
			break;
		}
		else
		{
			product = product->next;
		}
	}
	char*back=product->product_value;
	return back;
}


int main()
{
	FILE*pipe=popen("ls -la", "r");
	int counter=1;
	char *buffer = (char*) malloc(sizeof(char)*200);
	while (fgets(buffer, 200, pipe))
	{
		new_value(counter, buffer);
		buffer = (char*) malloc(sizeof(char)*200);
		counter++;
	}
	
	int print_all;
	for (print_all=1; print_all<products_tail->product_code+1; print_all++)
	{
		printf("%s", read_value(print_all));
	}
	
	
	while (products_head)
	{
		products_tail = products_head->next;
		free(products_head);
		products_head = products_tail;
	}
	
	
	return 0;
}

ich denke damit kann ich relativ zufrieden sein, das ist genau das was ich wollte. Das ist wie eine Revolution in C für mich :D. Denn das ist ohne diese Dynamic immer sehr umständlich Pipes oder sonstiges auszulesen, wenn man nicht weiß wie lange die Ausgabe ist.

Das ist ne super sache mit den linkedlists, "wenn man es verstanden" hat...

Eine weitere Frage zu der buffer Geschichte hätte ich noch...

Was bei char buffer[200] passiert verstehe ich...
Aber wenn ich nun buffer = (char*) malloc(sizeof(char)*200); , was bedeutet genau die 200 jetzt, setzt er nun beim ersten mal 200 wie bei buffer[200] frei, und beim zweiten Aufrufen diesen Befehls nochmals 200 zu den 200 dazu? Das kann ja eig. nicht sein, da ja sonst der Inhalt von den vorherigen 200 noch darin enthalten wäre... So wie ich es verstanden habe, ist malloc dafür zuständig so viel Speicherplatz freizustellen, wie ich ich in dem Moment benötige, doch wofür ist dann die 200? Ich glaub in dem Punkt bin ich noch etwas zu verwirrt^^

edit: denn zum Beispiel hier:
newproduct = malloc(sizeof(PRODUCT_DATA));
wird ja keine bestimmte Zahl angegeben, sondern ein Datentyp, warum ist das bei der buffer sache anders?
 
sizeof gibt eine Nummer zurrück und zwar die Anzahl der Byte welche von einem Exemplar eines Datentyps verbraucht wird.
dh, sizeof(char) gibt 1 zurrück.
in den so allokierten Speicher passt dan 1 char, aber nicht mehr, aber du willst ja das 200 chars reinpassen deswegen die 200.

Das macht vor allem dann sinn, wenn du 200 integer in einem Speicherbereich reinhaben willst, das sind dann aber 800Byte.
Damit du das nicht immer ausrechnen musst sagst du einfach
malloc(sizeof(int)*200)

Noch besser wird das wenn du wie in deinem Beispiel selbstzusammengestelte Datentypen hast, dann musst du den Speicherbedarf nicht zu Fuss ausrechnen.
mfg

sw33t
 
AHH ok.
Aber warum benutze ich dann nicht gleich char buffer[200], da hab ich doch auch 200 von Typ char. Ich hab zwar verstanden, dass dann passiert, das sich die Adresse und der Inhalt von buffer immer wieder ändert, aber was ist bei malloc der Unterschied? Heißt das dann, das durch malloc buffer eine neue Adresse mit dem Speicher von 200 vom Typ char bekommt?
 
Nein bei deinem char buffer[200] ändert sich nur der inhalt nicht die adresse.

Du brauchst char *buffer = .... weil buffer[200] und buffer nicht das gleiche sind.
Eigentlich schon, aber hier ist der Fallstrick über den ich jedes mal Falle wenn ich nach längerer Zeit wieder mit Arrays arbeite(Deswegen auch mein einer Nonsenspost oben):

char buffer[200];
buffer ist ein pointer auf buffer[0];
ich kann damit also auch pointeraritmethik betreiben,aber der Compiler sieht es nicht gerne wenn man Arrayvariablen Pointern zuweist, da unterschiedlicher Datentyp, obwohl das Prinzip das ihnen zugrunde liegt das gleiche ist.

Darüber hinaus wird char buffer[200] im Stack allokiert,
während malloc und co den speicher vom Heap alloziieren.

Also du weist, wie du schon festgestellt hast,mittels malloc eine neue adresse zu.
mfg

sw33t
 
Zuletzt bearbeitet:
AHH ok.
Aber warum benutze ich dann nicht gleich char buffer[200], da hab ich doch auch 200 von Typ char.

Ja. Aber eben nur EINMAL. Das heisst, du kannst immer nur eine Zeile (mit maximal 200 Zeichen) zwischenspeichern und dann ausgeben.

Ich hab zwar verstanden, dass dann passiert, das sich die Adresse und der Inhalt von buffer immer wieder ändert,

Nein. char buffer[200] heisst: IMMER an der gleichen Adresse 200 Zeichen Platz. Und zudem kannst du diesen buffer nicht erweitern, oder auf eine andere Stelle zeigen lassen. Das wars also.


aber was ist bei malloc der Unterschied? Heißt das dann, das durch malloc buffer eine neue Adresse mit dem Speicher von 200 vom Typ char bekommt?

malloc() gibt IMMER einen Zeiger zurück. Du hast also immer so etwas wie int*, oder char*. malloc() gibt dir einfach eine Adresse und sagt: Da hast du soviel Platz wie du mir "befohlen" hast.
Im Unterschied zu char buffer[200] (innerhalb einer Funktion) liegt der Speicherbereich auch auf einem Heap. char buffer[200] würde auf dem Stack liegen und das ist bei Overflows noch gefährlicher.

EDIT: Arg. 2 Minuten zu lahm. ;)
 
Ah ok, wenn man buffer neu allociert, und es eben wie festgestellt eine neue Adresse bekommt, wird das alte buffer mit der alten Adresse gelöscht oder überschrieben?
 
Ah ok, wenn man buffer neu allociert, und es eben wie festgestellt eine neue Adresse bekommt, wird das alte buffer mit der alten Adresse gelöscht oder überschrieben?

Angenommen du machst:

buffer = (char*) malloc(sizeof(char)*200);
buffer = (char*) malloc(sizeof(char)*200);

Dann wird zweimal Speicher reserviert. Aber du kennst nur die Adresse von der letzten Speicherstelle. (Die steht in buffer)
Die alte Speicherstelle existiert zwar noch, und der Platz ist prinzipiell auch beschreibbar. Aber die Adresse ist weg. Du weißt nicht mehr wo das ist sozusagen. Und dies nennt man einen "Memory Leak". Wenn man allozierten Speicher nicht mehr freigibt, den man nicht mehr benutzt, bzw. benutzen kann.
 
Weder noch.
Der Speicher bleibt so lange liegen bis das programm beendet oder du den Speicher freigibst.
So kommen Memoryleaks zustande.

Du kannst Speicher überigens nur freigeben wenn du noch einen Pointer als Referenz auf den Speicher hast.
sonst macht das behalten des Speichers ja auch keinen Sinn.
Es gibt also keine Garbagecollection unter C.


//edit:
ha nun bin ich zu langsam gewesen, das nenn ich doch mal ausgleichende gerechtigkeit;)
 
Aber warum wurde das dann nicht sozusagen so geregelt, das der Speicher, den man nicht mehr benutzen kann weil man die Adresse nicht mehr kennt, gleich wieder freigegeben wird? Wenn man ein Programm hat in dem dieses Scenario immer wieder vorkommt, könnte ja blitzschnell der Speicher voll laufen?
Wir regeln das größere Programme?

Eine Frage nebenbei wäre, woher ihr das alles wisst, studiert ihr Informatik oder etwas in der Richtung? Ich wäre da nie mit Tutorials oder sonstiges drauf gekommen...
 
Nein. In C ist das nicht so. Es gibt aber Programmiersprachen mit "Garbage-Collector", welche unbenutzen Speicher von selbst freigeben.
C ist generell sehr minimalistisch. Man muss sich um vieles selbst kümmern. Auch um das Speichermanagement. Und das führt dazu, dass wir hacker immer wieder zu tun haben, weil viele Programmierer da etwas falsch machen und man das ausnutzen kann. 8)

"Memory Leaks" beobachtet man in-th-wild übrigens auch sehr oft. Viele Tools benötigen unglaublich viel mehr Speicher, als eig. nötig, unter anderem weil vieles nicht freigegeben wird. Das merkt man nicht direkt. Das Tool läuft ja nochl, aber es wird eben viel Speicher verbraucht.
 
Lange erfahrung,noch längere pausen und dann nochmal alles von vorn ;) . (mein geheimniss:C war die 1.Programmiersprache die ich gelernt habe)

Grössere Programme, oder Sprachen wie Python, sind mittels C so geschrieben das sie das selbst im auge behalten.
Abgesehen davon gibt es evtl momente wo du speicher nicht gleich wieder freigeben willst.

BTW: es ist ein heidenaufwand die Referenzen auf speicher im Auge zu behalten, vor allem wenn es sich um beliebige konstrukte handelt und unter Python und Co funktioniert das auch nur WEIL du nicht die freiheit hast speicher direkt anzufordern sonst wäre das ,wie schon gesagt,ein unglaublicher aufwand.
mfg
sw33t

//edit
argh... wieder zu langsam *sign*
 
Ahja, interessant, aber ich glaub da lern ich erst mal noch ein bisschen.
Wenn wir schon bei einer solchen langen Fragerei sind, was mir sehr viel bringt...
Also ich habe C++ nur sehr bruchhaft und nur Anfänge gelernt, da mir die library von GTK in Zusammenhang mit C anschaulicher aussah. Aber was wird denn nun öfters benutzt C++ oder C? C++ ist ja einiges einfacher zu lernen, heißt das dann gleichzeitig das es mehr Nachteile gibt, oder C mächtiger ist?
 
CPP ist grundsätzlich eine erweiterung von C.
CPP programme sind grösser als ihre C-Gegenstücke.
Es kommt drauf an, was du brauchst, und ist geschmackssache.

//edit auch noch was zu deinem das ist so kompliziert, es geht noch komplexer ;)
 
Aber als ich in Python größere Programme (1000-2000 Zeilen) als Anfänger schreiben wollte, hat das nach knapp 1500 Zeilen meistens mit sehr sporadischen und unauffindbaren Speicherzugriffsfehlern geendet :D :D. Habe das Gefühl, dass das in C zwar etwas öfters passiert, man sie aber besser und sicherer beheben kann und weiß wo sie her kommen. Habe die Erfahrung gemacht, das wenn das Programm mal ohne Fehler compiled und gestartet wurde, dass es dann ziemlich stabil läuft...

Naja jedenfalls, ein wirklich sehr interessanter Beitrag, kann das nur jedem empfehlen sich mal durchzulesen, besonders weil viele daran rum nörgeln pointer usw. nicht zu verstehen.
 
Guten Tag zusammen ich stehe vor einem Problem hier kurz die Aufgabenstellung und mein erster Lösungsansatz ohne Malloc allerdings soll ich das ganze jetzt mit Malloc machen stehe aber total auf dem Schlauch.

[FONT=&quot] [/FONT]
[FONT=&quot]Sie müssen einen erkrankten Kollegen vertreten, der mit der Entwicklung eines Programms zur Verarbeitung geografischer Daten beschäftigt war. Es geht darum, innerhalb eines bestimmten Gebiets den höchsten bzw. tiefsten Punkt zu lokalisieren. [/FONT]
[FONT=&quot] [/FONT]
[FONT=&quot]Ihnen steht der Quellcode zur Verfügung, an dem Ihr Kollege bis zu seiner Erkrankung gearbeitet hat. Das Programm ist bereits lauffähig und die gemessenen Geländehöhen werden aus einer Datei mit Hilfe einer Bibliotheksfunktion in ein eindimensionales Array eingelesen.

[/FONT]
PHP:
    // Array-Deklaration für die gemessenen Geländehöhen 
    double h[10201];

    // 2D-Array deklarieren
    double Array[101][101];

    // Zusätzliche Variablen deklarieren
    int anz, i = 0, j, k = 0, i_min, i_max, j_min, j_max;
    
    double h_min = 1000.0, h_max = 0.0;

    // Geländehöhen einlesen
    FILE * pF = fopen("hoehen.txt", "r");

    if (pF == NULL)
    {
        printf("ERROR");
        exit(0);
    }

    // Anzahl auslesen
    fscanf(pF, "Anzahl Daten: %i\n", &anz);    // anz wird in diesem Programm allerdings nirgendwo wirklich gebraucht, ...

    // Daten einlesen
    while (!feof(pF))
    {
        fscanf(pF, "%lf\n", &h[i++]);        // ... denn jetzt steht die Anzahl auch in i.
    }

    fclose(pF);

    // Übertragen der Rohdaten h[k] in ein zweidimensionales Array
    for(i=0; i<101; i++) 
    {
        for(j=0; j<101; j++) 
        {
            Array[i][j] = h[k++];
        }
    }

    // Lokalisieren des höchsten u. niedrigsten Punktes
    for(i=0; i<101; i++) 
    {
        for(j=0; j<101; j++) 
        {
            if(Array[i][j] < h_min) 
            {
                i_min = i;
                j_min = j;
                h_min = Array[i][j];
            }

            if(Array[i][j] > h_max) 
            {
                i_max = i;
                j_max = j;
                h_max = Array[i][j];
            }
        }
    }

    // Ausgabe des höchsten und niedrigsten Punktes auf der Konsole
    printf( "Tiefster Punkt bei i=%i und j=%i: %.1lf\n\n", i_min, j_min, h_min );
     printf( "Hoechster Punkt bei i=%i und j=%i: %.1lf\n\n", i_max, j_max, h_max);

    getch();
    return;

Sorry ich habe eine txt. datei mit 10201 Zahlen alle untereinander diese sollte ich in der ersten Aufgabenstellung so schreiben dass sie in einem 2D Array gespeichert wird. Nachdem das geschehen ist soll ich den höchsten und niedriegsten Punkt raussuchen und ausgeben. Habe ich ja soweit auch geschaft :) Nun soll das ganze mit malloc geschehen habe allerdings keinen Plan wie habe es schon ausprobiert allerdings ist mein rechner dann abgeschmiert.
 
Zuletzt bearbeitet:
Ich stehe auch ziemlich auf dem Schlauch, mir will einfach nicht einfallen wie deine Frage lautet. :wink:

Deswegen rate ich jetzt einfach mal in das Blaue hinein:
Code:
#include <stdlib.h>

int main(int argc, char **argv)
{
  double **a = (double**)malloc(5 * sizeof(double*));
  
  for (unsigned int i = 0; i < 5; ++i)
    a[i] = (double*)malloc(5 * sizeof(double));
  
  // do something

  for (unsigned int i = 0; i < 5; ++i)
    free(a[i]);
  free (a);
  
  return 0;
}

mfg benediktibk
 
Zurück
Oben