PDA

Visualizza la versione completa : [C] Utilizzo di malloc all'interno di un ciclo


ipspaolo
16-04-2012, 15:47
Ciao, in questo codice utilizzo la funzione malloc al di fuori del ciclo "do while", ciò vuol dire che mi alloca la memoria necessaria solo al primo elemento dell'array (giacchè nel sizeof non ho specificato "n*" è come se avessi scritto 1*).
Solo così il programmino riesce a girare; secondo me invece dovrei allocare 1 elemento per ogni volta che scelgo di inserire un nuovo dato. Se, però inserisco la malloc all'interno del "do while" il programma non gira.
Mi sa che così, anche se funziona tutto, gestisco male la memoria.
Qualcuno potrebbe chiarirmi le idee?
grazie in anticipo


struct mail{
char indirizzo[30];
} *email = NULL;
int i=-1;
int n=0;
char scelta[2];
email=(struct mail*)malloc(sizeof(struct mail));
do {
i++;
printf("\nInserisci il %d° indirizzo email: ",i+1);
scanf("%s", email[i].indirizzo);
printf("\nNuovo indirizzo?: ");
scanf("%s", scelta);
} while (strcmp(scelta,"s")==0);
for (n=0; n<=i; n++) {
printf("\nMail nr.%d: %s",n+1,email[n].indirizzo);
}
free (email);

oregon
16-04-2012, 16:03
Certo che dovresti allocare nel ciclo ma dovresti avere anche un array di puntatori e non un semplice puntatore.

Ovvero, ad esempio, per 100 inserimenti

struct mail *email[100];

nel ciclo

email[i]=(struct mail *)malloc(sizeof(struct mail));

e di conseguenza puntare all'elemento con il ->

email[i]->indirizzo

Caiodark
16-04-2012, 16:19
Potresti chiedere come ulteriore parametro N quanti indirizzi si vogliono inserire ed allocare la memoria in conseguenza di questo, in questo modo il ciclo avrebbe solo N interazione e non dovresti chiedere se si desidera inserirne altri.
Oppure dovresti utilizzare realloc nel ciclo, questo manterrebbe la possibilità di inserire indirizzi finché l'utente dice stop ma non è il top dell'efficienza e bisogna riallocare con parsimonia (tipo ogni tot cicli).

Approccio 2


# define NEW_RECORDS 10
struct mail{
char indirizzo[30];
} *email = NULL;
int i=-1;
int n=0;
int allocazioni = 1;
char scelta[2];
email=(struct mail*)malloc(NEW_RECORDS*sizeof(struct mail)); //alloco inizialmente 10 posti
do {
i++;
if (i == allocazioni * NEW_RECORDS){
email=(struct mail*)realloc(((allocazioni ++) * NEW_RECORDS)*sizeof(struct mail)); // realloc è dispendiosa, alloco 10 nuovi record per volta
}
printf("\nInserisci il %d° indirizzo email: ",i+1);
scanf("%s", email[i].indirizzo);
printf("\nNuovo indirizzo?: ");
scanf("%s", scelta);
} while (strcmp(scelta,"s")==0);
for (n=0; n<=i; n++) {
printf("\nMail nr.%d: %s",n+1,email[n].indirizzo);
}
free (email);

Who am I
16-04-2012, 21:59
Considera questo codice:


struct mail{
char indirizzo[30];
} *email = NULL;
int i=-1;
int n=0;
char scelta[2];
do {
email=(struct mail*)malloc(sizeof(struct mail));
i++;
printf("\nInserisci il %d° indirizzo email: ",i+1);
scanf("%s", email[i].indirizzo);
printf("\nNuovo indirizzo?: ");
scanf("%s", scelta);
} while (strcmp(scelta,"s")==0);
for (n=0; n<=i; n++) {
printf("\nMail nr.%d: %s",n+1,email[n].indirizzo);
}
free (email);


L' istruzione email=(struct mail*)malloc(sizeof(struct mail)); è un assegnamento.Ciò significa che se metti questa istruzione nel ciclo, continui a riassegnare il valore di email, che punterà alla nuova zona di memoria allocata.
email non è un array, e tu nel for lo stai trattando come se fosse un array.
Stampare email[0].indirizzo va bene, sarebbe come stampare (*email).indirizzo, cioè email->indirizzo, ma stampare email[1].indirizzo dovrebbe causare segmentation fault.
oltre al segmentation fault c'è una perdita di memoria perché continui a riassegnare email senza liberare la zona di memoria precedentemente allocata.

