Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/63.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 为什么我要重写我的结构?实现队列,但它没有';工作_C_Pointers_Struct_Queue_Malloc - Fatal编程技术网

C 为什么我要重写我的结构?实现队列,但它没有';工作

C 为什么我要重写我的结构?实现队列,但它没有';工作,c,pointers,struct,queue,malloc,C,Pointers,Struct,Queue,Malloc,我需要用C语言编程队列结构来分配任务。节点具有指向下一个节点的指针和值(到目前为止,正常)。但是,由于我需要在线程中使用它,我将malloc堆上的所有容量。 但是,节点和队列的定义如下: //Element of a queue struct queue_node { // Pointer to next element in the queue struct queue_node* next; // Value/Data of the queue element

我需要用C语言编程队列结构来分配任务。节点具有指向下一个节点的指针和值(到目前为止,正常)。但是,由于我需要在线程中使用它,我将malloc堆上的所有容量。 但是,节点和队列的定义如下:

//Element of a queue
struct queue_node {
    // Pointer to next element in the queue
    struct queue_node* next;
    // Value/Data of the queue element
    int value;
};

// Queue data structure
    struct queue {
    // Head of the linked list
    struct queue_node* head;
    // Max capacity of the queue
    int capacity;
    // Current size of the queue. size <= capacity, always
    int size;
};
struct queue* queue_new(int capacity){

    struct queue_node* head1 = malloc(sizeof(struct queue_node)*capacity);

    struct queue* ret = malloc(sizeof(struct queue));

    /*
    struct queue_node head2;
    head2.next = NULL;

    (*head1) = head2;
    */
    (*head1).next = NULL;

    (*ret).head = head1;
    (*ret).size = 0;
    (*ret).capacity = capacity;

    return ret;

    }



void queue_delete(struct queue* queue){
    free((*queue).head);
    free(queue);
    }
所以。但是,当我想把东西推到队列中时,我会遇到麻烦。显然,首先要做的是填满脑袋。这似乎奏效了。但将元素附加到头部节点不会:

int queue_push_back(struct queue* queue, int value){

    if((*queue).size >= (*queue).capacity){
        return -1;
    }else if((*queue).size == 0){
        (*(*queue).head).value = value;
        (*queue).size++;
        return (*queue).size;
    } else{



        if((*(*queue).head).next == NULL){          ////((*queue).head + sizeof(struct queue_node))

            printf("Intern queue size 1: %d\n", (*queue).size);

            (*(*queue).head).next = ((*queue).head + sizeof(struct queue_node));
            printf("Error here?\n");
            (*(*(*queue).head).next).value = value;
            printf("Error here 2?\n");
            (*(*(*queue).head).next).next = NULL;
            printf("Error here 3?\n");


            printf("Intern queue size 2: %d\n", (*queue).size);
            printf("Intern queue capacity: %d\n", (*queue).capacity);

            (*queue).size++;
            return (*queue).size;

        }
}
我跳过了常见情况下的代码,因为这根本不起作用。出于某种原因,如果我想推送第二个元素,它会覆盖我的队列结构。我不知道为什么。
有人能帮我一下,告诉我哪里做错了什么吗?

你似乎在试图混合两种不同的方法来解决这个问题:

  • 将队列维护为数组,以及

  • 将队列维护为链表

  • 为一个块中的全部节点分配空间,将队列头保持在块的开头,并且实际上首先具有固定的队列容量,这些都是类似于数组的使用的特征。另一方面,具有带有“下一个”指针的元素节点结构是链表的形式

    如果您将队列管理为一个数组,那么
    next
    指针是多余的,如果您实际使用它们,它们确实会收缩。相反,您可以始终通过指向节点块开头的指针和节点索引来标识和导航到节点:
    my\u queue\u ptr->head[node\u num]
    。您还可以根据队列的当前大小确定下一个可用节点:
    my\u queue\u ptr->head[my\u queue\u ptr->size]

    但是,每当您将一个节点出列时,您必须将所有其他节点(至少是它们的数据)向前移动一个位置。如果移动整个节点,则会弄乱它们的
    next
    指针,因为每个指向位置的对象与之前的对象不同,并且具有不同的意义

    另一方面,如果将队列管理为链表,则在一个块中分配所有节点是没有意义的。相反,传统做法是为您排队的每个值分配一个新节点,并取消分配您排队的每个值的节点。在这种情况下,您将在第一个元素进入队列和任何元素退出队列时修改队列的
    指针。如果您没有维护指向当前尾部的指针(目前没有),那么每次您将一个元素排入队列时,您都需要遍历列表以找到尾部节点,并将新节点附加到那里


    更新: 如果您仍然继续您所描述的内容,对我来说唯一有意义的方法就是采用基于数组的方法,完全忽略数据结构的链表方面。您提供的
    queue\u new()
    queue\u delete()
    函数对此是合理的。另一方面,您的
    队列\u push\u back()
    甚至在内部都不一致,更不适合类似于数组的方法

    在此之前,我将详细介绍,但是,我想指出,您的代码不必要地难以阅读。至此,您肯定已经了解了
    ->
    操作符;它是专门为方便使用指向结构的指针而设计的,特别是为了方便使用指向结构的指针链。这是您的
    队列\u push\u back()
    函数的第一部分,已重写为使用
    ->
    ;提交的部分与原件的相应部分完全相同:

    int queue_push_back(struct queue* queue, int value){
    
        if (queue->size >= queue->capacity) {
            return -1;
        } else if (queue->size == 0) {
            queue->head->value = value;
            queue->size++;
            return queue->size;
        } else {
    
        // ...
    
    }
    
    至少对我来说,这更容易阅读。现在,通过减少干扰,更容易看到头部节点的唯一属性是其
    值。不设置其
    next
    指针。如果您已经理解了我的建议,那么您将认识到这实际上很好——您将使用数组中的索引来访问元素,而不是链接,这充其量是冗余的

    但是现在考虑一下当你推下一个元素时你想做什么。第一件事是测试头部节点的

    next
    指针的值,这是您从未设置过的。未定义的行为结果。现在您可以管理并使用这些链接(尽管如果您想支持容量大于2的队列,您需要比现在更复杂的东西),但正如我所说的,我的建议是完全忽略这些链接

    已经验证队列是否有空间容纳另一个元素后,您可以通过
    queue->head[queue->size]
    直接访问该元素:

        queue->head[queue->size].value = value;
        queue->size++;
    
    瞧,这就是一切。但是等等,情况会好起来的!如果仔细观察,您会发现第一个节点的情况与其他节点的情况几乎没有区别。事实上,这种差异纯粹是句法上的;第一个节点(当
    queue->size==0
    时)将由我刚才介绍的代码提供同样好的服务;这根本不需要特殊情况:

    int queue_push_back(struct queue* queue, int value){
        if (queue->size >= queue->capacity) {
            return -1;
        } else {
            queue->head[queue->size].value = value;
            return ++queue->size;
        }
        // That's all, folks!
    }
    

    您似乎试图混合两种不同的方法来解决此问题:

  • 将队列维护为数组,以及

  • 将队列维护为链表

  • 为一个块中的全部节点分配空间,将队列头保持在块的开头,并且实际上首先具有固定的队列容量,这些都是类似于数组的使用的特征。另一方面,具有带有“下一个”指针的元素节点结构是链表的形式

    如果您将队列管理为一个数组,那么
    next
    指针是多余的,如果您实际使用它们,它们确实会收缩。相反,始终可以通过指向节点块开头的指针和