[C]Problema memorizzazione liste

Forum dedicato alla programmazione.

Moderatore: Staff

Regole del forum
1) Citare in modo preciso il linguaggio di programmazione usato.
2) Se possibile portare un esempio del risultato atteso.
3) Leggere attentamente le risposte ricevute.
4) Scrivere i messaggi con il colore di default, evitare altri colori.
5) Scrivere in Italiano o in Inglese, se possibile grammaticalmente corretto, evitate stili di scrittura poco chiari, quindi nessuna abbreviazione tipo telegramma o scrittura stile SMS o CHAT.
6) Appena registrati è consigliato presentarsi nel forum dedicato.

La non osservanza delle regole porta a provvedimenti di vari tipo da parte dello staff, in particolare la non osservanza della regola 5 porta alla cancellazione del post e alla segnalazione dell'utente. In caso di recidività l'utente rischia il ban temporaneo.
Rispondi
Dennis
Linux 0.x
Linux 0.x
Messaggi: 1
Iscritto il: lun 28 lug 2014, 20:39

[C]Problema memorizzazione liste

Messaggio 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..

Avatar utente
Paoletta
Staff
Staff
Messaggi: 3975
Iscritto il: lun 25 apr 2005, 0:00
Slackware: 14.2 - 64 bit
Desktop: fluxbox
Località: Varese

Re: [C]Problema memorizzazione liste

Messaggio 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.

Rispondi