ipspaolo
16-04-2012, 23:16
Grazie ragazzi, ho adottato la soluzione della realloc perché è più vicina alle mie esigenze; le altre prevedono un numero di inserimenti predefiniti e a me non piace.

Capito anche il problema malloc all'interno del ciclo (in effetti era logico), però email lo tratto come se fosse un array perché voglio che sia un array di struct mail e credo di esserci riuscito perché mi stampa in ordine tutti gli indirizzi che vado ad inserire

oregon
16-04-2012, 23:28
Non so che codice hai usato ma se non hai utilizzato un vettore di puntatori ma tratti il semplice puntatore come se lo fosse, il tuo programma potrà avere problemi di crash (che magari adesso non si verificano per motivi di status attuale della memoria).

Ti consiglio di valutare bene quello che ti è stato suggerito, non perché sono delle soluzioni tra cui scegliere rispetto alla tua ma perché il tuo codice è sbagliato.

ipspaolo
17-04-2012, 00:47
Il codice che ho usato è questo:



#define dim 5 //alloco 5 blocchi di memoria per volta(*allocazioni che viene incrementato ogni 5 inserimenti)
struct mail{
char indirizzo[30];
} *email = NULL;
int i=-1;
int n=0;
int allocazioni=1; //coefficiente per incrementare i blocchi da reallocare
int alloc=1; //dimensione nuovo blocco
char scelta[2];
email=(struct mail*)malloc(dim*sizeof(struct mail));
do {
i++;
if (i == allocazioni * dim){ //quando i(num mail) diventa uguale ad un multiplo di 5
allocazioni++; //aggiorno il coefficiente
alloc=allocazioni*dim; //definisco il nuovo blocco
email=(struct mail*)realloc(email, (alloc*sizeof(struct mail ))); //e rialloco la memoria
}
printf("\nInserisci il %d° indirizzo email: ",i+1);
scanf("%s", email[i].indirizzo);
printf("\nNuovo indirizzo?: ");
scanf("%s", scelta);
} while (strcmp(scelta,"s")==0);
for (n=0; n<=i; n++) {
printf("\nMail nr.%d: %s",n+1,email[n].indirizzo);
}
free (email);


Se mi dite che sbaglio non c'è dubbio, mi fido ciecamente dell'esperienza ( altrimenti non stavo qui a scrivere), ma non riesco a capire dove:

Ho letto (e spero di aver letto bene) che un vettore di caratteri statico (con il valore di "n" noto) lo dichiaro

char xxx[n];

mentre un vettore di caratteri dinamico lo dichiaro

char *xxx;

perché un vettore di struct dovrebbe essere diverso?

D'altronde il fatto che quando stampo "email[n]" vengono mostrati i valori inseriti, correttamente ed in ordine di inserimento, mi fa supporre che per ogni valore di "n" è stata creata una cella (email[n]) che contiene l'ennesimo dato inserito.

Fatemi capire dove sbaglio altrimenti comincio male

torn24
17-04-2012, 11:49
Non è sbagliato l'ultimo codice che hai inserito , e fa correttamente quello che ti serve!

E' SBAGLIATA , la domanda che hai posto , hai chiesto ,in pratica ,se era possibile usare malloc all'interno del ciclo , quindi ti hanno risposto SI se usi un array di puntatori , e allochi per ogni elemento spazio per la struttura.
ma non era quello che volevi fare tu, quindi , sono risposte che non ti servono e
che "non devi prendere in considerazione" per questo problebla.

La domanda che avresti dovuto porre è , come alloco altra memoria ad un array dinamico
all'interno di un ciclo , e ti avrebbero indicato quasi sicuramente direttamente la realloc


gli esperti non capiscono e non parlano il "principiantese" :D

quindi noi ,che lo siamo ,dobbiamo spiegarci in modo corretto , altrimenti non otteniamo
l'aiuto voluto :ciauz:

oregon
17-04-2012, 11:54
Originariamente inviato da ipspaolo
Il codice che ho usato è questo:

Ti faccio notare che nel primo tuo post hai scritto

email=(struct mail*)malloc(sizeof(struct mail));

mentre nell'ultimo hai scritto

email=(struct mail*)malloc(dim*sizeof(struct mail));

Ovviamente sono cose diverse e solo la seconda è corretta.

ipspaolo
17-04-2012, 16:21
Si, è vero, l'ho cambiato quando mi è stato suggerito di usare la realloc. A quel punto ho dovuto per forza allocare blocchi di misura" dim".
Ragazzi/e vi ringrazio tutti e cosa importantissima è che grazie alle vostre indicazioni ho capito di avere capito

Loading