PDA

View Full Version : [C] Come posso risolvere?


DanieleC88
01-07-2005, 16:51
Mi trovo in questa situazione: ho del codice che si occupa di gestire una lista di dati aggiunti alla lista con la funzione push(), ma alla fine risulta aggiunta una sola voce (basta vedere la funzione push()):
typedef struct elem {
voce* ptvoce;
struct elem* next;
} elem;

int push(elem** db, voce* v)
{
elem * nuova = (elem *) malloc(sizeof(elem));
elem * step = (elem *) (*db);

nuova->ptvoce = v;
if (step)
{
step = step->next;
}
step = nuova;

return 0;
}

Come faccio ad accodare una voce senza usare quegli assegnamenti che cambiano l'intero valore dell'elem** db?

Brazorv
01-07-2005, 17:04
typedef struct elem {
voce* ptvoce;
struct elem* next;
} elem;

int push(elem** db, voce* v)
{
elem * nuova = (elem *) malloc(sizeof(elem));
elem * step = (elem *) (*db);

nuova->ptvoce = v;
if (step)
{
nuova->next=step;
}

step = nuova;

return 0;
}


prova così

EDIT

71104
01-07-2005, 20:29
hai una lista (espressa nella forma di un puntatore al suo primo elemento, che può anche essere nullo) e devi accodargli un nuovo elemento, ho capito bene? io farei così (non l'ho provato): typedef struct _elem {
voce *pvoce;
struct _elem *next;
} elem;

int push(elem **head, voce *pv) {
if (!head) {
return -1;
}
elem *nuovo = (elem*)malloc(sizeof(elem)), **step;
nuovo->pvoce = pv;
nuovo->next = NULL;
for (step = head; *step; step = &(*step)->next);
*step = nuovo;
return 0;
}
ciao

Brazorv
01-07-2005, 21:24
non credo che quel codice metta un elemento in coda alla lista.
Se vuoi aggiungere un elemento come ultimo della lista devi fare un ciclo per trovare l'ultimo elemento attuale e poi metterlo dopo di questo.
Se non ho capito male lui vuole metterlo sempre in testa alla lista.

DanieleC88
01-07-2005, 21:33
Innanzitutto grazie ad entrambi delle risposte (devo ancora provarlo).
Poi: non mettere il nuovo elemento in cima alla lista (quello lo facevo tranquillamente), devo invece accodare il nuovo elemento alla lista.

71104
01-07-2005, 22:00
avete ragione, un imperdonabile errore :p
ho editato, così dovrebbe andare, a meno di altri imperdonabili errori :D
ariciao :)

Brazorv
01-07-2005, 22:05
void push(elem **ptr,voce *pv)
{
elem *nuovo,*temp;
nuovo =(elem *)malloc(sizeof(elem));

nuovo->pvoce=pv;
nuovo->next=NULL;

if(!(*ptr)){
*ptr=nuovo;
return;
}

for(temp=*ptr; temp->next;temp=temp->next);
temp->next=nuovo;
}

io l'ho fatta così.

71104
01-07-2005, 22:08
void push(elem **ptr,voce *pv)
{
elem *nuovo,*temp;
nuovo =(elem *)malloc(sizeof(elem));

nuovo->pvoce=pv;
nuovo->next=NULL;

if(!(*ptr)){ // <-- e qui??? :-)
*ptr=nuovo;
return;
}

for(temp=*ptr; temp->next;temp=temp->next);
temp->next=nuovo;
}

io l'ho fatta così..

Brazorv
01-07-2005, 22:14
se la lista è vuota devi mettere nuovo come primo elemento, altrimenti scorri la lista e lo metti come ultimo.

VICIUS
01-07-2005, 22:15
Se devi fare una coda probabilmente ti conviene creare una struttura "radice" che ha il puntatore sia del primo che dell'ultimo elemento. In questo modo l'inserimento diventa O(1) invece di O(N).

ciao ;)

