Pagina 1 di 1

[C]Problema memorizzazione liste

Inviato: lun 28 lug 2014, 20:57
da Dennis
Buonasera a tutti,
ho un problema col codice che vi posto
main.c

Codice: Seleziona tutto

#include "header.h"
#include "strutture.h"

/* Funzione per deallocare memoria. Gli viene passata una struttura di liste
e una variabile intera che indica quante liste ci sono. */
void dealloca_memoria(struct list* list, int numListe){
	int i; /* Indice per scorrere le liste */
	
	for(i = 1; i <= numListe; i++){    /* Ciclo che scorre tutte le liste fino a quel momento create */
		free(list->next);    /* per ogni lista libero lo spazio che avevo allocato */
		list = list -> next; /* passo alla lista successiva */
	}

	printf("Memoria liberata da %d liste\n", numListe);
}

int main (void){
	int iGuardia; /* Contiene un valore che mi dice se l'inserimento e' valido o no. */
	int iContList=0;/* Contatore di liste presenti in memoria. */
	int iElementoDellaLista; /* Contiene l'elemento, inserito dall'utente, da inserire nella lista. */
	int k; /* Contiene il valore di K come richiesto dalla specifica. */
	char aczNameOfList[100]; /*Contiene il nome di una lista inserito dall'utente al punto b. */
	char cScelta; /* Contiene la scelta effettuata dall'utente. */

	struct list* first = init_list();
	struct list* last_list = first;
	
	while(1){
	cScelta=stampaMenu();
		switch (cScelta){
			case 'a':
				printf("Inserisci gli elementi della lista.\n 0 per terminare l'inserimento\n\n");
				iContList++;
	
				last_list = insert_list(last_list, iContList);

				printf("\nElemento: ");
                                iGuardia = scanf("%d", &iElementoDellaLista);
				
				if(iGuardia!=1){ /* Se è vero vuol dire che ho inserito un input errato, dunque richiedo l'inserimento. */
					do{
						printf("Input errato!!\nElemento: ");
						while (getchar() != '\n');
						iGuardia = scanf("%d", &iElementoDellaLista);
					}while(iGuardia != 1);
				}

				while(iElementoDellaLista!=0){ /* Chiedo l'inserimento di elementi fino a quando non inserisco lo 0.*/
					insert_node(last_list, iElementoDellaLista); /* Ogni elemento che inserisco lo salvo nella lista. */
					printf("Elemento: ");
					iGuardia = scanf("%d", &iElementoDellaLista);
					
					if(iGuardia!=1){
						do{
							printf("Input errato!!\nElemento: ");
							while (getchar() != '\n');
							iGuardia = scanf("%d", &iElementoDellaLista);
						}while(iGuardia!=1);
					}
				}
				break;
			case 'v':
				if(iContList==0){
					printf("Non ci sono liste da stampare\n");
					break;
				}else{
					print_allList(first, iContList);
				}
				break;
			case 'b':
				printf("Inserisci il nome di una lista (nel formato List-i) a cui applicare lo split: ");
				scanf("%s", aczNameOfList);

				iContList = listPresentOrNotPresent(first, aczNameOfList, iContList);
				
				print_allList(first, iContList);
				break;
			case 'c':
				do{
					printf("Inserisci un valore intero positivo(maggiore di 1): ");
					scanf("%d", &k);
				}while(k<=1);
				iContList = split_k_diTutteLeListe(first, k, iContList);
				print_allList(first, iContList);
				break;
			case 'd':
				printf("\nEsecuzione terminata\n\n");
				dealloca_memoria(first, iContList); /* Chiamata alla funzione per liberare la memoria dalle liste create */
				
				system("make clean"); /* Prima di uscire faccio la pulizia della directory dei file di esecuzione temporanei */
				exit(EXIT_SUCCESS); /* provoca la conclusione corretta del programma */
		}
	}
}
header.h

Codice: Seleziona tutto

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

char stampaMenu(void); /* Dichiarazione di stampaMenu che restituisce un char (la scelta) e non prende
		          valori, per questo è stato messo esplicitamente void nelle parentesi, 
		          come richiesto dallo standard ANSI. */
struct list *init_list (); /* Mi fa l'iniziliazzazione della lista. */
struct list* insert_list(struct list*, int contList); /* Mi permette di inserire nuove liste. */
menu.c

