Dubbio sulle code

Ho un dubbio riguardante l’inizializzazione delle code.
Nelle slide ho notato che nella testata della funzione “InitQueue” il parametro qptr viene indicato come puntatore. Essendo di tipo Queueptr, che è a sua volta puntatore alla struttura queue, questo non creerebbe un doppio puntatore? Se sì, qualcuno sarebbe in grado di spiegarmi il senso?immagine immagine

Occhio: gli esempi di Riccardi sono diversi da quelli che abbiamo fatto in laboratorio.
Se vuoi l’esempio funzionante di Riccardi per capire meglio perché usa un doppio puntatore ecco:

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

/* Queue implementata con Liste Concatenate
        -Definizione struttura nodo
        -Funzioni di supporto
             -Inizializza
             -Enqueue
             -Dequeue
             -QueueIsEmpty
             -PrintQueue
 */

typedef int TipoElemento;

/*Struttura nodo lista*/

struct EL {
    TipoElemento Info;
    struct EL *Prox;
};
typedef struct EL ElemLista;
  

/*Struttura Coda*/

struct queue {
    ElemLista *Head;
    ElemLista *Tail;
};     
typedef struct queue Queue;
typedef Queue *QueuePtr; 


/* Prototipi funzioni per manipolizazione stack */

void    InitQueue(QueuePtr *qptr);
bool    QueueIsEmpty (QueuePtr qPtr);
void    Enqueue (QueuePtr qPtr, TipoElemento Elem);
TipoElemento    Dequeue(QueuePtr qPtr);
void    PrintQueue(QueuePtr qPtr, FILE *fout);

/* main */

int main(int argc, char *argv[])
{
    QueuePtr qptr; //
    TipoElemento value;
    
    InitQueue(&qptr);
    
    if(QueueIsEmpty(qptr)) printf("Coda e' vuota\n");
        
    /*Inseriamo degli elementi*/
    
    for(int i=0;i<10;i++){
        Enqueue(qptr, rand()%10);
    } 
    
    /*Stampa Lista*/
    PrintQueue(qptr, stdout); 
    
    /*Estraiamo un elemento */
    
    value=Dequeue(qptr);
    PrintQueue(qptr, stdout);
    
    /*Stampa Lista*/
   
    Enqueue(qptr, 10);
    PrintQueue(qptr, stdout);
    
    /* Svuotiamo Intera Coda*/
    while(!QueueIsEmpty(qptr)){
        printf("dequeued: %d\n",Dequeue(qptr));
    }
    PrintQueue(qptr, stdout);
}

/* Inizializza testa e coda  */

void    InitQueue(QueuePtr *qptr){
    
    
    if( !(*qptr=(Queue *) malloc(sizeof(Queue))) ){
        printf("errore allocazione mem InitQueue\n");
        exit(1);
    }
    (*qptr)->Head=NULL;
    (*qptr)->Tail=NULL;
}

/* Se la testa e' vuota la coda e' vuota  */

bool    QueueIsEmpty (QueuePtr qPtr){
    return (qPtr->Head == NULL);
}

/* Inserimento in Coda Alla Lista*/

void    Enqueue(QueuePtr qptr, TipoElemento Elem){
    
     ElemLista *Punt;
    
    /* Allocazione Nuovo Elemento ed inizializzazione  puntatore*/
    
    if( !(Punt=(ElemLista *) malloc(sizeof(ElemLista))) ){
        printf("errore allocazione mem Enqueue\n");
        exit(1);
    }
    Punt->Info=Elem;
    Punt->Prox=NULL; //Elemento in coda
    if(QueueIsEmpty(qptr))     //head and Tail puntano a stesso elemento
        qptr->Head=Punt;
        else
                qptr->Tail->Prox=Punt;
    qptr->Tail=Punt;
}


/* Implementata con una Estrazione della testa ad una lista */


TipoElemento    Dequeue(QueuePtr qPtr){
    
    ElemLista *Punt=qPtr->Head;
    TipoElemento qvalue=qPtr->Head->Info;
    
    qPtr->Head=(qPtr->Head)->Prox;
    
    if(qPtr->Head  == NULL) qPtr->Tail=NULL;
    
    free(Punt);
    return qvalue;
    
}

/* Stampa coda a partire dalla testa della lista */

void    PrintQueue(QueuePtr qPtr, FILE *fout){
    
    if(qPtr->Head == NULL) printf("Coda e' vuota\n");
    else{
        ElemLista *Punt=qPtr->Head;
        while(Punt != NULL) {
                printf("%d\n",Punt->Info);
                Punt=Punt->Prox;
        }
        printf("Fine Coda\n");
    }
}

ma ti consiglio di vedere piuttosto le slide di laboratorio per le implementazioni FIFO, LIFO e compagnia bella.

Infatti anche io ho notato questa cosa, secondo me il parametro della funzione è (QueuePtr qptr) oppure (struct Queue* qptr) senza il doppio puntatore, che QueuePtr è già un puntatore da typedef, altrimenti sarebbe un puntatore a valore puntatore a valore struttura. Non necessario in questo caso, mi sembra di capire. All’esame cmq si usa il C++ quindi io proverei a scriverla così:

void InitQueue (QueuePtr qptr) {

   qptr = new Queue;

   if (!qptr) { 
   cout << "errore allocazione mem InitQueue << endl; 
   exit(1);
   }

   qptr -> Head = nullptr;
   qptr -> Tail = nullptr;
}

Sono 2 giorni che ho preso in mano il ++, a saperlo prima nemmeno mi imparavo sto malloc. Cmq quello che ho scritto qui sopra a me funziona SOLO se metto “using namespace std” e “#define nullptr NULL”, non so come mai me lo fa solo con DevCpp (che è quello che si usa all’esame). Non so se exit è come il C però

1 Mi Piace

Non penso ti serva più una risposta dato che è passato un mese ma magari a qualcuno potrebbe servire:
Nella gestione delle linked list si usano puntatori doppi, questo perchè in C i parametri sono passati alla funzione sempre per COPIA, anche quando usiamo i puntatori per passare un parametro per RIFERIMENTO in realtà stiamo passando per COPIA l’indirizzo della variabile puntata dal puntatore.
Di solito una lista è identificata da un PUNTATORE al primo elemento della lista, di coseguenza per modificare questo PUNTATORE bisogna passare alla funzione un PUNTATORE a tale PUNTATORE(PUNTATORE doppio). In questo modo passando alla funzione l’indirizzo del puntatore alla testa della lista possiamo modificarlo, se passassimo l’indirizzo del puntatore alla testa della lista come argomento potremmo modificare solo ciò a cui punta.
Lascio di seguito una guida ben fatta (in inglese) sull’argomento:
https://dev-notes.eu/2018/07/double-pointers-and-linked-list-in-c/