Brazorv
01-07-2005, 22:28
Se devi fare una coda probabilmente ti conviene creare una struttura "radice" che ha il puntatore sia del primo che dell'ultimo elemento. In questo modo l'inserimento diventa O(1) invece di O(N).

ciao ;)

allora possiamo fare così

void push(elem **testa,elem **coda,voce *pv)
{
elem *nuovo,*temp;
nuovo =(elem *)malloc(sizeof(elem));

nuovo->ptvoce=pv;
nuovo->next=NULL;

if(!(*testa)){
*testa=nuovo;
*coda=nuovo;
return;
}

(*coda)->next=nuovo;
*coda=nuovo;
}

71104
01-07-2005, 22:37
allora possiamo fare così

void push(elem **testa,elem **coda,voce *pv)
{
elem *nuovo,*temp;
nuovo =(elem *)malloc(sizeof(elem));

nuovo->ptvoce=pv;
nuovo->next=NULL;

if(!(*testa)){ // l'hai rifatto di nuovo :D
*testa=nuovo;
*coda=nuovo; // dimeticavo: stavolta l'errore è doppio :D
return;
}

(*coda)->next=nuovo;
*coda=nuovo;
}

che succede se chiami push(NULL, NULL, NULL);? :D

Brazorv
01-07-2005, 22:41
che succede se chiami push(NULL, NULL, NULL);? :D
per i primi due NULL non succede niente, testa e coda NULL vuol dire lista vuota. per il terzo non l'ho provato, ma basta fare un controllo che per semplicità non avevo previsto.
Manca anche un altro controllo su un puntatore. :)

ghiotto86
02-07-2005, 08:31
Se devi fare una coda probabilmente ti conviene creare una struttura "radice" che ha il puntatore sia del primo che dell'ultimo elemento. In questo modo l'inserimento diventa O(1) invece di O(N).

ciao ;)

quoto.
se devi fare una coda è meglio gestirla con due puntatori.
ciauz

DanieleC88
02-07-2005, 08:54
allora possiamo fare così

void push(elem **testa,elem **coda,voce *pv)
[...cut...]
}
Eh... peccato che il prototipo della funzione non va modificato (non è un mio software [non è neanche per me], è un test e questo fa parte dell'esercizio).

Proverò con le vostre funzioni. Speriamo bene! :sperem:

71104
02-07-2005, 09:38
per i primi due NULL non succede niente, testa e coda NULL vuol dire lista vuota. per il terzo non l'ho provato, ma basta fare un controllo che per semplicità non avevo previsto. infatti il terzo puntatore per semplicità puoi anche non controllarlo (devi solo stare attento a non dereferenziare subito il contenuto dei nodi), ma se chiami push(NULL, NULL, NULL); va in crash a causa dei primi due, anzi del primo.

Brazorv
02-07-2005, 10:15
Guarda come ti ho detto prima era solo che non avevo tralasciato dei controlli

int push(elem **testa,elem **coda,voce *pv)
{
if(!testa || !coda || !pv)
return -1;

elem *nuovo;
nuovo =(elem *)malloc(sizeof(elem));
if(!nuovo)
return -1;

nuovo->pvoce=pv;
nuovo->next=NULL;

if(!(*testa)){
*testa=nuovo;
*coda=nuovo;
return 0;
}

(*coda)->next=nuovo;
*coda=nuovo;

return 0;
}


il problema non è nel controllo if(!(*testa)), che è giusto perchè controlla se la lista è vuota oppure no, era più su che non avevo messo il primo controllo.
Poi se metti NULL in pv non ti crasha la funzione, ma se poi fai riferimento all'elemento che hai lasciato NULL (per esempio così tmp->pvoce ) ti crasha perchè pvoce è NULL.

Fenomeno85
02-07-2005, 11:52
void push(elem **ptr,voce *pv)
{
elem *nuovo,*temp;
nuovo =(elem *)malloc(sizeof(elem));

nuovo->pvoce=pv;
nuovo->next=NULL;

if(!(*ptr)){
*ptr=nuovo;
return;
}

for(temp=*ptr; temp->next;temp=temp->next);
temp->next=nuovo;
}

io l'ho fatta così.

non è la soluzione ottimale dato che ogni volta ti tocca andare a scorrere una lista e, se questa molto vasta diventa un pò problematico. La soluzione migliore è quella con un parametro in + che ti identifica direttamente la coda oppure la cosa ancora + easy e + funzionale è inserimento in testa e poi se al massimo se vuoi per forza averla al contrario ti basta fare una reverse della lista :)

