[C] char * zu lang, Speicherzugriffsfehler?

corema

Grünschnabel
Hallo Community,

ich habe erst vor kurzem angefangen unter Linux Ubuntu C zu lernen, bin also noch ein blutiger Anfänger.
Ich möchte eine Website aufrufen, und deren Inhalt verarbeiten.
Dazu habe ich einen Socket gebastelt, der http und https unterstützt. Über diesen rufe ich die gewünschte Seite auf. Dabei wird über eine Pipe die Seite an den verwaltenden Prozess weitergeleitet.
Dieser Speichert die Seite in einer Variable (char *), indem die übermittelten Daten an die Variable immer hinten ran gehängt werden.

Das Problem entsteht, so vermute ich, wenn der Speicherbedarf der Variable zu groß wird:
Rufe ich beispielsweise "http://www.google.de" auf komme ich auf Größe von (43349 Bytes müssten es ein)
Enthält die Seite beispielsweise eine lange Liste, können 134912 Bytes zugewisen werden. Sobald die nächsten 256 Bytes rangehängt werden sollen (= 135168 Byte) entsteht ein Speicherzugriffsfehler und das Programm stürzt ab.

Das "Ranhängen" wird wie folgt bewerkstelligt:
Code:
int i;
char buff[256];
char *result = (char *) malloc(0);
 
while ((i = read(pout[0], &buff, sizeof(buff))) != 0) {
	if (i == -1) { perror("read"); }

	memcpy (&result[strlen(result)], buff, i);
	fflush(0);
}

Hängt das damit zusammen, dass ein Variable in C nur eine bestimmten Größe haben darf, oder ist da auf char* begrenzt?
Gibt es eine Möglichkeit mein Problem zu beheben?

Vielen Dank schonmal für eure Hilfe!
LG
 
Zuletzt bearbeitet:
Hi und Willkommen bei tutorials.de,

Theoretisch ist die Größe nicht sprachenmäßig begrenzt
(bzw. man kann den ganzen verfügbaren Speicher vom Computer nutzen).
Aber: Ein einfaches
C++:
char *irgendwas;
hat gar keinen Speicher.

Falls du Java oder C# kennst, kurz:
Du hast ein
C++:
byte[] irgendwas;
Dir fehlt aber vom Prinzip her das
C++:
= new byte[1234];

Ausfürlicher:
Einem char* kann man zur Programmlaufzeit einen beliebig großen Speicherbereich reservieren,
mit
C++:
variable = malloc(byteanzahl)
. Im Gegensatz zu zB. Java gibt es keinen Garbage Collector,
also muss der "manuell" angelegte Speicher irgendwann nach Verwendung
mit
C++:
free(variable)
auch wieder freigegeben werden.

Der zweite Teil deines Problems: Du weißt am Anfang vermutlich nicht,
wie viele Byte du letztendlich benötigst.
Daher am Anfang eine bestimmte Größe anlegen und in einem int mitspeichern,
wie viel Byte schon gelegt sind. Wenns voll wird kann man das Array mit realloc vergrößern.
(realloc sollte sparsam verwendet werden, aus Geschwindigkeitsgründen etc.
Also am Besten nicht für alle 256 Byte eine Vergrößerung, sondern zB.
eine Verdopplung der aktuellen Größe, wenns grad voll wurde)
 
Hi,
falls der Server im HTTP-Header das Feld Content-Length mitschickt, könntest du diesen auslesen und ausreichend Speicher alloziieren, damit du bei kleineren Seiten nicht so einen riesen Overhead hast.

Grüße
 
Vielen Dank sheel,

Java und C# kenne ich leider nicht, lediglich Delphi.
Dass der Buffer eine feste größe hat, liegt an der Pipe, da diese nur bis zu einer best. Größe daten sicher transferieren kann (so weit ich das richtg verstanden habe).
Ich habe die 256 in PIPE_BUF (ca. 4000) geändert, was natürlich an dem Problem an sich nichts ändert.
Mir war gar nicht aufgefallen, dass ich den Speicherbereich der Variable gar nicht vergrößert habe.
Mit realloc konnte das Problem gelöst werden.
Auf Grund des von dir angesprochenen Geschwindigkeitsmanko, werde ich mal schauen, wie ich den Vorschlag von Jennesta mit einbauen kann.
So funktioniert es derweilen:
Code:
pid_t pid;
char *result = (char *) malloc(0);
long count=0;

while ((i = read(pout[0], &buff, sizeof(buff))) != 0) {
	if (i == -1) { perror("read"); }
		
	count = count+i;	
	result = realloc(result, count);
	memcpy (&result[strlen(result)], buff, i);
	fflush(0);
}
Vielen Dank euch beiden!
 
Zurück