PDA

View Full Version : Array di struct


k_mishima
06-06-2007, 15:36
Ciao, devo fare questo esercizio, ma il programma mi crasha e non capisco dov'è l'errore, per ora sono alla parte statica.

Simulare i C la gestione di 1 pila (stack) tramite array (array di struct) statico
e dinamico [che differenza c'è?]

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_SIZE 10
struct pila
{
char nome[30];
char cognome[30];
int matricola;
struct pila *p;
} *head;



void InserisceTesta(struct pila elenco[], short *n);
main()
{
struct pila elenco[MAX_SIZE];
short what,n_persone=0;

head=NULL;
while (1)
{
puts("\nScegli l'operazione:");
puts("[1] Inserisci un elemento in testa");
puts("[2] Esci");
printf("Inserisci Scelta: ");
scanf("%hd", &what);

switch(what)
{

case 1:
InserisceTesta(elenco,&n_persone);
break;
case 2:
exit(0);
break;

default:
puts("\nScelta sbagliata! Ripeti!\n\n");
}
}
}

void InserisceTesta(struct pila elenco[], short *n)
{

if (*n==MAX_SIZE)
puts("Spazio finito");
else
{
puts("Scrivi 1 nome");
gets(elenco->nome);
puts("Scrivi 1 cognome");
gets(elenco->cognome);
puts("Digita la matricola");
scanf("%d", elenco->matricola);
head=head->p;
head->p=NULL;
*n+=1;
}
}


Mi fà leggere il cognome (non il nome), la matricola e poi crasha

Grazie 1000 per l'aiuto

andbin
06-06-2007, 21:01
Ciao, devo fare questo esercizio, ma il programma mi crasha e non capisco dov'è l'errore, per ora sono alla parte statica.

head=NULL;

....
head=head->p;
head->p=NULL;La prima volta (inserimento del primo elemento) head vale NULL, quindi non puoi fare head->p. Inoltre 'p' cosa conterrebbe? Non si sa ...

La questione è tutta lì, c'è da fare un caso specifico per il primo inserimento.

Simulare i C la gestione di 1 pila (stack) tramite array (array di struct) statico
e dinamico [che differenza c'è?]Una pila stack si può realizzare appunto in due modi:
- Tramite un array e in questo caso la lista di elementi non serve che sia "linkata" (cioè non c'è bisogno di un puntatore all'elemento seguente). Ci si basa solo su un indice che indica il 'top'.
- Tramite una lista linkata e in questo caso è necessario che ogni elemento abbia un puntatore al seguente. In genere in questi casi ogni elemento viene allocato in modo dinamico con malloc ecc...

turibbio
06-06-2007, 21:36
Vorrei inoltre farti notare che una pila è una struttura dati di tipo LIFO (last in- first out), il che significa che gli elementi vengono inseriti sempre in testa. Come hai implementato il codice non penso che l'elemento venga sempre messo in testa. Anzi mi pare che venga sempre aggiunto dopo, e non è il modo corretto per implementarlo!
Inoltre ti do un consiglio: inizializza la struct head nel main, e non in modo globale, perché poi la devi passare alla function di inserimento. Ma adesso cmq riguardando il codice mi sono accorto che c'è un errore di fondo. Tu stai forzando nella funzione di inserimento la creazione di una lista e non un array di struct. Quindi ancora una volta head = head -> p_next deve puntare ad un elemento di un array e non come hai fatto tu. Datti una riguardata al progetto e vedi bene quello che richiede, perché implementato così, a parte che da errore, ma non è neanche ciò che è stato richiesto!
La differenza tra statico e dinamico e' la seguente:
-statica: array di struct dichiarato in modo statico: array[MIOSIZE]
-dinamica: uso di un array dinamico, ovvero si modificano runtime il numero di componenti dell'array con l'uso dell'allocazione dinamica.

k_mishima
07-06-2007, 12:02
Innanzitutto grazie per le risposte :)

Una pila stack si può realizzare appunto in due modi:
- Tramite un array e in questo caso la lista di elementi non serve che sia "linkata" (cioè non c'è bisogno di un puntatore all'elemento seguente). Ci si basa solo su un indice che indica il 'top'.


Mi sa che hai ragione, l'esercizio chiede proprio questo, ora modifico il codice e lo posto.


- Tramite una lista linkata e in questo caso è necessario che ogni elemento abbia un puntatore al seguente. In genere in questi casi ogni elemento viene allocato in modo dinamico con malloc ecc...

Non mi richiede questo, ma cmq ha senso fare l'allocazione statica non ha senso vero? Perchè ho letto che tra i prossimi dovro' fare una pila linkata soltanto dinamica.

La differenza tra statico e dinamico e' la seguente:
-statica: array di struct dichiarato in modo statico: array[MIOSIZE]
-dinamica: uso di un array dinamico, ovvero si modificano runtime il numero di componenti dell'array con l'uso dell'allocazione dinamica.

Tnx :D

k_mishima
07-06-2007, 14:00
Ho modificato cosi', mi da lo stesso problema di prima: non mi fa leggere il nome, ma solo cognome e matricola (tra l'altro è una lettura fittizia perchè nelle stampe mi da caratteri a casaccio).

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_SIZE 10
struct pila
{
char nome[30];
char cognome[30];
int matricola;
};