~§~ Sempre E Solo Lei ~§~

Brazorv
02-07-2005, 12:05
non è la soluzione ottimale dato che ogni volta ti tocca andare a scorrere una lista e, se questa molto vasta diventa un pò problematico. La soluzione migliore è quella con un parametro in + che ti identifica direttamente la coda oppure la cosa ancora + easy e + funzionale è inserimento in testa e poi se al massimo se vuoi per forza averla al contrario ti basta fare una reverse della lista :)


Che quella non sia la soluzione ottimale è già stato detto, e il problema era già stato risolto con un puntatore alla coda della lista.
Come fai il reverse della lista?

71104
02-07-2005, 12:06
La soluzione migliore è quella con un parametro in + che ti identifica direttamente la coda [...] si, però Daniele dice di non poter modificare i prototipi...

Fenomeno85
02-07-2005, 12:07
si, però Daniele dice di non poter modificare i prototipi...

ottimo allora via con inserimento in testa ... aggiunge un prototipo per il reverse della lista :D

~§~ Sempre E Solo Lei ~§~

Fenomeno85
02-07-2005, 12:08
che poi scusa ma i metodi push e pop li vedo meglio con l'inserimento in testa dato che alla fine di solito gli stack si gestiscono in modo LIFO

~§~ Sempre E Solo Lei ~§~

Brazorv
02-07-2005, 12:09
che poi scusa ma i metodi push e pop li vedo meglio con l'inserimento in testa dato che alla fine di solito gli stack si gestiscono in modo LIFO

~§~ Sempre E Solo Lei ~§~

ma lui non ha detto che vuole uno stack

Fenomeno85
02-07-2005, 12:10
ma lui non ha detto che vuole uno stack

ops ... cmq la soluzione del reverse che problemi ha?? :mbe: non cambi i prototipi che così è contento :D

~§~ Sempre E Solo Lei ~§~

Brazorv
02-07-2005, 12:12
non ho capito come vuoi fare la reverse.

Fenomeno85
02-07-2005, 12:15
non ho capito come vuoi fare la reverse.

il reverse si può fare in modo ricorsivo (se si sa che la lista è PICCOLA) oppure in modo iterativo ;)

~§~ Sempre E Solo Lei ~§~

Brazorv
02-07-2005, 12:25
ma così avresti comunque una complessità O(n). o no?

DanieleC88
02-07-2005, 12:49
Che macello, 'sta dicussione sta diventando troppo tecnica. :D
Aggiorno: con le varie soluzioni che mi avete dato (a parte quelle con i prototipi modificati, che non ho provato) sembra che l'aggiunta vada bene, ma quando accedo a dei campi di ptvoce all'interno del database ho un segmentation fault, mentre con il codice che vi avevo postato all'inizio il segmentation fault sparisce, ma la lista risulta composta da un solo elemento. Boh! :(

Fenomeno85
02-07-2005, 12:54
ma così avresti comunque una complessità O(n). o no?

si ma solo una volta quando te vuoi fare il reverse ... metre li ogni volta che chiami push

~§~ Sempre E Solo Lei ~§~

Brazorv
02-07-2005, 13:01
Che macello, 'sta dicussione sta diventando troppo tecnica. :D
Aggiorno: con le varie soluzioni che mi avete dato (a parte quelle con i prototipi modificati, che non ho provato) sembra che l'aggiunta vada bene, ma quando accedo a dei campi di ptvoce all'interno del database ho un segmentation fault, mentre con il codice che vi avevo postato all'inizio il segmentation fault sparisce, ma la lista risulta composta da un solo elemento. Boh! :(

