代码之家  ›  专栏  ›  技术社区  ›  Invictus97k

c编程、队列和模块问题

  •  0
  • Invictus97k  · 技术社区  · 6 年前

    我正在创建一个具有简单操作的简单队列。我使用ADT项来包含信息,在本例中,仅使用int值。然后在节点中使用此项。以下是文件:

    项目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);
    

    项目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;
    }
    

    队列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);
    

    队列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; 
    }
    

    主要的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 所以在主文件和 队列c 文件我无法将结构声明从 项目c . 我如何解决这个问题?

    2 回复  |  直到 6 年前
        1
  •  3
  •   user2371524 user2371524    6 年前

    你在这里做了一件非常明智的事情: struct 仅在队列的实现中定义。这确保了没有其他模块可以依赖 结构 ,因此您可以在不接触任何外部代码的情况下对其进行更改。

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

    您有两种选择:

    1. 移动的定义 结构 到您的头文件,因此将其公开。

    2. (IMHO首选):提供如下访问器方法

      int value(const item it)
      {
          return it->x;
      }
      

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


    旁注:

    • 是什么 memory.h ? 我想你不需要它
    • 最好不要把指针藏在后面 typedef . 你可以 typedef struct c_item item; 而是在任何地方使用明确的星号。代码更容易理解,C程序员希望指针是显式的。
        2
  •  0
  •   Lundin    6 年前

    您即将使用所谓的“不透明类型”或“不透明指针”,这是一种用于ADT私有封装的设计模式。它通过在头文件中声明一个不完整的结构来工作,调用方可以访问该头文件。但仅在c文件中定义结构,调用方无权访问该结构。因此,调用方无法知道结构内部是什么,这是一件好事。

    这种方法的缺点是调用方永远无法创建对象的实例,只能创建指向它的指针。(它的工作原理很像C++中的抽象基类。)因此,调用者必须依赖于“构造函数”和“析构函数”来完成此操作。

    其他良好做法:

    • C语言中有一条经验法则,即永远不要将指针隐藏在typedef后面,因为这样做会使读者感到困惑。

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

    • 永远不要对C中的函数使用空parentheis,因为这是过时的样式,意味着“接受任何参数”。(与C++不同,C++表示不带参数。)

    • ADT函数参数使用const correction。


    现在,要使ADT不透明(这是一种很好的设计),需要执行以下操作:

    队列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
    

    队列c

    struct queue {
      ...
    };
    

    主要的c

    queue* q = queue_new();