【问题标题】:C for loop has different effect than rolled out loopC for 循环与推出循环的效果不同
【发布时间】:2018-08-11 14:39:36
【问题描述】:

我正在使用一个跟踪最后一个元素的链表在 c 中编写一个简单的队列。

这是我的代码:

#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>   

typedef struct node_s {
    uint32_t x, y;
} node;


// very cheap linked list queue that lives as long as its scope
typedef struct queue_s {
    node* node;
    struct queue_s* next;
} queue;

bool isEmpty(queue** queue)
{
    return !*queue;
}

node* dequeue(queue** head, queue** tail)
{
    if (isEmpty(head)) {
        printf("attempting to dequeue from an empty queue\n");
        return NULL;
    }
    node* ret = (**head).node;
    *head = (*head)->next;
    if (isEmpty(head)) *tail = NULL;
    printf("next %p\n", (void*) *head);
    // no need to free anything, the queue lives as long as its scope
    return ret;
}

void enqueue(queue** head, queue** tail, queue* new)
{
    if (isEmpty(head)) {
        // has no head -> make new head
        *head = new;
        *tail = new;
        printf("empty\n");
    } else {
        // has head -> make new tail // TODO does this work?
        (*tail)->next = new;
        *tail = (*tail)->next;
        printf("not empty\n");
    }
}

int main()
{
    queue* head = NULL;
    queue* tail = NULL;

    enqueue(&head, &tail, &(queue) {.node=&(node) {1, 1}, NULL});
    printf("h %i\n", head->node->x);
    printf("t %i\n", tail->node->x);

    enqueue(&head, &tail, &(queue) {.node=&(node) {2, 2}, NULL});
    printf("h %i\n", head->node->x);
    printf("t %i\n", tail->node->x);

    enqueue(&head, &tail, &(queue) {.node=&(node) {3, 3}, NULL});
    printf("h %i\n", head->node->x);
    printf("t %i\n", tail->node->x);

    // for (int i = 1; i <= 3; ++i) {
    //  enqueue(&head, &tail, &(queue) {.node=&(node) {i, i}, NULL});
    //  printf("h %i\n", head->node->x);
    //  printf("t %i\n", tail->node->x);
    // }

    return 0;
}

现在 main() 中推出的 for 循环的行为正确,因为头元素保持 1 而新元素排队:

empty
h 1
t 1
not empty
h 1
t 2
not empty
h 1
t 3

...但是 for 循环本身给出了错误的输出,因为头元素总是等于尾元素:

empty
h 1
t 1
not empty
h 2
t 2
not empty
h 3
t 3

我是一个 c 初学者,这让我发疯,有人可以帮帮我吗?

【问题讨论】:

  • &amp;(queue) {.node=&amp;(node) {i, i}, NULL} 创建一个局部变量,该变量在封闭块的末尾不再存在。
  • 您可能想了解复合文字的生命周期。

标签: c loops for-loop side-effects loop-unrolling


【解决方案1】:

这段代码:

for (int i = 1; i <= 3; ++i) {
      enqueue(&head, &tail, &(queue) {.node=&(node) {i, i}, NULL});
      printf("h %i\n", head->node->x);
      printf("t %i\n", tail->node->x);
}

等价于:

for (int i = 1; i <= 3; ++i) 
      queue next = {.node=&(node) {i, i}, NULL};
      enqueue(&head, &tail, &next);
      printf("h %i\n", head->node->x);
      printf("t %i\n", tail->node->x);
} // End of scope

新元素next 将在作用域结束时不复存在(见注释)。要让它循环工作,您需要做的是动态内存分配。

【讨论】:

  • 谢谢,我认为在函数返回之前它会一直存在,这正是我所需要的。我读了一点,据我所知,这是不可能的,因为我必须为每个队列声明队列“本地化到 for 循环块”以获得唯一的指针。所以我必须使用 malloc,对吗?
  • @Matt 是的,您可能需要使用 malloc。当我想到它时,在没有 malloc 的情况下实现这样的东西是一个非常奇怪的想法,因为不这样做会受到所有限制。
  • 我本来希望在没有 malloc 的情况下实现它,因为我不必担心再次释放并且可以让变量超出范围。我只需要创建它的范围内的队列,我不想返回它并在其他任何地方使用它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-20
  • 1970-01-01
  • 2020-07-10
  • 1970-01-01
相关资源
最近更新 更多