Codice: Seleziona tutto

#include "header.h"
/*
* Funzione che stampa il menu di selezione.
* L'utente inserisce da tastiera la scelta, sulla quale viene fatto
* il controllo che sia una scelta corretta, altrimenti si richiede
* di rieffettuare la scelta.
*/

char stampaMenu(void){

	char cScelta; // Variabile che contiene la scelta effettuata

	printf("\n\nMENU DI SCELTA\n");
	printf("a) Creazione di una nuova lista di interi.\n");
	printf("v) vedi liste\n");
	printf("b) Split k di una lista List-i.\n");
	printf("c) Split k di tutte le liste.\n");
	printf("d) Stampa un messaggio di uscita e esce dal programma.\n");
	
	printf("Fai una scelta: ");
	
	do{

		scanf("%c", &cScelta); // Inserisco la scelta nella variabile.

	}while(!(cScelta=='a' || cScelta=='b' || cScelta=='c' || cScelta=='d' || cScelta=='v'));

	return cScelta; // restituisco la variabile con la scelta fatta.
}
operation_on_list.c

Codice: Seleziona tutto

#include "header.h"
#include "strutture.h"

/**
* Funzione che mi permette di stampare
* la lista passata come argomento.
*/
void print_list(struct list* list){
	int i;
		
	struct node* tempNode;

	tempNode = list -> header;
	

	if(list -> iNumeroElementi == 0){ /* Se la lista non ha elementi */
		printf("\n%s: Nil", list -> cNomeLista); /* Stampo Nil */
	}else{
		printf("\n%s: [", list -> cNomeLista);
		for(i = 0; i < list -> iNumeroElementi; i++){ /* Ciclo for che stampa uno per uno tutti gli elementi della lista*/
			printf(" %d ", tempNode->iData);
			tempNode = tempNode -> next;
		}
		printf("]");
	}
}

/**
* Funzione che stampa tutte le liste 
* che sono state create e che sono
* presenti in memoria. Ogni lista 
* presente in memoria viene passata come
* argomento alla funzione print_list
* che si occupa di stamparla.
*/
void print_allList(struct list* list, int iNumListe){
	int i=0;
	printf("iNumListe vale: %d\n", iNumListe);
	for(i = 0; i < iNumListe; i++){ 
		list = list -> next;
		print_list(list/*->next*/);
		//list = list -> next;
	}
	/*while(list -> next != NULL){
		i = i + 1;
		list = list -> next;
	}*/
	printf("liste in memoria: %d\n", i);
}
void printNameOfAllList(struct list *list, int contList){
	int i;
	for(i=0; i < contList; i++){
		list = list -> next;
		printf("\n%s", list -> cNomeLista);
	}
}
int split_k_diUnaLista(int x, struct list* list, int k, int iContList){
	int i;
	int j;
	int iElemento;
	struct node* tempNode = list -> header; /* Assegno a tempNode la testa della lista passata come argomento */
	struct node* tempNode2 = list -> header; /* tempNode2 lo uso per lavorare con la nuova lista creata a partire da quella passata per argomento. */
	struct list* newList = list; /* Dichiarazione una nuova lista*/
	
	while(newList -> next != NULL){ /* Ciclo che mi serve per spostarmi all'ultima lista presente in memoria. */
		newList = newList -> next;
	}

	iContList = iContList + 1; /* Incremento il contatore del numero di liste presenti in memoria */
	newList = insert_list(newList, iContList); /* Faccio l'inserimento della nuova lista in memoria. */
	
	
	for(i=0; i < list -> iNumeroElementi; i++){
		if(i == x){ //appena l'indice i e' uguale al valore calcolato x
			for(j=i; j < list -> iNumeroElementi; j++){ /* Scorro la lista a partire dall'elemento indicato 
									dall'indice x calcolato*/
				iElemento = tempNode2 -> iData; /* Prendo l'elemento corrispondente */
				insert_node(newList, iElemento); /* e lo inserisco nella nuova lista */
				tempNode2 = tempNode2 -> next; /* Passo all'elemento successivo. */
			}
			tempNode = tempNode -> next = NULL; /* Metto l'elemento successivo a quello indicato dall'indice i*/
			list -> iNumeroElementi = x; /* Modifico la lunghezza della lista originale passata come argomento. */
			break; //interrompo il ciclo for
		}
	tempNode = tempNode -> next;
	tempNode2 = tempNode2 -> next;
	}
	
	k = k - 1; /* Decremento k che sarebbe il numero di nuove liste da creare*/
	if(k>1){
		iContList = split_k_diUnaLista(x, newList, k, iContList); /* Chiamata ricorsiva passando come argomenti il solito 
									     valore di x, la nuova lista calcolata, il valore di k aggiornato
									     e iContList aggiornato*/
	}

	return iContList;
}


