Pagina 1 di 1

[C] Struct incomplete: un mistero.

Inviato: sab 21 giu 2014, 23:43
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);
}

Re: [C] Struct incomplete: un mistero.

Inviato: dom 22 giu 2014, 0:34
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

Re: [C] Struct incomplete: un mistero.

Inviato: dom 22 giu 2014, 4:15
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'

Re: [C] Struct incomplete: un mistero.

Inviato: dom 22 giu 2014, 11:03
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

Re: [C] Struct incomplete: un mistero.

Inviato: dom 22 giu 2014, 12:39
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. :)

Re: [C] Struct incomplete: un mistero.

Inviato: dom 22 giu 2014, 15:52
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