Ci posti il codice in cui crei la lista aggiungi gli elementi e accedi a quei campi?

DanieleC88
12-07-2005, 16:46
Grazie delle risposte, alla fine sono riuscito a risolvere quel problema, ma ora ne ho un'altro molto strano: ho due variabili che vengono allocate l'una dopo l'altra, ma quando provo a realloc()arle, solo la prima malloc()ata viene ridimensionata senza problemi, l'altra causa un segmentation fault. Vi posto il codice:
int registraArchivio(FILE* uscita, elem* db)
{
char str[RECLEN];
int num = 0;
char * dest;
char * temp;

while (db)
{
if (vocetorec(str,db->ptvoce) != 0) return -1;

if (num == 0)
{
temp = malloc(RECLEN);
dest = malloc(RECLEN);
strcpy(dest, str);
}
else
{
realloc(temp, num*RECLEN);
strcpy(temp, dest);
realloc(dest, (num+1)*RECLEN);
sprintf(dest, "%s\n%s", str, temp);
}

num++;
if (!db->next) break;
db = db->next;
}
fprintf(uscita,dest);
free(dest);
free(temp);
return num;
}

DanieleC88
13-07-2005, 17:04
up :cry:

Fenomeno85
14-07-2005, 09:35
1) per correttezza va fatto il cast su MALLOC
2) realloc ritorna il puntatore del nuovo spazio

su su il caldo ti sta dando alla testa :D

~§~ Sempre E Solo Lei ~§~

DanieleC88
14-07-2005, 16:59
1) per correttezza va fatto il cast su MALLOC
2) realloc ritorna il puntatore del nuovo spazio

su su il caldo ti sta dando alla testa :D

~§~ Sempre E Solo Lei ~§~
1) ci avevo già provato, non cambia nulla;
2) ma modifica anche lo spazio del primo puntatore. :cry:

Vi posto il nuovo codice e test che ho fatto con gdb:
int registraArchivio(FILE* uscita, elem* db)
{
char str[RECLEN];
int num = 0;
char * dest = NULL;

fprintf(stderr,"-> registraArchivio();\n");
while (db)
{
/* Se vocetorec() fallisce, usciamo con un errore */
if (vocetorec(str,db->ptvoce) != 0) return -1;

fprintf(stderr,"\tnum = %d;\n", num);
fprintf(stderr,"\t- str = \"%s\";\n", str);
if (num == 0)
{
dest = malloc(RECLEN);
strcpy(dest, str);
}
else
{
char * temp = NULL;

fprintf(stderr,"\t- duplicating dest in temp memory;\n");
temp = strdup(dest);
fprintf(stderr,"\t- reallocating dest memory;\n");
realloc(dest, (num+1)*RECLEN);
fprintf(stderr,"\t- copying dest memory;\n");
sprintf(dest, "%s\n%s", str, dest /* temp */);
fprintf(stderr,"\t- freeing temp memory;\n");
free(temp);
}
fprintf(stderr,"\t- dest = \"%s\";\n", dest);

/* Incrementiamo il numero di voci scritte */
num++;
if (!db->next) break;
db = db->next;
}
fprintf(stderr,"\tsaving;\n");
fprintf(uscita,dest);
fprintf(stderr,"\tfreeing memory;\n");
free(dest);
fprintf(stderr,"<- registraArchivio();\n");
return num;
}
Prima di allocare "dest":
--
(gdb) print dest
$1 = 0x6 <Address 0x6 out of bounds>
--
Dopo aver impostato "dest" a NULL:
--
(gdb) print dest
$2 = 0x0
--
Dopo aver allocato "dest":
--
(gdb) print dest
$3 = 0x804b398 "¸Ùü·¸Ùü·ÿÿÿÿ"
--