int split_k_diTutteLeListe(struct list* list, int k, int iContList){
	int i;
	int x;
	int temp = iContList;

	list = list -> next;

	for(i=0; i < temp; i++){ /* Uso temp come guardia perche' iContList viene modificato e si andrebbe in errore. */
		if(list -> iNumeroElementi != 0){ /* Per ogni lista che contiene almeno un elemento, */
			x = (list -> iNumeroElementi)/k; /* calcolo il valore della x secondo le specifiche del testo. */
			iContList = split_k_diUnaLista(x, list, k, iContList);/* E ogni lista presente in memoria la passo come argomento
										 alla funzione dell'esercizio al punto b. */
			list = list -> next; /* Passo alla lista successiva. */
		}else{
			list = list -> next; /* Se la lista attuale contiene 0 elementi, quindi Nil, passo 
						alla lista successiva. */
		}
	}
		
	
	return iContList; /* Ritorno il valore di iContList aggiornato (cioe' il numero di liste presenti in memoria dopo
				aver chiamato le funzioni sopra). */
}

/**
* Funzione che controlla se il nome di lista
* inserito corrisponde con un nome di lista
* presente in memoria.
*/
int listPresentOrNotPresent(struct list* list, char *sEnteredName, int iContList){
	int i;	/* indice del ciclo for */
	int k;  /* valore richiesto dal testo dell'esercizio */
	int x;  /* valore calcolato secondo le specifiche dell'esercizio */
	int notPresent = 0;

	for(i=0; i < iContList; i++){ //scorro tutte le liste a partire dalla prima alla ricerca di quella inserita in input
		list = list -> next;
		if(strcmp(list -> cNomeLista, sEnteredName)==0){ //verifico che il nome della lista corrisponde a quello da me inserito
			notPresent = 1;
			if(list -> iNumeroElementi == 0) { //se la lista contiene 0 elementi (Nil) stampo un messaggio e esco.
				printf("Split non applicabile ad una lista vuota!\n");
				break;
			}

			do{ /* Se la lista esiste chiedo di inserire il valore di k, controllando di inserire un valore > 1. */
				printf("Inserisci un valore intero positivo(maggiore di 1): ");
				scanf("%d", &k);
			}while(k<=1);

			x = (list -> iNumeroElementi)/k; /* Calcolo il valore della x secondo le specifiche del testo */

			iContList = split_k_diUnaLista(x, list, k, iContList); /* chiamo la funzione per effettuare lo split sulla lista inserita in input con il valore di k inserito in input. */
			break;
		}
	}
	
	if (notPresent != 1) printf("Lista non trovata\n"); /* Se il nome che inserisco non si trova in memoria, stampo un messaggio informativo. */
	
	return iContList;
}



/**
* Funzione che, se richiamata, mi permette di 
* di inizilizzare la lista.
*/
struct list* init_list (){
	printf("Inizializzo la struttura delle liste\n");
	struct list *temp;

	temp = malloc(sizeof(struct list));

	temp -> iNumeroElementi=0;
	temp -> header = NULL;
	temp -> tail = NULL;
	temp -> next = NULL;

	return temp;
}

/**
* Funzione che nserisce una nuova lista in memoria
* con nome nel formato List-iContList (che è progressivo).
*/
struct list* insert_list(struct list* list, int iContList){ //modifica
        //creo una nuova lista
	struct list *new_list;
	//alloco spazio per la nuova lista
	new_list = malloc(sizeof(struct list));

	sprintf(new_list -> cNomeLista, "List-%d", iContList);
	new_list -> iNumeroElementi = 0;
	new_list -> header = NULL;
	new_list -> tail = NULL;
	list -> next = new_list;
	
	new_list -> next = NULL;

