[C] Struct incomplete: un mistero.

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
Avatar utente
Blallo
Packager
Packager
Messaggi: 3302
Iscritto il: ven 12 ott 2007, 11:37
Nome Cognome: Savino Liguori
Slackware: 14.2 / 12.2
Kernel: 4.4.14-smp
Desktop: DWM
Località: Torino / Torremaggiore (FG)
Contatta:

[C] Struct incomplete: un mistero.

Messaggio da Blallo »

Premetto che si tratta solo di una richiesta di spiegazioni, il programma per fortuna funziona perfettamente.

Ho un dubbio che mi attanaglia la mente sulle struct incomplete.
Praticamente ho creato un ADT FIFO costituito da oggetti Item, anch'essi astratti.
(Item è composto da una stringa e un intero).

Non capisco come si faccia a risolvere un problema di "tipo incompleto".
Nel file item.c c'è questo pezzo di codice suggeritomi da un amico:

Codice: Seleziona tutto

 i = (Item) malloc (sizeof(*i));
che io in precedenza avevo scritto come

Codice: Seleziona tutto

 i = (Item *) malloc (sizeof(Item));
Nella mia versione mi dava come errore "incomplete type error", che con la prima versione non si presenta.
Il punto è che... non capisco il senso della malloc di cui sopra.
Anche perché nella fifo questa malloc

Codice: Seleziona tutto

 queue = (Queue *) malloc (sizeof(Queue));
funziona egregiamente.
Il mio amico non è stato in grado di farmi capire niente, probabilmente ha solo copincollato da qualche sorgente.
Qualcuno sa darmi una spiegazione? :)

Allego sotto i listati.
Grazie in anticipo!

item.h

Codice: Seleziona tutto

#ifndef ITEM_H_INCLUDED
#define ITEM_H_INCLUDED

#define MAXBUF 100
#define MAXSTRING 20

#define FAILURE 0
#define SUCCESS 1

typedef struct ItemStruct *Item;

Item ItemGet();
void printItem (Item item, FILE *fp);

#endif // ITEM_H_INCLUDED
item.c

Codice: Seleziona tutto

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

#include "item.h"


struct ItemStruct
{
    char word[MAXSTRING];
    int number;
};

Item ItemGet()
{
    Item i;
    char buf[MAXBUF];

    i = (Item) malloc (sizeof(*i));
    if (i == NULL)
    {
        fprintf ( stderr, "Error: insufficient memory for new element.\n");
        return NULL;
    }

    fgets(buf, MAXBUF, stdin);
    sscanf(buf, "%s %d", i->word, &i->number);

    return i;
}


void printItem (Item item, FILE *fp)
{
    fprintf(fp, "%s %d\n", item->word, item->number);
}

fifo.h

Codice: Seleziona tutto

#ifndef FIFO_H_INCLUDED
#define FIFO_H_INCLUDED

#include "item.h"

typedef struct QueueStruct Queue;

Queue *QueueInit(int size);
int QueueEmpty(Queue *queue);
void QueuePut(Queue *queue, Item item);
Item QueuePush(Queue *queue);

void QueuePrint(Queue *queue, FILE *fp);
void QueueFree(Queue *queue);

#endif // FIFO_H_INCLUDED
fifo.c

Codice: Seleziona tutto

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


struct QueueStruct
{
    Item *q;
    int N;
    int head;
    int tail;
};

/*
 * QueueInit (int size)
 *
 * Create a queue of size [Size+1].
 *
 */
Queue *QueueInit(int size)
{
    Queue *queue;

    queue = (Queue *) malloc (sizeof(Queue));
    if (queue == NULL)
    {
        fprintf ( stderr, "Error: insufficient memory for new element.\n");
        return NULL;
    }

    queue->q = (Item *) malloc (sizeof(Item) * (size+1));
    if(queue == NULL)
    {
        fprintf ( stderr, "Error: insufficient memory for new queue.\n");
        free(queue);
        return NULL;
    }
    queue->N = size+1;
    queue->head = queue->N;
    queue->tail = 0;

    return queue;
}

/*
 * QueueEmpty()
 *
 * Checks if the queue is Empty.
 *
 */
int QueueEmpty(Queue *queue)
{
    return queue->head % queue->N == queue->tail;
}

void QueuePut(Queue *queue, Item item)
{
    if ( (queue->tail + 1) != queue->head)
    {
        queue->q[queue->tail++] = item;
        queue->tail = queue->tail % queue->N;
    }
    else
        fprintf(stdout, "Full queue! Data not inserted.\n");
}

Item QueuePush(Queue *queue)
{
    queue->head = queue->head % queue->N;
    return queue->q[queue->head++];
}

void QueuePrint(Queue *queue, FILE *fp)
{
    int i;

    for(i=queue->head % queue->N; i !=queue->tail; i++)
        printItem (queue->q[i], fp);
}

void QueueFree(Queue *queue)
{
    int i;

    for(i=queue->head % queue->N; i !=queue->tail; i++)
        free(queue->q[i]);
    free(queue->q);
    free(queue);
}