void InserisceTesta(struct pila elenco[], short *n);
void Elimina_pila(struct pila elenco[],short *n);
void CancellaTesta(struct pila elenco[],short *n);
void StampaTesta(struct pila elenco[], short *n);
void StampaPila(struct pila elenco[], short *n);
main()
{
struct pila elenco[MAX_SIZE];
short what,n_persone=0;

while (1)
{
puts("\nScegli l'operazione:");
puts("[1] Inserisci un elemento in testa");
puts("[2] Cancella Pila");
puts("[3] Stampa numero elementi nella pila");
puts("[4] Elimina elemento in testa");
puts("[5] Stampa testa");
puts("[6] Stampa pila");
puts("[7] Esci");
printf("Inserisci Scelta: ");
scanf("%hd", &what);

switch(what)
{

case 1:
InserisceTesta(elenco,&n_persone);
break;
case 2:
Elimina_pila(elenco,&n_persone);
break;
case 3:
if (n_persone!=1)
printf("\nCi sono %d elementi nella pila\n",n_persone);
else
puts("\nC'è 1 elemento nella pila");
break;
case 4:
CancellaTesta(elenco,&n_persone);
break;
case 5: StampaTesta(elenco,&n_persone);
break;
case 6: StampaPila(elenco,&n_persone);
break;
case 7:
exit(0);
break;

default:
puts("\nScelta sbagliata! Ripeti!\n\n");
}
}
}

void InserisceTesta(struct pila elenco[], short *n)
{
short i=(*n)-1;
if (*n==MAX_SIZE)
puts("Spazio finito");
else
{
puts("Scrivi 1 nome");
gets(elenco[i].nome);
puts("Scrivi 1 cognome");
gets(elenco[i].cognome);
puts("Digita la matricola");
scanf("%d", elenco[i].matricola);
*n+=1;
}
}

void Elimina_pila(struct pila elenco[],short *n)
{
short i;
if (n==NULL)
puts("La pila non contiene nodi");
else
{
for (i=0;i<(*n);i++)
{
elenco[i].nome==NULL;
elenco[i].cognome==NULL;
elenco[i].matricola=0;
}
}
*n=0;
}

void CancellaTesta(struct pila elenco[],short *n)
{
short i=(*n)-1;
if (n==NULL)
puts("La pila non contiene nodi");
else
{
elenco[i].nome==NULL;
elenco[i].cognome==NULL;
elenco[i].matricola=0;
}
*n=i;
}

void StampaTesta(struct pila elenco[], short *n)
{
short i=(*n)-1;
if (i>=0)
printf("\nStudente %s %s, matr. %d",elenco[i].nome, elenco[i].cognome, elenco[i].matricola);
else
puts("\nNon ci sono persone nella pila");
}