	return new_list;
}
operation_on_node.c

Codice: Seleziona tutto

#include "strutture.h"
#include "header.h"

void insert_node(struct list *list, int iElemento){
	//creo un nuovo nodo
	struct node *new_node;
	//alloco spazio per il nuovo nodo
	new_node = malloc(sizeof(struct node));

	new_node -> iData = iElemento;

	new_node -> next = NULL;
	
	if(list -> iNumeroElementi==0){
		new_node -> prev = NULL;

		list -> header = new_node;
	}else{
		new_node -> prev = list -> tail;
		list -> tail -> next = new_node;
			

	}

	list -> tail = new_node;
	
	list -> iNumeroElementi++;
}

int scan_node(struct list* list, int indice){
	
	indice--;
	if(indice >= list -> iNumeroElementi){
		printf("Errore: hai inserito un indice che supera le dimensioni della lista");
		return 0;
	 }
	int i;
	int iElemento;
	struct node* tempNode;
	tempNode = list -> header;
	for(i = 0; i < list -> iNumeroElementi; i++){
		if(i == indice){
			iElemento = tempNode -> iData;
			return iElemento;
		}
	tempNode = tempNode -> next;
	}
	return 0;	
}
strutture.h

Codice: Seleziona tutto

struct node{
	int iData;//elemento della lista
	struct node *prev; //puntatore all'elemento precedente della lista;
	struct node *next; //puntatore all'elemento successivo della lista;
};

struct list {
	char cNomeLista[10]; //array contenente il nome della lista
	int iNumeroElementi; //numero elementi della lista
	struct node *header; //puntatore al primo elemento della lista
	struct node *tail; //puntatore all'ultimo elemento della lista
	struct list *next; //puntatore alla successiva lista
};
Il problema è questo: avviato il programma io inserisco un tot di liste con l'opzione ( a ), dopodichè chiamo o lopzione ( b ) inserendo il nome di una lista su cui operare, oppure chiamo l'opzione ( c ) che fa quello che deve fare su tutte le liste presenti in memoria.
I punti ( b ) e ( c ) quando richiamati fanno il loro dovere secondo le specifiche del testo, il problema nasce se, dopo aver chiamato ( b ) o ( c ) chiamo ( a ) per inserire una nuova lista, a questo punto anche se chiamo semplicemente ( v ) per stampare le liste in memoria mi da

Codice: Seleziona tutto

Segmentation fault ( core dumped)
Non so se sono riuscito a spiegarmi, vi faccio un esempio:
Inserisco le liste

Codice: Seleziona tutto

List-1: [ 33  -44  55  123  12 ]
List-2: [ 11  13 ]
List-3: Nil
List-4: [ 1 ]
chiamo, ad esempio, il punto ( c ) inserendo K=3 e ottengo

Codice: Seleziona tutto

Inserisci un valore intero positivo(maggiore di 1): 3
iNumListe vale: 10

List-1: [ 33 ]
List-2: Nil
List-3: Nil
List-4: Nil
List-5: [ -44 ]
List-6: [ 55  123  12 ]
List-7: Nil
List-8: [ 11  13 ]
List-9: Nil
List-10: [ 1 ]
che va bene. A questo punto chiamo ( a ) per inserire una nuova lista e chiamando ( v ) ottengo

Codice: Seleziona tutto

Fai una scelta: v
iNumListe vale: 11

List-1: [ 33 ]
List-2: Nil
List-3: Nil
List-4: Nil
Segmentation fault (core dumped)
Non capisco dove sia l'errore..

Re: [C]Problema memorizzazione liste

Inviato: dom 3 ago 2014, 13:41
da Paoletta
ciao, non uso piu' C e C++ da parecchio tempo, ma credo sia perche' in print_list l'esecuzione sceglie il ramo if anziche' il ramo else:

Codice: Seleziona tutto

       if(list -> iNumeroElementi == 0){ /* Se la lista non ha elementi */
          printf("\n%s: Nil", list -> cNomeLista); /* Stampo Nil */
       }else{
invece dovrebbe andare nel ramo else; ma andando in quello sbagliato dereferenzia un puntatore nullo, e questo spiega il segmetation fault.
Prova a fare una stampa di list -> iNumeroElementi ad ogni esecuzione, e vedi se il risultato ti sembra corretto.