Prima di allocare "temp":
--
(gdb) print temp
$4 = 0xffffffff <Address 0xffffffff out of bounds>
--
Dopo aver impostato "temp" a NULL:
--
(gdb) print temp
$5 = 0x0
--
Provando ad allocare "temp" attraverso strdup(): segmentation fault. :(

Fenomeno85
14-07-2005, 17:04
ehm realloc serve a reallocare ma se non ci sta dove è allocato quello di partenza PER FORZA cambia indirizzo e

~§~ Sempre E Solo Lei ~§~

DanieleC88
15-07-2005, 08:15
ehm realloc serve a reallocare ma se non ci sta dove è allocato quello di partenza PER FORZA cambia indirizzo e

~§~ Sempre E Solo Lei ~§~
Se la memoria che realloc() deve ridimensionare è nulla, la chiamata equivale a una malloc(). In ogni caso, avevo sempre errori con malloc(), quindi ho deciso di sostituire la strdup() dell'ultimo codice che vi ho postato con strdupa() - che usa alloca() - e ho risolto. Boh, strana cosa, comunque l'importante è che il codice ora funzioni. Grazie a tutti dell'aiuto!

Fenomeno85
15-07-2005, 08:29
Se la memoria che realloc() deve ridimensionare è nulla, la chiamata equivale a una malloc().


si ma io non vedo dove gestisci il tutto con realloc

~§~ Sempre E Solo Lei ~§~

DanieleC88
15-07-2005, 08:37
si ma io non vedo dove gestisci il tutto con realloc

~§~ Sempre E Solo Lei ~§~
realloc(dest, (num+1)*RECLEN);
Comunque, non importa, ora funziona. :)

Fenomeno85
15-07-2005, 08:39
realloc(dest, (num+1)*RECLEN);
Comunque, non importa, ora funziona. :)

ritorno della funzione :)

~§~ Sempre E Solo Lei ~§~

Fenomeno85
15-07-2005, 16:44
hai provato?

~§~ Sempre E Solo Lei ~§~

DanieleC88
15-07-2005, 16:53
hai provato?

~§~ Sempre E Solo Lei ~§~
Scusami, ho letto solo ora. Comunque mi pare di aver già provato ad usare "dest = realloc(dest, (num+1)*RECLEN);", ma senza risultati. In ogni caso, quel problema è superato. Ora invece sono alle prese con fgets() che non ne vuole sapere di leggere.

Fenomeno85
15-07-2005, 17:08
http://www.cplusplus.com/ref/cstdio/fgets.html

tutto corretto?

~§~ Sempre E Solo Lei ~§~

DanieleC88
16-07-2005, 10:59
Si, ora ho risolto anche il problema di lettura. E se ti dico qual'era l'errore... che rabbia ora che ci penso! Era proprio idiota come errore. Sullo stesso file dovevo prima leggere e poi anche scrivere, e io l'avevo aperto con «file = fopen("file.dat", "w+");»... e per forza che non lo leggeva! Veniva troncato ad ogni apertura... :cry:

Grazie mille a tutti e in particolare a Ronaldo (il "Fenomeno" 85 :Prrr: )! ;)

Fenomeno85
16-07-2005, 11:23
Si, ora ho risolto anche il problema di lettura. E se ti dico qual'era l'errore... che rabbia ora che ci penso! Era proprio idiota come errore. Sullo stesso file dovevo prima leggere e poi anche scrivere, e io l'avevo aperto con «file = fopen("file.dat", "w+");»... e per forza che non lo leggeva! Veniva troncato ad ogni apertura... :cry:

Grazie mille a tutti e in particolare a Ronaldo (il "Fenomeno" 85 :Prrr: )! ;)

:asd: la cosa che però mi sta ancora incuriosendo è perchè non funziona realloc usando appunto il ritorno della funzione realloc :muro:


~§~ Sempre E Solo Lei ~§~

