Newsgroup: it.comp.lang.c
Titolo: stringhe di lunghezza qualsiesi a posteriori (probelma con free)

Ho creato una funzione, char *legge(void) che alloca automaticamente
l'alrea di memoria riservata a una stringa di cui non si conosce a priori
la lunghezza. Il problema è che non so come liberare in seguito l'area di
memoria occupata: 
free(puntatore)
se compilato con visual c++ mi da un errore(cioè viene compilato il tutto
senza warning e/o errori, ma
 il programma si blocca una volta arrivati a free, mentre col borland
5.5(command line) nessun problema. 
Non so se l'area di memoria viene effettivamente liberata se compilata col
borland o no.
Non ho idea del perchè dell'errore:
qualcuno sa spiegarmi il tutto.
p.s. posto il codice per controllare
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <limits.h>
char *legge(void);
void main(void) {
	char *stringa;
	printf("Inserisci stringa\t[INVIO PER TERMINARE]\n:");
	if((stringa=legge())!=NULL)
                printf("\n\nLa stringa inserita Š:\n%s", stringa);
	else
                printf("Non Š stata inserita alcuna stringa\n");
	//free(stringa);		Questo free causa un errore fatale se compilato con
Visual C++ 6.0, non col Borland 5.5
	printf("\n\nPremere un tasto\n");
	getch();
}
char *legge(void)
{
	unsigned int n=0;
	char tempchar;
	char *string, *temp;
	if((string=(char *)calloc(sizeof(char), 1))==NULL){
		printf("\a\n");
		return NULL;
	}
	string[0]='\0';
	do {
		n++;
		tempchar=getch();
		if(tempchar!=8) {//cioè non si è premuto cancelletto
			if((temp=(char *)realloc(string, n+1))==NULL){
				printf("\a\a\a\n");
				return string;
			}
			string=temp;
			string[n-1]=tempchar;
			string[n]=0;
			putch(tempchar);
		}
		else if(n>1) {
			putch(8);
			putch(32);
			putch(8);
			if((temp=(char *)realloc(string, n-1))!=NULL) {
				string=temp;
				n=n-2;
				string[n]=0;
			}else {
				printf("\a\n");
				return string;
			}
		} else
			n--;
	}while(string[n-1]!=13 && n<UINT_MAX);
	if((temp=(char *)realloc(string, n-1))==NULL) {  //tolglie l'invio
		printf("\n");
		if(n>2)
			return string;
		else {
			//free(string);		Questo free causa un errore fatale se compilato con
Visual C++ 6.0, non col Borland 5.5
			return NULL;
		}
	}
	//else
	string=temp;
	string[n-1]=0;
	printf("\n");
	return string;
}

 memoria occupata:
   Posso darti un consiglio spassionato? Butta l'implementazione di 
leggi() e ricomincia da capo: richiamare la funzione realloc() 
all'inserimento di ogni singolo carattere e` quanto di meno efficiente 
(per usare un eufimismo) abbia mai visto.
   Se proprio hai problemi di memoria, alloca sullo stack un buffer 
ausiliario in leggi(), leggici dentro la stringa (magari usando le 
bellissime funzioni, come fgets(), messe appositamente a disposizione 
dalla libreria standard), misura la lunghezza effettiva della stringa 
letta, alloca sullo heap lo spazio che ti serve e copiaci dentro la tua 
stringa.
   Se hai intenzione di leggere veramene molti caratteri, puoi 
riallocare la memoria sullo heap ogni volta che "sfori" il buffer 
ausiliario (e fgets() sembra proprio fatta apposta per cose di questo 
tipo), riducendo il numero di chiamate a realloc() della dimensione del 
buffer stesso.
   All'uscita dalla funzione, il buffer ausiliario verra` liberato e 
sara` riutilizzabile, e poiche` era stato allocato sullo stack neanche 
contribuira` alla frammentazione del pool di memoria gestito dalle 
malloc() & Co.
-- 
Alla prossima,
Marco


So che era poco efficiente; grazie del consiglio, cmque ho fato quella
funzione solo per curiosità. Proverò a fare come dici.

 free(stringa); Questo free causa un errore fatale
Non ho verificato tutto il programma, però quel free(stringa) va eseguito
solo se stringa è diversa da NULL.
Maurizio.

 eseguito solo se stringa e` diversa da NULL.
Lo  standard  ammette  una  chiamata  del  tipo  free(NULL)  ed  il  suo
comportamento e` definito: non fa nulla.
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
Porc i' mond che cio' sott i piedi!
V. Catozzo

  ed  il  suo comportamento e` definito: non fa nulla.
Non lo sapevo. Grazie per la info.
Maurizio.

 Visual C++ 6.0, non col Borland 5.5
Lo standard prevede che in caso di fallimanto di realloc(), l'array
originario deve rimanere valido; forse il VC++ la pensa diversamente.
Due note:
- non usare realloc() per cambiare dimensione di un solo byte, ma cerca
  di lavorare con blocchi più grossi, almeno di 1KB;
- se la tua libc la implementa, puoi usare la getline(), che fa
  esattamente quello che tu vorresti facesse la leggi().
-- 
Saluti,
    Mardy
http://castellina.org/interlingua