c编程,队列和模块问题

时间:2018-04-24 08:25:36

标签: c queue

我用简单的操作创建一个简单的队列。我使用ADT项来包含信息,在这种情况下只包含一个int值。然后我在节点中使用此项。这些是文件:

item.h

typedef struct c_item *item;

item newItem(int x);
int eq(item x, item y);
item input_item();
void output_item(item x);
char* getx(item x);
item cloneItem(item x);

item.c

#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include "item.h"

struct c_item {
    int x;
};

item newItem(int x){
    item n = malloc(sizeof(struct c_item));
    n->x=x;
    return n;
}

int eq(item x, item y){
    if (x->x==y->x)
        return 1;
    return 0;
}

item input_item(){
    item n;
    printf("Inserisci x: ");
    scanf("%d", n->x);
    return n;
}

void output_item(item x){
    printf("x: %d\n", x->x);
}

item cloneItem(item x){
    item n ;
    n->x=x->x;
    return n;
}

queue.h

#include "item.h"

typedef struct queue *queuePtr;

queuePtr newQueue();
int emptyQueue(queuePtr q);
item dequeue(queuePtr q);
int enqueue(item val, queuePtr q);

void checkPointer(queuePtr p);

queue.c

#include <stdlib.h>
#include <stdio.h>
#include "item.h"
#include "queue.h"

typedef struct node* nodePtr;

struct node{
    item val;
    nodePtr next;
};

struct queue{
    nodePtr head, tail;
    int dim;
};

queuePtr newQueue(){
    queuePtr q = malloc(sizeof(struct queue));

    if (q==NULL)
        return NULL;

    q->dim=0;
    q->head=NULL;
    q->tail=NULL;

    return q;
}

int emptyQueue(queuePtr q){
    if (q==NULL)
        return -1;
    return q->dim==0;
}

// aggiunge un nodo alla coda
int enqueue(item val, queuePtr q){

    if (q==NULL)
        return -1;

    nodePtr nuovo = malloc(sizeof(struct node));

    if (nuovo==NULL)
        return 0;

    nuovo->val=val;
    nuovo->next=NULL;

    if(q->head==NULL) {
        q->head = nuovo;
    }
    else {
        q->tail->next = nuovo;
    } 
    q->tail=nuovo;
    (q->dim)++;
    return 1;

}

item dequeue(queuePtr q){
    if (q==NULL)
        return (item)NULL;

    if (q->dim==0)
        return (item)NULL;

    item res = q->head->val;

    struct node* tmt = q->head;

    q->head=q->head->next;

    free(tmt);

    if (q->head==NULL)
        q->tail=NULL;

    (q->dim)--;

    return res; 
}

的main.c

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

int main() {

    queuePtr q = newQueue();

    item val = newItem(1);

    item val2 = newItem(2);

    enqueue(val, q);
    enqueue(val2, q);

    item ret = dequeue(q);
    printf("x: %d\n", ret->x);

    return 0;
}

但是在编译时我有这样的错误信息:

/LibreriaQueque/main.c:17:26: error: dereferencing pointer to incomplete type ‘struct c_item’
 printf("x: %d\n", ret->x);

IDE在queue.c中给出了相同的警报消息,但它有效。我认为问题是item.c中声明的项结构,因此无法在主文件和queue.c文件中看到它。我无法从item.c移动结构声明。我该如何解决这个问题?

2 个答案:

答案 0 :(得分:3)

你在这里做了一件经常明智的事情:struct仅在你的队列实现中定义。这样可以确保其他任何模块都无法依赖struct的内部工作原理,因此您可以在不触及任何外部代码的情况下进行更改。

但在main()中,您尝试执行明确禁止的操作:访问struct的内容。这是不可能的,因为编译器在编译主文件时不知道内容。

您有两种选择:

  1. struct的定义移至您的标头文件,从而将其公开。

  2. (恕我直荐):提供像

    这样的访问方法
    int value(const item it)
    {
        return it->x;
    }
    

    并从主代码中调用它来获取值。

  3. 附注:

    • 什么是memory.h?我想你不需要它
    • 最好不要隐藏typedef后面的指针。您可以改为typedef struct c_item item;并在任何地方使用显式星号。理解代码更容易,C程序员期望指针是明确的。

答案 1 :(得分:0)

您接近使用所谓的“opaque类型”或“不透明指针”,这是一种用于ADT私有封装的设计模式。它的工作原理是在头文件中声明一个不完整的结构,调用者可以访问该结构。但只定义c文件中的结构,调用者无权访问该结构。因此调用者无法知道结构中的内容,这是一件好事。

此方法的缺点是调用者永远不能创建对象的实例 - 只指向它的指针。 (它的工作方式与C ++中的抽象基类非常相似。)因此调用者必须依靠“构造函数”和“析构函数”来执行此操作。

其他良好做法:

  • C中有一条经验法则说你永远不应该隐藏在typedef后面的指针,因为这样做往往会让读者感到困惑。

  • 编写ADT时,最好以相同的方式为所有函数,类型和宏添加前缀。在这种情况下,我会命名所有函数queue_。理想情况下,您应该有一个编码标准,说明如何前缀/后缀属于ADT的函数,宏和类型。

  • 你不应该在C中使用空括号来表示函数,因为那是过时的样式并且意味着“接受任何参数”。 (与C ++不同,它意味着不带参数。)

  • 对ADT函数参数使用const正确性。

现在要让你的ADT不透明(这是一个好的设计),你需要这样做:

queue.h

typedef struct queue queue; // typedef of incomplete type

queue* queue_new (void);
void queue_delete (queue* q);
int queue_empty (const queue* q);
// and so on

queue.c

struct queue {
  ...
};

的main.c

queue* q = queue_new();