void StampaPila(struct pila elenco[], short *n)
{
short i;
if (n=NULL)
puts("La pila non conviene nodi");
else
{
for (i=0;i<(*n);i++)
printf("Studente %s %s, matr. %d",elenco[i].nome, elenco[i].cognome, elenco[i].matricola);
}
}


C'è qualcosa che non va nella function della lettura credo, ma cosa?

andbin
07-06-2007, 14:05
Se mi permetti, ti consiglio di gestire la pila in modo un pochino diverso:
struct elem_pila
{
char nome[30];
char cognome[30];
int matricola;
};

struct pila
{
struct elem_pila elementi[MAX_SIZE];
int size;
};

Eviti di dover passare alle varie funzioni l'array e l'altro parametro e rendi il codice più semplice e pulito. ;)

k_mishima
07-06-2007, 15:31
Ho fatto come mi hai detto, pero' ho sbagliato qualcosa, ora crasha addirittura il prog alla prima lettura

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_SIZE 10
struct elem_pila
{
char nome[30];
char cognome[30];
int matricola;
};

struct pila
{
struct elem_pila elenco[MAX_SIZE];
int n;
}stack;


void InserisceTesta();
void Elimina_pila();
void Lunghezza();
void CancellaTesta();
void StampaTesta();
void StampaPila();
main()
{

short what;

while (1)
{
puts("\nScegli l'operazione:");
puts("[1] Inserisci un elemento in testa");
puts("[2] Cancella Pila");
puts("[3] Stampa numero elementi nella pila");
puts("[4] Elimina elemento in testa");
puts("[5] Stampa testa");
puts("[6] Stampa pila");
puts("[7] Esci");
printf("Inserisci Scelta: ");
scanf("%hd", &what);

switch(what)
{

case 1:
InserisceTesta();
break;
case 2:
Elimina_pila();
break;
case 3:
Lunghezza();
break;
case 4:
CancellaTesta();
break;
case 5: StampaTesta();
break;
case 6: StampaPila();
break;
case 7:
exit(0);
break;

default:
puts("\nScelta sbagliata! Ripeti!\n\n");
}
}
}

void InserisceTesta()
{
short i=(stack.n)-1;
if (stack.n==MAX_SIZE)
puts("Spazio finito");
else
{
puts("Scrivi 1 nome");
gets(stack.elenco[i].nome);
puts("Scrivi 1 cognome");
gets(stack.elenco[i].cognome);
puts("Digita la matricola");
scanf("%d", stack.elenco[i].matricola);
stack.n+=1;
}
}

void Elimina_pila()
{
short i;
if (&stack.n==NULL)
puts("\nLa pila non contiene nodi");
else
{
for (i=0;i<(stack.n);i++)
{
stack.elenco[i].nome==NULL;
stack.elenco[i].cognome==NULL;
stack.elenco[i].matricola=0;
}
}
stack.n=0;
}

void CancellaTesta()
{
short i=(stack.n)-1;
if (&stack.n==NULL)
puts("\nLa pila non contiene nodi");
else
{
stack.elenco[i].nome==NULL;
stack.elenco[i].cognome==NULL;
stack.elenco[i].matricola=0;
}
stack.n=i;
}

void StampaTesta()
{
short i=(stack.n)-1;
if (i>=0)
printf("\nStudente %s %s, matr. %d",stack.elenco[i].nome, stack.elenco[i].cognome, stack.elenco[i].matricola);
else
puts("\nNon ci sono persone nella pila");
}

void Lunghezza()
{
if (stack.n!=1)
printf("\nCi sono %d elementi nella pila\n",stack.n);
else
puts("\nC'è 1 elemento nella pila");
}

void StampaPila()
{
short i;
if (&stack.n==NULL)
puts("La pila non conviene nodi");
else
printf("Studente %s %s, matr. %d\n",stack.elenco[i].nome, stack.elenco[i].cognome, stack.elenco[i].matricola);
{
for (i=0;i<(stack.n);i++)
printf("Studente %s %s, matr. %d\n",stack.elenco[i].nome, stack.elenco[i].cognome, stack.elenco[i].matricola);
}
}