Avatar utente
targzeta
Iper Master
Iper Master
Messaggi: 6628
Iscritto il: gio 3 nov 2005, 14:05
Nome Cognome: Emanuele Tomasi
Slackware: 64-current
Kernel: latest stable
Desktop: IceWM
Località: Carpignano Sal. (LE) <-> Pisa

Re: [C] Struct incomplete: un mistero.

Messaggio da targzeta »

L'errore parte dalla typedef. Quella corretta è:

Codice: Seleziona tutto

typedef struct QueueStruct Queue;
mentre in item hai (nota l'* di troppo):

Codice: Seleziona tutto

typedef struct ItemStruct *Item;
Tutto segue in cascata (a me le typedef non piacciono molto).

Emanuele
Se pensi di essere troppo piccolo per fare la differenza, prova a dormire con una zanzara -- Dalai Lama

Avatar utente
Blallo
Packager
Packager
Messaggi: 3302
Iscritto il: ven 12 ott 2007, 11:37
Nome Cognome: Savino Liguori
Slackware: 14.2 / 12.2
Kernel: 4.4.14-smp
Desktop: DWM
Località: Torino / Torremaggiore (FG)
Contatta:

Re: [C] Struct incomplete: un mistero.

Messaggio da Blallo »

Stesso errore.
Nel momento in cui la alloco nella fifo:

Codice: Seleziona tutto

queue->q = (Item *) malloc (sizeof(Item) * (size+1));
mi sputa fuori questo:

Codice: Seleziona tutto

error: invalid application of 'sizeof' to incomplete type 'Item'

Avatar utente
targzeta
Iper Master
Iper Master
Messaggi: 6628
Iscritto il: gio 3 nov 2005, 14:05
Nome Cognome: Emanuele Tomasi
Slackware: 64-current
Kernel: latest stable
Desktop: IceWM
Località: Carpignano Sal. (LE) <-> Pisa

Re: [C] Struct incomplete: un mistero.

Messaggio da targzeta »

Quello è normale. Hai definito la struttura in item.c ma in fifo.c hai incluso item.h. Devi fare qualcosa tipo:

item.h

Codice: Seleziona tutto

#ifndef ITEM_H_INCLUDED
#define ITEM_H_INCLUDED

#define MAXBUF 100
#define MAXSTRING 20

#define FAILURE 0
#define SUCCESS 1

typedef struct ItemStruct
{
  char word[MAXSTRING];
  int number;
} Item;

Item *ItemGet();
void printItem (Item *item, FILE *fp);

#endif // ITEM_H_INCLUDED
Emanuele
Se pensi di essere troppo piccolo per fare la differenza, prova a dormire con una zanzara -- Dalai Lama

Avatar utente
Blallo
Packager
Packager
Messaggi: 3302
Iscritto il: ven 12 ott 2007, 11:37
Nome Cognome: Savino Liguori
Slackware: 14.2 / 12.2
Kernel: 4.4.14-smp
Desktop: DWM
Località: Torino / Torremaggiore (FG)
Contatta:

Re: [C] Struct incomplete: un mistero.

Messaggio da Blallo »

Però io volevo provare a fare qualcosa di questo tipo.
http://ejrh.wordpress.com/2011/04/29/en ... tion-in-c/
(Alla sezione Data Hiding)
Volevo, insomma, provare ad incapsulare la struttura, per dirla alla Java. :)

Avatar utente
targzeta
Iper Master
Iper Master
Messaggi: 6628
Iscritto il: gio 3 nov 2005, 14:05
Nome Cognome: Emanuele Tomasi
Slackware: 64-current
Kernel: latest stable
Desktop: IceWM
Località: Carpignano Sal. (LE) <-> Pisa

Re: [C] Struct incomplete: un mistero.

Messaggio da targzeta »

Potevi dirlo prima.

Quello che fa lui è corretto, però allora tu non puoi mai riferire a Item direttamente fuori dal file item.c, devi:
  • usare sempre un puntatore;
  • usare solo i metodi dichiarati dentro item.h;
In particolare per allocare la coda devi fare:

Codice: Seleziona tutto

 queue->q = (Item **) malloc(sizeof(Item *) * size);
(quidi q nella QueueStruct diventa Item **q. Una volta allocato queue->q però devi anche allocare i vari oggetti Item (q->[0], q->[1], ...) usando la ItemGet().

Poi ritorni sempre e solo oggetti (Item *) e se vuoi manipolarne il contenuto devi aggiungere funzioni a item.{c,h} tipo:

Codice: Seleziona tutto

void setWord(Item *, char*);
setNumber(Item*, int);
char *GetWord(Item *);
int GetNumber(Item *);
Il punto è che solo il file item.c può accedere alla struttura Item correttamente, perché solo lui sa com'è fatta. Questa è la programmazione ad oggetti in C che a me piace molto,
Emanuele
Se pensi di essere troppo piccolo per fare la differenza, prova a dormire con una zanzara -- Dalai Lama

Rispondi