Lista di struct C

abaco90
Ciao a tutti,

ho da poco approcciato alle liste e sto cercando si svolgere un esercizio in cui ho una lista che ha come elementi delle struct.

In particolare, ho le seguenti dichiarazioni:

struct libro {
    char *nome;
    char *genere;
    int quantita;
};

struct nodo {
    struct libro l;
    struct nodo *next;
};


La prima struct contiene le informazioni su un libro, cioè il nome, il genere e la quantità, cioè il numero di copie che ho a disposizione.
La seconda struct invece rappresenta una lista che ha come elementi la struct libro, cioè i libri.

L'esercizio richiede di svolgere alcune funzioni, che ho gia implementato per liste di interi e funzionano.
Il problema ora è che ho una lista di struct e non riesco ad adattarle a questa situazione.

Ad esempio, partendo dall'inizio, cioè l'acquisizione in input della quantità di ogni libro, come devo fare?

Io per le liste di interi utilizzo il seguente codice:

struct elemento {

	int inf;

	struct elemento *next;
};

typedef struct elemento* list;

void inserisci_coda (list *lista, int elem) {

	list l = *lista;

	// caso lista vuota (N.B. fondamentale l'utilizzo di *lista)

	if (*lista == NULL) {

		*lista = malloc(sizeof(struct elemento));

		(*lista) -> inf = elem;

		(*lista) -> next = NULL;
	}

	// caso lista con almeno un elemento

	else {

		while (l -> next != NULL) { // cerco l'ultimo elemento

			l = l -> next; // l ha l'indirizzo dell'ultimo elemento
		}

		l -> next = malloc(sizeof(struct elemento));

		l = l -> next;

		l -> inf = elem;

		l -> next = NULL;
	}
}


Ovviamente ho provato diverse soluzioni ma vengono un sacco di errori.

Grazie!

Risposte
apatriarca
Sostituisci alle variabili intere delle variabili di tipo struct libro e tutto dovrebbe funzionare senza problemi..

Super Squirrel
Magari posta quello che hai fatto finora, così possiamo darti delle indicazioni più precise.

abaco90
Ho riscritto la funzione che crea la lista, in modo che mi restituisca un puntatore e funziona:

struct nodo *crea_lista () {
 
	struct nodo *p, *punt;

	int i, n; // --> i è l'indice del ciclo, n è il numero di elementi

	printf("Inserisci il numero di libri\n");
	scanf("%d", &n);

	if (n == 0) {

		p = NULL; // lista vuota
	}

	else {

		// creo primo elemento (testa)

		p = (struct nodo*) malloc (sizeof(struct nodo));

		printf("Inserisci la quantità del 1° libro: ");
		scanf("%d", & p -> l.quantita);

		punt = p;

		// aggiungo gli altri elementi

		for (i = 2; i <= n; i++) {

			punt -> next = (struct nodo*) malloc (sizeof(struct nodo));
			punt = punt -> next;

			printf("Inserisci la quantità del %d° libro: ", i);
			scanf("%d", & punt -> l.quantita);
		}

		punt -> next = NULL; // fine lista
	}

	return p;
}


e nel main scrivo:

struct nodo *lista;
lista = crea_lista();


però mettiamo che la mia struct libro abbia un'intero in più che rappresenta il numero di pagine, quindi:

struct libro {
    char *nome;
    char *genere;
    int quantita;
    int pagine;
};


come faccio ad aggiungere questa ulteriore informazione alla lista? Ho provato a scrivere un duplicato della funzione crea_lista, con un nuovo nome cioè crea_lista2 e nel main ho scritto:

struct nodo *lista;
lista = crea_lista();
lista = crea_lista2();


però mi sembra di capire che mi sovrascrive i valori rappresentanti i numeri di pagine sopra quelli delle quantità.
In sostanza quindi, come faccio ad aggiungere più elementi diversi alla stessa lista?

Grazie!

Super Squirrel
Per aggiungere elementi alla lista userei delle semplici funzioni inserisci_testa o inserisci_coda in cui vai ad inserire tutte le informazioni riguardanti il singolo libro. Nel caso poi devi aggiornare il numero di copie, puoi effettuare una ricerca per titolo e quindi modifichi il campo quantità.

Qualcosa del genere insomma:

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

#define M 20

typedef struct libro_
{
    char nome[M];
    char genere[M];
    int quantita;
}   libro;

typedef struct nodo_
{
    libro l;
    struct nodo_ *next;
}   nodo;

void inserisci_testa(nodo **testa, char *NOME, char *GENERE, int QUANTITA)
{
    nodo *nuovo = malloc(sizeof(nodo));
    strcpy(nuovo->l.nome, NOME);
    strcpy(nuovo->l.genere, GENERE);
    nuovo->l.quantita = QUANTITA;
    nuovo->next = *testa;
    *testa = nuovo;
}

void mostra_lista(nodo *testa)
{
    if(testa == NULL)
    {
        printf("LISTA VUOTA!\n");
    }
    else
    {
        do
        {
            printf("%s / %s / %d\n", testa->l.nome, testa->l.genere, testa->l.quantita);
            testa = testa->next;
        }
        while(testa != NULL);
    }
}

int main()
{
    nodo *testa = NULL;
    inserisci_testa(&testa, "L'isola del tesoro", "Romanzo ", 7);
    inserisci_testa(&testa, "Marcovaldo        ", "Racconti", 4);
    inserisci_testa(&testa, "Re Lear           ", "Tragedia", 9);
    mostra_lista(testa);
    return 0;
}

abaco90
Ti ringrazio molto, mi hai risolto un problema che mi bloccava!

Funziona tutto ma c'è un ultimo problema però: le dichiarazioni delle struct sono in un file .h che non posso modificare e quindi non posso scrivere char nome[M] e char genere[M] e se lascio invariato il compilatore ovviamente mi da segmentation fault.

Come posso fare?

Super Squirrel
Basta che nella funzione inserisci_testa allochi la memoria necessaria per il nome e il genere.

abaco90
Grazie mille!

abaco90
Ciao scusa se ti chiedo aiuto ancora, ho provato a fare come hai detto ma non ci sono riuscito, mi potresti aiutare?

Grazie!

Super Squirrel
Ciao, premesso che non sono molto pratico delle funzioni del C, potresti fare qualcosa del genere:

nuovo->l.nome = malloc((strlen(NOME) + 1) * sizeof(char));
strcpy(nuovo->l.nome, NOME);

apatriarca
Il valore di [tt]sizeof(char)[/tt] è 1 in qualsiasi compilatore/sistema per la definizione di [tt]sizeof[/tt]. Esiste una funzione che unisce tutte queste operazioni (strdup). Non è standard C (è definita in POSIX), ma è utilizzabile praticamente ovunque (compreso il compilatore Microsoft). Il codice con questa funzione diventa semplicemente:
nuovo->l.node = strdup(NOME);

La memoria viene internamente allocata con malloc per cui devi anche in questo caso usare free per deallocare la memoria.. Le opinioni riguardo all'uso di questa funzione variano molto per cui non sono sicuro quale sia quella del tuo professore. Personalmente trovo che quando la dimensione è sconosciuta, è più semplice di scrivere il corrispondente codice. Per quanto sia abbastanza corto.

abaco90
Grazie ad entrambi per il prezioso aiuto!

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.