Potreste provarlo e vedere cosa non va'? Ci sto impazzendo.

andbin
07-06-2007, 15:42
Ho fatto come mi hai detto, pero' ho sbagliato qualcosa, ora crasha addirittura il prog alla prima letturaAvendo definito 'stack' con la dichiarazione della struttura, stack è una variabile globale, pertanto inizializzata a zero, fin qui ok.

In InserisceTesta fai short i=(stack.n)-1;, all'inizio quindi i è -1 ...... vai un po' fuori dall'array!

Poi perché in StampaPila fai if (&stack.n==NULL)?? L'indirizzo di stack.n non può essere NULL!

Credo che debba rivedere bene un po' tutta la gestione della pila.

Stev-O
07-06-2007, 16:29
e metti un controllino sul what (tipo un isnum)

lo switch non accetta altro che interi

andbin
07-06-2007, 16:57
lo switch non accetta altro che interiSecondo lo standard ANSI C, l'espressione nello switch può essere di tipo char, short, int o long

k_mishima
07-06-2007, 17:05
In InserisceTesta fai short i=(stack.n)-1;, all'inizio quindi i è -1 ...... vai un po' fuori dall'array!

ok ho tolto il meno 1, non serviva.


Poi perché in StampaPila fai if (&stack.n==NULL)?? L'indirizzo di stack.n non può essere NULL!

io veramente vorrei fare stack.n==NULL ma mi da errore, mi dice comperazione tra puntatore e un intero

Credo che debba rivedere bene un po' tutta la gestione della pila.

