Problema con realloc

di il
7 risposte

Problema con realloc

Per ricevere una stringa, si dichiara un vettore sufficientemente grande e il gioco è fatto.

Cosa fare quando non si conosce a priori la dimensione della stringa volendo sfruttare l'allocazione dinamica?

Ho steso un programmino con malloc e realloc, molto rudimentale, ma funzionante.

Se però provo ad inserirlo in un programma che debba leggere il nome di un file sul quale compiere certe operazioni, va tutto a farsi friggere.

Nel senso che se il nome del file che passo al programma è lungo 7 caratteri o meno, compie il suo dovere, ma se è anche di un carattere più lungo il programma si blocca e dà come errore "segmentation fault".

Spero vivamente di stare sbagliando qualcosa, altrimenti non saprei dove sbattere la testa.

Qui di seguito riporto il programma (mi scuso ulteriormente per la sintassi trasandata), sperando di ricevere un aiuto dalla community
#include <stdio.h>
#include <stdlib.h>

int main(){

	FILE *f;
	char *m, *n;
	int i=0, j, x, y, z;

	m=malloc(sizeof(char));
	m[0]=getchar();
	while(m[i]!='\n'){
		i++;
		j=i+1;
		m=realloc(m, j*sizeof(char));
		m[i]=getchar();
	}

	n=malloc(i*sizeof(char));
	for(i=0; i<j-1; i++)
		n[i]=m[i];
		
	f=fopen(n, "r");
	
	fscanf(f, "%d", &x);
	fscanf(f, "%d", &y);
	fscanf(f, "%d", &z);
	printf("%d %d %d", x, y, z);
}

7 Risposte

  • Re: Problema con realloc

    La variabile j deve partire da 1.

    Non hai previsto il carattere terminatore NULL della stringa.

    Perché allochi n e non usi m direttamente?
  • Re: Problema con realloc

    Una cosa che non viene mai spiegata (e non so perché) è che gli stream sono bufferizzati.

    Ad esempio da terminale difficilmente si superano i 2048 o 4096 byte di buffer.

    Quindi, ad esempio, allocare nello stack
    
    char m[5000] = {0};
    
    E' più che adeguato allo scopo, senza scomodare lo heap. Che poi un nome di un file non può essere così lungo, quindi la fopen fallirebbe comunque.
    Se vuoi provare a gestire i casi estremi (tipo i 32'767 byte del path dell'NTFS) ti basta comunque allargare adeguatamente la dimensione di m, ma non credo che tu abbia voglia di sperimentare da terminale una situazione del genere.
  • Re: Problema con realloc

    Weierstrass ha scritto:


    Una cosa che non viene mai spiegata (e non so perché) è che gli stream sono bufferizzati.

    Ad esempio da terminale difficilmente si superano i 2048 o 4096 byte di buffer.

    Quindi, ad esempio, allocare nello stack
    
    char m[5000] = {0};
    
    E' più che adeguato allo scopo, senza scomodare lo heap.
    Sono pienamente d'accordo con te Weierstrass: il problema è superfluo.
    Si può passare il programma da riga di comando, da standard input, si può semplicemente allocare un vettore "più grande" come tu hai giustamente suggerito.
    Ma difatti lo considero un problema fine a se stesso, una "sfida" personale da riuscire a risolvere (nonostante la totale ininfluenza che ciò può avere sul programma)

    oregon ha scritto:


    La variabile j deve partire da 1.
    Ho provato ad inizializzare j=1, ma non ha cambiato le sorti del programma oregon

    Per quanto riguarda il cambio da m a n è proprio per eliminare il terminatore NULL della stringa prima di passarlo a fopen.

    Ma ripensandoci potrei facilmente aver commesso qualche errore.

    Tu cosa cambieresti?
  • Re: Problema con realloc

    C'é un problema FONDAMENTALE con la realloc, anzi 2:

    1) frammentazione della memoria: usare in continuazione allocazioni e deallocazioni puo' frammentare la memoria a tal punto da non essere piu' in grado di fornire il blocco di memoria della dimensione necessaria. Soluzione: allocazione di blocchi piu' grandi ed a multipli del blocco minimomallocabile

    2) nella realloc viene fatta una copia byte x byte. Questo va bene per in C, MA NON per in C++

    3)le allocazioni di memoria sono LENTE, per tutta una serie di motivi. Ragion per cui meno si alloca e meglio e'

    Considerazioni:
    1) per gli esercizi, la memoria frammentata o velocita' di allocazione non sono un problema. L'esercizio usa 100 byte e tu hai 16gb di ram
    2) no, NON ESISTE il concetto di 'compattazione della memoria' in C/C++. il linguaggio non permette l'implementazione di un tale servizio
  • Re: Problema con realloc

    C'é un problema FONDAMENTALE con la realloc, anzi 2:

    1) frammentazione della memoria: usare in continuazione allocazioni e deallocazioni puo' frammentare la memoria a tal punto da non essere piu' in grado di fornire il blocco di memoria della dimensione necessaria. Soluzione: allocazione di blocchi piu' grandi ed a multipli del blocco minimomallocabile

    2) nella realloc viene fatta una copia byte x byte. Questo va bene per in C, MA NON per in C++

    3)le allocazioni di memoria sono LENTE, per tutta una serie di motivi. Ragion per cui meno si alloca e meglio e'

    Considerazioni:
    1) per gli esercizi, la memoria frammentata o velocita' di allocazione non sono un problema. L'esercizio usa 100 byte e tu hai 16gb di ram
    2) no, NON ESISTE il concetto di 'compattazione della memoria' in C/C++. il linguaggio non permette l'implementazione di un tale servizio

    Quindi, come si fa?
    In modo simile. Ci sonondue approcci:

    1) c'e un modo per sapere innanticipo la dimensione che serve SENZA allocate qualcosa
    2) c'e modo di leggere il dato un pezzetto alla volta , e quindi si usa l'approccio di allocare quanto serve di volta in volta
  • Re: Problema con realloc

    Per quanto riguarda il cambio da m a n è proprio per eliminare il terminatore NULL della stringa prima di passarlo a fopen.
    Ma che vuoi dire? Il terminatore devi aggiungerlo alla fine della stringa. E dato che hai m, lo aggiungi ad m e non usi affatto n.

    Ma il terminatore è obbligatorio!
    
    	FILE *f;
    	char *m;
    	int i = 0, x, y, z;
    
    	m = (char *)malloc(sizeof(char));
    	m[0] = getchar();
    	while (m[i] != '\n') {
    		i++;
    		m = (char *)realloc(m, (i+1) * sizeof(char));
    		m[i] = getchar();
    	}
    	m[i] = '\0';
    
    	f = fopen(m, "r");
    
    Ovviamente le obiezioni che ti sono state fatte su come è utilizzata la realloc sono vere. Ti propongo le correzioni solo per farti capire il tuo errore.
  • Re: Problema con realloc

    Molto stupidamente pensavo che la stringa passata ad fopen dovesse essere privata del terminatore: ma allora che stringa sarebbe stata?
    Grazie oregon per la dritta illuminante

    Grazie anche a migliorabile per l'illustrazione dei problemi che realloc inevitabilmente porta con sé viste le modalità d'uso della memoria!

    Il programma ora funziona correttamente
Devi accedere o registrarti per scrivere nel forum
7 risposte