PDA

View Full Version : [C] Lista di Lista


pepperamy
15-12-2017, 15:22
Salve a tutti ragazzi, ho iniziato da qualche mese a studiare il linguaggio C ed è anche il mio primo linguaggio di programmazione. Ho qualche problema con le liste di liste. Sto cercando di fare un programma (in questo momento fa tutto l'inserimento in lista e in sottolista automaticamente con dei cicli for) che mi permette di inserire degli elementi in una lista e in una sottolista di un elemento scelto.

Il codice che ho scritto è il seguente e quello che dovrebbe fare è: inserire gli interi da 1 a 9 in una lista principale con inserimento in testa, e questo lo fa, poi dovrebbe inserire i caratteri da "a" a "k" nella sottolista dell'intero 5, e anche questo sembra che lo faccia, e lo fa attraverso la funzione trova che mi cerca l'elemento 5 e mi restituisce il puntatore al nodo. Poi attraverso la funzione inserimento_sottolista alla quale passo il puntatore restituito dalla funzione trova e i caratteri che voglio inserire il secondo ciclo for mi fa l'inserimento nella sottolista . Ho messo dei printf qua a la per cercare di capire dove fosse il problema, ma non sono ancora riuscito a trovarlo.
Il problema che mi viene dato è che quando faccio la stampa degli elementi, la stampa della sottolista è sbagliata, perchè in corrispondenza dell'elemento 5 ci dovrebbe essere la sottolista con i caratteri invece c'è NULL.


ecco il codice

#include <stdio.h>
#include <stdlib.h>

/***** S T R U T T U R E ******/
struct sotto_nodo
{
char carattere;
struct sotto_nodo *nextPtr1;
};

struct nodo
{
int intero;
struct nodo *nextPtr; //puntatore al nodo successivo
struct sotto_nodo *sottonodoPtr; //puntatore al tipo struct sotto_nodo di nome sottonodoPtr

};

/****** T Y P E D E F ******/

typedef struct sotto_nodo SottoNodo;
typedef struct nodo Nodo;

typedef SottoNodo *SottoNodoPtr;
typedef Nodo *NodoPtr;

/****** P R O T O T I P I D I F U N Z IO N E ******/

void menu();
NodoPtr crea_lista(int elemento1);
void inserisci_lista (NodoPtr *head, int elementi);
SottoNodoPtr trova (NodoPtr head, int elemento);
void inserisci_sottolista (SottoNodoPtr *head1, char caratteri);
void stampa(NodoPtr testalistaPtr);


/****** M A I N ******/

int main (void)
{
NodoPtr testaPtr = NULL;
SottoNodoPtr testaPtr1 = NULL;


menu();
int scelta;
do {

printf("Fai una scelta: ");
fflush(stdin);
scanf("%d", &scelta);
switch (scelta)
{
case 1:
{
int i;
char j;
int elem1 = 0 ;

testaPtr = crea_lista(elem1);
for (i = 1; i < 10; i++)
{
inserisci_lista(&testaPtr, i);
printf("inserito %d in lista principale\n", testaPtr->intero);
}

testaPtr1 = trova(testaPtr, 5);
printf("\ntrovato l'elemento cercato\n\n");

for (j = 'a' ; j < 'l'; j++)
{

inserisci_sottolista(&testaPtr1, j);
printf("inserito %c in lista secondaria\n", testaPtr1->carattere);
}
}
break;

case 2:
stampa(testaPtr);

break;
}
}
while (scelta != 3);
}


/****** I M P L E M E N T A Z I O N E F U N Z I O N I ******/


void menu()
{
printf("1. Inserire elementi nella lista principale e nella sottolista\n");
printf("2. Stampare elementi\n");
printf("3. Termina programma\n");
};

NodoPtr crea_lista (int elemento1)
{
NodoPtr headPtr = malloc(sizeof(Nodo));

headPtr->intero = elemento1;
headPtr->nextPtr = NULL;
headPtr->sottonodoPtr = NULL;

return headPtr;
};

void inserisci_lista (NodoPtr *head, int elementi)
{
NodoPtr newPtr = malloc(sizeof(Nodo));
newPtr->intero=elementi;
newPtr->nextPtr = *head;
*head = newPtr;
};

SottoNodoPtr trova (NodoPtr head, int elemento)
{
while (head->intero != elemento && head != NULL)
{
head = head->nextPtr;
}
if (head->intero == elemento)
return head->sottonodoPtr;
else
return NULL;
};

void inserisci_sottolista (SottoNodoPtr *head1, char caratteri)
{
SottoNodoPtr newPtr = malloc(sizeof(SottoNodo));
newPtr->carattere = caratteri;
newPtr->nextPtr1 = *head1;
*head1 = newPtr;
};

void stampa(NodoPtr testalista)
{
printf("head -> ");
NodoPtr copia_testalista = testalista;
while (testalista != NULL)
{
printf("%d -> ", testalista->intero);
testalista = testalista->nextPtr;
}
printf("NULL\n");

SottoNodoPtr SubPtr = copia_testalista->sottonodoPtr;

while (copia_testalista != NULL)
{
printf("headsub -> (%d) -> ", copia_testalista->intero);

while (SubPtr != NULL)
{
printf("%c -> ", SubPtr->carattere);
SubPtr = SubPtr->nextPtr1;
}
printf("NULL\n");
copia_testalista = copia_testalista->nextPtr;
}
};

pepperamy
18-12-2017, 10:29
up

pabloski
18-12-2017, 16:16
Ci sono un paio di errorucci ma importanti.

Innanzitutto hai fatto bene in crea_lista ha porre headPtr->sottonodoPtr = NULL. Però perchè non hai fatto lo stesso in inserisci_lista, cioè newPtr->sottonodoPtr = NULL.

Il puntatore alla sottolista per tutti gli elementi della lista principale diversi dal primo è indefinito, cioè contiene valori a casaccio. Questo ti crea problemi in inserisci_sottolista quando fai newPtr->nextPtr1 = *head1, in quanto il primo elemento punterà al valore a casaccio. E ovviamente andrà in segmentation fault il programma. Il perchè adesso non vada in fault è dovuto al fatto che tutti gli elementi della lista principale hanno fortuitamente sottonodoPtr uguale a 0, cioè NULL.

Inoltre trova non ha senso così com'è fatta. In condizioni normali ritornerebbe sempre NULL, altrimenti il valore a casaccio contenuto in sottonodoPtr.

Ma il problema serio è il fatto che in inserisci_sottolista non fai nulla per aggiornare il valore di sottonodoPtr dell'elemento della lista principale relativo alla sottolista.

Cioè il sottonodoPtr dell'elemento 5 conterrà sempre NULL ( il compilatore sta facendo magheggi e settando implicitamente a NULL, altri compilatori ti lasciano il valore che trovano in memoria e le cose possono sfuggire di mano ).

Per cui quando inserisci un nuovo valore sotto l'elemento 5, il relativo sottonodoPtr dovrà puntare al sottonodo che rappresenta questo nuovo valore.

Pertanto trova deve restituirti il puntatore all'elemento 5 della lista, che poi dovrai passare a inserisci_sottolista che lo userà per individuare il sottonodoPtr da aggiornare.

Infine c'è un errore pure in stampa, dove assegni a SubPtr il valore della testa della sottolista dell'elemento di testa della lista. Poi però scorri tutti gli elementi della vista, ma non pone SubPtr al valore della testa della sottolista per OGNUNO degli elementi della vista.

In codice sarebbe

void inserisci_sottolista (SottoNodoPtr *head1, char caratteri, NodoPtr lPtr)
{
SottoNodoPtr newPtr = malloc(sizeof(SottoNodo));
newPtr->carattere = caratteri;
newPtr->nextPtr1 = *head1;
*head1 = newPtr;
lPtr->sottonodoPtr = newPtr; // aggiornamento sottonodoPtr per l'elemento 5
};

nel main


testaPtr2 = trova(testaPtr, 5); // testaPtr2 è di tipo NodoPtr
....
inserisci_sottolista(&testaPtr1, j, testaPtr2);



void inserisci_lista (NodoPtr *head, int elementi)
{
NodoPtr newPtr = malloc(sizeof(Nodo));
newPtr->intero=elementi;
newPtr->nextPtr = *head;
newPtr->sottonodoPtr = NULL; // non puoi lasciarlo al caso o alla bontà del compilatore
*head = newPtr;
};



NodoPtr trova (NodoPtr head, int elemento)
{
NodoPtr p = head;
while (p->intero != elemento && p != NULL)
{
p = p->nextPtr;
}
if (p->intero == elemento)
return p; // ritorna il puntatore all'elemento della lista non al relativo sottonodoPtr che è ovviamente NULL a questo punto
else
return NULL;
};



SottoNodoPtr SubPtr;

while (copia_testalista != NULL)
{
printf("headsub -> (%d) -> ", copia_testalista->intero);

SubPtr = copia_testalista->sottonodoPtr; // questo qui deve puntatore alla sottolista dello specifico elemento della lista, invece prima puntava sempre a quella della testa della lista