Il codice l'ho guardato molte volte ma ancora non ho capito perchè non funzioni la function sull'inserimento della testa, crasha pure togliendo il meno 1.
Sono troppo poco esperto, mi serve il vostro aiuto :(

e metti un controllino sul what (tipo un isnum)

lo switch non accetta altro che interi

Non ho capito cosa non và nello swich, cmq mi sembra l'ultimo dei miei problemi al momento lol

andbin
07-06-2007, 17:11
io veramente vorrei fare stack.n==NULL ma mi da errore, mi dice comperazione tra puntatore e un intero'n' è un intero non un puntatore, no? È vero che NULL tecnicamente vale 0, però se si sta compilando in C e non C++ in genere il NULL è definito come ((void *)0), pertanto un puntatore.

Quindi puoi fare stack.n == 0

k_mishima
07-06-2007, 17:24
'n' è un intero non un puntatore, no? È vero che NULL tecnicamente vale 0, però se si sta compilando in C e non C++ in genere il NULL è definito come ((void *)0), pertanto un puntatore.

Quindi puoi fare stack.n == 0

ok, messo uguale 0 e non ho problemi.

Per il crash non sai dirmi che ho sbagliato?

k_mishima
08-06-2007, 11:31
up

turibbio
08-06-2007, 22:45
struct elem_pila
{
char nome[30];
char cognome[30];
int matricola;
};

struct pila
{
struct elem_pila elementi[MAX_SIZE];
int size;
};

K_mishima, questa è una ottima soluzione, ma non quella richiesta dall'esercizio.
Dovresti implementare la stack utilizzando qualcosa di questo tipo:

//Singolo elemento
struct info{
char nome[10];
char cognome[10];
};


poi crei nel main un array di struct :

info pila[MAXSIZE];


Il controllo degli elementi massimi li fai con una variabile int cnt, che utilizzi incrementandola (push) e decrementadola (pop);

Puoi magari utilizzare cnt per mantenere la posizione dove inserire il prossimo elemento, posizionando così gli elementi nell'array in maniera sequenziale.

k_mishima
09-06-2007, 03:15
io cosi' avevo fatto, poi ho cambiato su consiglio di andbin per fare il codice piu' elengante e evitare di passare ogni volta le stesse cose alle function, cmq guarda, mi è indifferente, vorrei piuttosto sapere perchè mi crasha sto cavolo di prog :(

turibbio
09-06-2007, 12:24
Ho provato il tuo codice e ti posso dire che ci sono un casino di errori e di incongruenze. Innanzitutto riprendendo il codice originale una cosa del tipo:


stack.elenco[i].nome==NULL;
stack.elenco[i].cognome==NULL;
stack.elenco[i].matricola=0;

non va assolutamente bene. Non stai usando puntatori, stai usando array, quindi il NULL non va prorio bene. E poi hai fatto il più comune errore di programmazione in C: hai confuso '==' con '='. BE careful!
Se il tuo obiettivo è di inizializzare l'elemento a zero lo puoi fare in questo modo:

stack.elenco[i].nome[0] = '\0';
stack.elenco[i].cognome[0] = '\0';
stack.elenco[i].matricola=0;

così facendo inizializzi la prima componente dell'array nome[0] a '\0', evitando di accedere alle altre componenti.

Nella funzione di inserimento ci sono due errori importanti:

void InserisceTesta()
{
short i=(stack.n)-1;
if (stack.n==MAX_SIZE)
puts("Spazio finito");
else
{
puts("Scrivi 1 nome");
gets(stack.elenco[i].nome);
puts("Scrivi 1 cognome");
gets(stack.elenco[i].cognome);
puts("Digita la matricola");
scanf("%d", stack.elenco[i].matricola);
stack.n+=1;
}
}


Innanzitutto non ti usciva il nome perché devi utilizzare una chiamata del tipo
fflush(stdin); per pulire lo standard di input a cui è associato il programma, altrimenti la gets ti prende valori di tabulazione come il newline che non dovrebbe ricevere.

puts("Scrivi 1 nome");
fflush(stdin);
gets(stack.elenco[i].nome);
puts("Scrivi 1 cognome");
fflush(stdin);
gets(stack.elenco[i].cognome);
puts("Digita la matricola");
scanf("%d", stack.elenco[i].matricola);
stack.n+=1;

Il secondo errore è connesso alla scanf. Se vedi la documentazione sulla scanf noterai che il parametro e' un indirizzo -> &mia_variabile.

scanf("%d", stack.elenco[i].matricola);

Una istruzione di questo tipo invece non riceve l'indirizzo della variabile dove memorizzare il valore, pertanto va in crash perchè si verifica una unhandled exception (tenta di accedere a qualcosa a cui non può accedere). Stai attento perchè è un errore molto comune!

pertanto lo risolvi in questo modo:

scanf("%d", &(stack.elenco[i].matricola));

utilizzando cioè l'operatore di riferimento.

k_mishima
09-06-2007, 12:55
grazie 1000, pian piano stavo scoprendo tutti questi errori, mi mancava solo quello sulla scanf (&) che mi faceva ancora crashare :D

ammetto di essermela dimenticata :(
purtroppo il programma non mi dava errore :rolleyes:

oggi lo faccio dinamicamente allora, se ho problemi posto :D

turibbio
09-06-2007, 14:19
Si infatti non ti segnala né errori né warnign in base al fatto che i compilatori non sono previsti per segnalarlo. In realtà è lo standard del C stesso che non dice nulla al riguardo. Pertanto è compito del programmatore fare attenzione a passare un indirizzo.
Quando fai la versione dinamica abbi presente che l'array deve essere di tipo dinamico e pertanto devi aumentare o diminuire il suo size a seconda dell'inserimento o dell'eliminazione.
:bsod:

k_mishima
09-06-2007, 14:23
ecco, sono già nei guai. Voglio allocare dinamicamente la struct, ma come si fa?

Per ora ho scritto
struct elem_pila
{
char nome[30];
char cognome[30];
int matricola;
}*elenco;


elenco=(struct elem_pila*)calloc((1,sizeof(struct elem_pila));

e mi dice syntax error before ';' token

turibbio
09-06-2007, 19:14
capperini, K_mishima impara ad interpretare gli errori. Sintax error: errore di sintassi, hai scritto qualcosa che non va (suggerimento: conta le parentesi nell'allocazione!).:muro:

k_mishima
10-06-2007, 12:50
hai perfettamente ragione, questo errore era molto stupido scusa :doh:

finalmente è finito questo esercizio

grazie mille a tutti :D