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

4 回答 4

5

你有没有尝试过:

(*lastAction) -> nextAction = newQueuedAction;
于 2010-10-18T07:26:27.290 回答
3

你也可以这样做:

(*lastAction)->nextAction

我认为这是操作员操作的问题。

于 2010-10-18T07:29:24.547 回答
1

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

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

源代码可通过 GIT 获得。

格茨

于 2010-12-11T16:02:57.137 回答
1

我希望这会提前帮助你。首先,对不起我的英语。它可能有几个语法或拼写错误。

我在你的代码中看到的问题主要是你混合了一个指针的定义和同一个指针的实现。

从 ANSI C 到 C99,即使在 C++ 中(未在 C# 中测试),也有一个使用指针的大技巧可能会提前有所帮助:认为指针是向量的第一个元素,即[0] one

一个解释这个概念的好网站是:http ://boredzo.org/pointers/

这个 hack 是一个简单的翻译,是一个很好的 hack 工具,可以更好地理解指针。

开始行动吧,孩子们。

用于将元素添加到列表中的函数,

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 -> ...;

作为

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] hack的运算符

它看起来像这样:

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 定义为其他东西的被动攻击型程序员。始终使用大括号以确保可扩展性。这一行只是代码风格的推荐。

希望能帮助到你,

于 2017-09-14T07:15:01.900 回答