PDA

Visualizza la versione completa : [C] Stringhe allocate dinamicamente e uso di puts()


ramy89
05-12-2010, 20:26
Salve a tutti,ho scritto un programma che alloca dinamicamente caratteri per comporre una stringa,pensavo che funzionasse ma delle volte non mi stampa tutta la stringa intera.
Per esempio delle volte da input digito una stringa e me ne ristampa solo un pezzo,vorrei sapere cosa sto sbagliando.
Ecco il codice:


int main()
{
int i=0;
char *c,ci;
c=(char*)malloc(sizeof(char));
while(ci!=10)
{
ci=getchar();
c[i]=ci;
i++;
c=(char*)realloc(c,sizeof(char)*i);
}
puts(c);
return 0;
}

Andrea Simonassi
06-12-2010, 08:48
Una prima miglioria consiste nel terminare a 0 la stringa, come da convenzione in C.

Per il C la convenzione (e quello che si aspettano centinaia di funzioni C) è che la stringa di caratteri sia un array di char che termina con un carattere di valore ascii = 0.




int main()
{
int i=1;//inizialmente serve almeno un carattere per il terminatore '\0'
char *c,ci;
c=(char*)malloc(sizeof(char));

while(ci!=10)
{
ci=getchar();
c[i]=ci;
i++;
c=(char*)realloc(c,sizeof(char)*i);
}
c[i]='\0'; //inserisco terminatore '\0'
puts(c);
return 0;
}

Se vuoi anche raffinare un po il tutto, una seconda miglioria potrebbe consistere nel chiamare realloc non per ogni singolo carattere ma ogni multiplo di N (che so io 512) caratteri, risparmiando un be po di realloc.

Una terza miglioria sarebbe verificare che malloc e realloc non ritornino NULL, a meno che non sia un esercizio scolastico sarebbe anzi obbligatorio.

simo_85
06-12-2010, 09:06
#include <stdio.h>
#include <stdlib.h>

int main()
{
int i=0;
char *c,ci;
c=(char*)malloc(sizeof(char));
while(ci!=10)
{
ci=getchar();
c[i]=ci;
i++;
c=(char*)realloc(c, i + 1);
}
c[i] == 0;
puts(c);
free(c);
return 0;
}

I puntatori si liberano con la free().

ramy89
09-12-2010, 09:59
L' ho trasformata in una funzione per ottenere stringhe senza sapere la dimensione a priori,da stdin o da file:


char* get_string(FILE *fp,char*ptr)
{
ptr=(char*)malloc(sizeof(char));
int i=1;
char ci;
fflush(stdin);
while(ci!=10)
{
ci=fgetc(fp);
if(ci!=10)
ptr[i-1]=ci;
else
ptr[i-1]='\0';
ptr=(char*)realloc(ptr,(i+1)*sizeof(char));
i++;
}
fflush(stdin);
return ptr;
}

L' intento è di usarla durante un mio programma,dove ad esempio faccio:


char *p;
p=get_string(stdin,p);
/*faccio quello che devo fare*/
free(p);

La uso al posto di ogni funzione di lettura da input.

P.S.: ma se io sono sicuro che la memoria verrà allocata,per convenzione devo comunque verificare che non punti a NULL?
In genere me la realloca sempre,in che casi può fallire?

Andrea Simonassi
09-12-2010, 11:56
Si devi sempre verificare che la memoria sia stata allocata.

inoltre se realloc restituisce NULL devi ricordarti di liberare la memoria precedentemente allocata.

ramy89
09-12-2010, 12:21
Cioè...durante il programma lo interrompo e faccio comparire un messaggio di errore del tipo:memoria piena? Nel mio caso sto facendo un' agenda.

torn24
09-12-2010, 18:34
perchè la variabile i deve essere inizializzata a 1 e non a zero?



char* get_string(FILE *fp,char*ptr)
{
ptr=(char*)malloc(sizeof(char));
int i=1;//non va bene a 0?
char ci;
fflush(stdin);
while(ci!=10)
{
ci=fgetc(fp);
if(ci!=10)
ptr[i-1]=ci;
else
ptr[i-1]='\0';
ptr=(char*)realloc(ptr,(i+1)*sizeof(char));
i++;
}
fflush(stdin);
return ptr;
}

