在C语言中实现FIFO队列

4

我正在为一个嵌入式应用程序尝试使用 ANSI C 实现结构体的先进先出 (FIFO) 队列。实现这一目标最直接的方法似乎是通过实现链表,使得每个结构体都包含指向队列中下一个结构体的指针。因此,我将结构体本身定义为:

typedef enum { LED_on, LED_off, etc } Action;
typedef struct Queued_Action QueuedAction;

struct Queued_Action
{
    Action       action;
    int          value;
    QueuedAction *nextAction;
};

到目前为止一切顺利。如果我将指针定义为队列中第一个和最后一个项目:

QueuedAction *firstAction;
QueuedAction *lastAction;

如果涉及到添加新的操作到队列中,可以通过以下方式进行说明:

if (!add_action_to_queue(LED_on, 100, &lastAction))
     printf("Error!\n);

...因此,当返回时,lastAction将指向队列中新创建的最后一个动作的指针。因此,将动作添加到队列的例程将如下所示:

int add_action_to_queue(Action newAction, int newValue, QueuedAction **lastAction)
{
    QueuedAction *newQueuedAction;

    // Create a new action in memory
    if ((newQueuedAction = (QueuedAction *)malloc(sizeof(QueuedAction))) == NULL)
        return 0;

    // Make the old 'lastAction' point to the new Action, 
    // and the new Action to point to NULL:
    *lastAction -> nextAction = newQueuedAction;
    newQueuedAction -> nextAction = NULL;
    newQueuedAction -> action = newAction;
    newQueuedAction -> value = newValue;

    // Designate the new Action as the new lastAction:
    *lastAction = newQueuedAction;
    return 1;
}

除了这段代码无法编译之外,一切都很好。错误出现在这行代码:


*lastAction -> nextAction = newQueuedAction;

......编译器声称“->”左侧的项目不是有效的结构体。但是,它肯定是有效的。如果我实际上进行了本应该是完全多余的强制转换:

fakeAction = (QueuedAction *)(*lastAction);
fakeAction -> nextAction = newQueuedAction;

如果编译器没有报错,那么一切都很顺利。但是,我担心错误信息暗示了我可能做错了一些微妙的事情。所以(言归正传),有人能告诉我为什么编译器不满意,以及是否有更好的方法来实现我在这里尝试做的事情吗?

4个回答

5

你尝试过以下方法吗:

(*lastAction) -> nextAction = newQueuedAction;

谢谢你们两位,的确是运算符优先级的问题,将括号放在(*lastAction)周围解决了这个问题。 - Eos Pengwern

3
您也可以这样做:
(*lastAction)->nextAction

我认为这是运算符优先级的问题。

是的,这就是运算符优先级在作怪。 - sbi

1
我希望这能提前帮到你。首先,抱歉我的英语可能有几个语法或拼写错误。
我看到你代码中的问题主要是你混合了指针的定义和实现。
从ANSI C到C99,甚至在C++(没有在C#中测试),使用指针的一个很好的技巧是:认为指针是向量的第一个元素,即 [0] 元素。
一个很好的解释这个概念的网站是:http://boredzo.org/pointers/ 这个技巧是一种简单的翻译,也是一个更好地理解指针的好工具。
开始动手吧,伙计们。
你用来向列表添加元素的函数,
int add_action_to_queue(Action newAction, int newValue, QueuedAction **lastAction)
{
    QueuedAction *newQueuedAction;

    // Create a new action in memory
    if ((newQueuedAction = (QueuedAction *)malloc(sizeof(QueuedAction))) == NULL)
        return 0;

    // Make the old 'lastAction' point to the new Action, 
    // and the new Action to point to NULL:
    *lastAction -> nextAction = newQueuedAction;
    newQueuedAction -> nextAction = NULL;
    newQueuedAction -> action = newAction;
    newQueuedAction -> value = newValue;

    // Designate the new Action as the new lastAction:
    *lastAction = newQueuedAction;
    return 1;
}

包含一些错误。首先,请考虑使用

标签。

*lastAction -> ...;

as

lastAction[0] -> ...;

正如您所看到的,您无法使用->运算符访问内部元素。
这里也是一样的:
lastAction[0] = newQueuedAction;

你不能复制结构体内的指针。使用这个技巧更好地理解,lastAction 不再是一个指针 - 实际上,它是编译器分配到结构体第一个元素中的内容 - 因此你需要改变这一行,以改变指针的值:
lastAction = newQueuedAction;

使用这个翻译和注释,现在您的代码将会是这样的:
int add_action_to_queue(Action newAction, int newValue, QueuedAction **lastAction)
{
    QueuedAction *newQueuedAction;

    // Create a new action in memory
    if ((newQueuedAction = (QueuedAction *)malloc(sizeof(QueuedAction))) == NULL)
        return 0;

    // Make the old 'lastAction' point to the new Action, 
    // and the new Action to point to NULL:
    lastAction[0] -> nextAction = newQueuedAction;
    newQueuedAction -> nextAction = NULL;
    newQueuedAction -> action = newAction;
    newQueuedAction -> value = newValue;

    // Designate the new Action as the new lastAction:
    lastAction[0] = newQueuedAction;
    return 1;
}

现在错误已经变得明显:您试图错误使用->运算符。这意味着您的代码将更改两个方面:

  • 使用->运算符

它看起来像这样:

int add_action_to_queue(Action newAction, int newValue, QueuedAction **lastAction)
{
    QueuedAction *newQueuedAction;

    // Create a new action in memory
    if ((newQueuedAction = (QueuedAction *)malloc(sizeof(QueuedAction))) == NULL)
        return 0;

    // Make the old 'lastAction' point to the new Action, 
    // and the new Action to point to NULL:
    lastAction -> nextAction = newQueuedAction;
    newQueuedAction -> nextAction = NULL;
    newQueuedAction -> action = newAction;
    newQueuedAction -> value = newValue;

    // Designate the new Action as the new lastAction:
    lastAction = newQueuedAction;
    return 1;
}
  • 使用.操作符和[0]技巧

看起来像这样:

int add_action_to_queue(Action newAction, int newValue, QueuedAction **lastAction)
{
    QueuedAction *newQueuedAction;

    // Create a new action in memory
    if ((newQueuedAction = (QueuedAction *)malloc(sizeof(QueuedAction))) == NULL)
        return 0;

    // Make the old 'lastAction' point to the new Action, 
    // and the new Action to point to NULL:
    lastAction[0].nextAction = newQueuedAction;
    newQueuedAction[0].nextAction = NULL;
    newQueuedAction[0].action = newAction;
    newQueuedAction[0].value = newValue;

    // Designate the new Action as the new lastAction:
    lastAction = newQueuedAction;
    return 1;
}

不要忘记删除== NULL代码,否则你可能会遇到一个被动侵略的程序员,他将NULL定义为其他东西。始终使用大括号确保可扩展性。这行只是代码风格的建议。
希望能帮到你,

1

我制作了一个可以处理队列的小型库。 "UltraQueue"

它是用C++编写的,但完全兼容ANSI C。 如果你真的想要,它可以很容易地转换为ANSI C。

源代码可通过GIT获得。

Grtz


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接