DanieleC88
16-07-2005, 11:41
Infatti la cosa è molto strana. Boh! :(

Fenomeno85
16-07-2005, 11:47
Infatti la cosa è molto strana. Boh! :(

azzo adesso mi metto a allocare deallocare a manetta vediamo


~§~ Sempre E Solo Lei ~§~

DanieleC88
16-07-2005, 11:51
LOL :asd:
Spacca tutto! :p

Fenomeno85
16-07-2005, 12:01
qui funziona tutto :mbe:

ti posto il codice



/*

realloc a manetta

*/

#include <stdio.h>
#include <windows.h>

#define BASE 100

int main (void){
int *p, i;
p = (int*)malloc(BASE);
for (i = 2; i<1100; i++){
p = (int*)realloc((int*)p,BASE*i);
printf ("%d\n", p);
}
system ("PAUSE");
}



~§~ Sempre E Solo Lei ~§~

Fenomeno85
16-07-2005, 12:09
compila con questo deve per forza andare :muro:


int registraArchivio(FILE* uscita, elem* db)
{
char str[RECLEN];
int num = 0;
char * dest = NULL;

fprintf(stderr,"-> registraArchivio();\n");
while (db)
{
/* Se vocetorec() fallisce, usciamo con un errore */
if (vocetorec(str,db->ptvoce) != 0) return -1;

fprintf(stderr,"\tnum = %d;\n", num);
fprintf(stderr,"\t- str = \"%s\";\n", str);
if (num == 0)
{
dest = (char*)malloc(RECLEN);
strcpy(dest, str);
}
else
{
char * temp = NULL;

fprintf(stderr,"\t- duplicating dest in temp memory;\n");
temp = strdup(dest);
fprintf(stderr,"\t- reallocating dest memory;\n");
dest = (char*)realloc((char*)dest, (num+1)*RECLEN);
fprintf(stderr,"\t- copying dest memory;\n");
sprintf(dest, "%s\n%s", str, dest /* temp */);
fprintf(stderr,"\t- freeing temp memory;\n");
free(temp);
}
fprintf(stderr,"\t- dest = \"%s\";\n", dest);

/* Incrementiamo il numero di voci scritte */
num++;
if (!db->next) break;
db = db->next;
}
fprintf(stderr,"\tsaving;\n");
fprintf(uscita,dest);
fprintf(stderr,"\tfreeing memory;\n");
free(dest);
fprintf(stderr,"<- registraArchivio();\n");
return num;
}


~§~ Sempre E Solo Lei ~§~

Fenomeno85
16-07-2005, 12:11
sarò anche un pò pirla ma che te ne frega usare strdup ?? e usare temp?? usa direttamente dest no?

~§~ Sempre E Solo Lei ~§~

DanieleC88
16-07-2005, 12:16
Niente, non va. Anche se il tuo codice (compreso quello di prima) dovrebbe funzionare. Non so, la cosa è strana.

DanieleC88
16-07-2005, 12:19
sarò anche un pò pirla ma che te ne frega usare strdup ?? e usare temp?? usa direttamente dest no?

~§~ Sempre E Solo Lei ~§~
Ci avevo provato, ma al posto di aggiungere nuove voci a dest, copiava tutte voci uguali (#num volte).

Fenomeno85
16-07-2005, 12:27
allora il codice è corretto osti lo compilo, lo eseguo e non da nessun errore controlla db


#include <stdio.h>
#include <windows.h>

#define RECLEN 10

int main (){
char str[] = "ciao";
int num = 0;
char * dest = NULL;
fprintf(stderr,"\tnum = %d;\n", num);
fprintf(stderr,"\t- str = \"%s\";\n", str);
for (int i = 0;i<3;i++){
if (num == 0)
{
dest = (char*)malloc(RECLEN);
strcpy(dest, str);
}
else
{
fprintf(stderr,"\t- duplicating dest in temp memory;\n");
fprintf(stderr,"\t- reallocating dest memory;\n");
dest = (char*)realloc((char*)dest, (num+1)*RECLEN);
fprintf(stderr,"\t- copying dest memory;\n");
sprintf(dest, "%s\n%s", str, dest);
fprintf(stderr,"\t- freeing temp memory;\n");
}
fprintf(stderr,"\t- dest = \"%s\";\n", dest);
}
system ("PAUSE");
}


~§~ Sempre E Solo Lei ~§~

DanieleC88
16-07-2005, 12:37
Boh, non so che dirti. Ma ora quel problema è storia. :)