ramy89
09-12-2010, 18:43
In effetti non avevo calcolato che il terminatore viene aggiunto direttamente,prima lo aggiungevo a fine ciclo.Per cui quell' i puo' diventare 0 oppure si sostituisce (i+1) con i.Prova a vedere se va.

ramy89
09-12-2010, 21:16
Dovreste aiutarmi a rendere stabile la funzione get_string,funziona bene sulle letture da stdio,ma da file da problemi.
Molte volte mi stampa anche un' altra stringa,probabilmente è perchè l' area di memoria di ptr si è espansa e contiene qualche valore casuale,essendo che mi devo fermare a i e non i+1,però non mi include mai il terminatore alla fine,glelo devo dire 2 volte sennò non me lo considera :dhò:
Ecco qua cosa sto provando a fare,lettura da file,sostituite quel "prova.txt" con qualsiasi altro file.
Sto provando ad aprire il file prova.txt che contiene:


5
78
89
90
hhhhhh
ghhhhhh
5
30
12
30
hhhhhhhhhh
fhfhhfhf

Ecco il codice completo:


typedef struct
{
int data [4]; /* contenuto: mese,giorno,ora,minuti */
char *oggetto;
char *testo;
}nota;


typedef struct
{
int par[2]; /* parametri di ricerca di una nota */
char *parole_chiave;
}parametri;


void nota_write (FILE *fp,nota *ptr);
nota *nota_read(FILE*fp,nota *ptr);
int num_line(FILE*fp);
char* get_string(FILE *fp,char*ptr);


int main()
{
nota *ptr;
FILE *fp;
fp=fopen("prova.txt","r");
ptr=nota_read(fp,ptr);
fclose(fp);
return 0;
}

nota *nota_read(FILE*fp,nota *ptr)
{
ptr=(nota*)malloc(sizeof(nota));
fscanf(fp,"%d\n%d\n%d\n%d\n",&(*ptr).data[0],&(*ptr).data[1],&(*ptr).data[2],&(*ptr).data[3]);
(*ptr).oggetto=get_string(fp,(*ptr).oggetto);
(*ptr).testo=get_string(fp,(*ptr).testo);
return ptr;
}


void nota_write (FILE *fp,nota *ptr)
{
fprintf(fp,"%d\n%d\n%d\n%d\n%s\n%s\n",(*ptr).data[0],(*ptr).data[1],(*ptr).data[2],(*ptr).data[3],(*ptr).oggetto,(*ptr).testo);
}

int num_line(FILE*fp)
{
int c,line=1;
do
{
c = fgetc (fp);
if (c == '\n')
line++;
}while (c != EOF);
rewind(fp);
return line;
}


char* get_string(FILE *fp,char*ptr)
{
ptr=(char*)malloc(sizeof(char));
int i=1;
char ci;
fflush(stdin);
while(ci!=10)
{
ci=fgetc(fp);
ptr[i-1]=ci;
ptr=(char*)realloc(ptr,i*sizeof(char));
i++;
}
ptr[i-2]='\0';
puts(ptr);
printf("%d",strlen(ptr));
fflush(stdin);
return ptr;
}



La get_string funziona male,provate a sostituire,quel puts alla fine della get_string dovrebbe stampare la stringa letta da file,ma mi stampa:


hhhhhh
6HFI
3


Anche se il terminatore glielo ho messo e stramesso (ho anche provato a inserirlo 2 volte).
Ma niente da fare,ogni volta mi stampa una stringa sporca :dhò:

ramy89
10-12-2010, 10:09
Ecco qua l' utlima "versione" di get_string,legge riga per riga stringhe da stdin o da file (i dati vanno separati da newline).


char* get_string(FILE *fp,char*ptr)
{
ptr=(char*)malloc(sizeof(char));
int i=1;
char ci;
if(fp==stdin)
fflush(fp);
else
{
ci=fgetc(fp);
if(ci!='\0')
fseek(fp,-1,SEEK_CUR);
}
while(ci!=10)
{
ptr=(char*)realloc(ptr,i*sizeof(char));
ci=fgetc(fp);
if(ci!=10)
ptr[i-1]=ci;
else
ptr[i-1]='\0';
i++;
}
fflush(stdin);
return ptr;
}

Loading