C 中的队列可变参数推送

Queue variadic push in C

我有一个关于在用 C 语言编写的队列实现中使用 varadic 功能的问题。特别是我需要编写一个多推函数来将结构存储到队列中。

code_generator.h

typedef enum
{
    NOP,
    START, END,
    ADD, MIN, MULT, DIV,
    ..., // others similar stuffs
    LABEL,
    LE, GE, LT, GT,
    AND, OR,
    DECREMENT
} p_operator;
typedef struct code
{
    p_operator operator;
    p_argument argument;

    struct code * next;

} *p_code;


typedef struct queue
{
    unsigned int length;
    struct code * head;
    struct code * tail;
} p_queue;

不用担心p_operator和p_argument,第一个是枚举,第二个是用于存储不同类型数据的典型联合。 我尝试了两种不同的实现,但没有一个有效。

第一种方法(参数数量未知)

p_queue pqueue_push(p_queue queue, p_code code, ...)
{
    p_code temp;
    va_list vars;

    va_start(vars, code);
    printf("PUSH 1\n");

    for(temp = code; temp != NULL; temp = va_arg(vars, p_code))
    {
        printf("PUSH 2 OPERATOR: %d\n", temp->operator);

        if(queue.length == 0)
        {
            printf("PUSH 3\n");
            queue.tail = queue.head = temp;
        }
        else
        {
            printf("PUSH 4\n");
            p_code swap = queue.tail;
            swap->next = temp;
            queue.tail = swap->next;
        }

        queue.length = queue.length + 1;

        printf("PUSH 5 : %d\n", queue.length);
    }

    printf("PUSH 6\n");
    va_end(vars);

    return queue;
}

在这种情况下,程序会打印所有内容,但会再执行一次循环(为什么?),显然,在队列中存储了一些不存在的内容。

第二种方法(参数个数已知)

p_queue pqueue_push(p_queue queue, int nargs, p_code code, ...)
{
    int i;
    p_code temp;
    va_list vars;

    va_start(vars, code);
    printf("PUSH 1 ARGS SIZE: %d\n", nargs);

    for(i = 0; i < nargs; i++)
    {
        temp = va_arg(vars, p_code);
        printf("PUSH 2 OPERATOR: %d\n", temp->operator);

        if(queue.length == 0)
        {
            printf("PUSH 3\n");
            queue.tail = queue.head = temp;
        }
        else
        {
            printf("PUSH 4\n");
            p_code swap = queue.tail;
            swap->next = temp;
            queue.tail = swap->next;
        }

        // Aumenta la dimensione dello queue
        queue.length = queue.length + 1;

        printf("PUSH 5 : %d\n", queue.length);
    }

    printf("PUSH 6\n");
    va_end(vars);

    return queue;
}

在第二种情况下,控制台在 "PUSH 2" 处显示分段错误,这意味着 temp->operatorNULL(但如果第一种方法有效,则没有任何意义在相同的参数上很好)。

这段代码是我 运行 在我的主要功能中(我认为你不需要知道所有的依赖项、原型等):

p_stack stack_temp = pstack_constructor();

// method 1
pstack_push(stack_temp, pcode_constructor_op(START));
// or method 2
pstack_push(stack_temp, 1, pcode_constructor_op(START));

结果方法一

OPERATOR 1
PUSH 2 OPERATOR: 1
PUSH 3
PUSH 4
PUSH 5
PUSH 2 OPERATOR: 1398167381
PUSH 4
PUSH 5
PUSH 6

分段错误(核心已转储)

结果方法2

OPERATOR 1
PUSH 1 ARGS SIZE: 1
Segmentation fault (core dumped)

代码中用到的其他函数

p_queue pqueue_constructor()
{
    p_queue queue;
    queue.length = 0;
    queue.head = queue.tail = NULL;
    return queue;
}

p_code pcode_constuctor()
{
    p_code code = ((p_code) malloc(sizeof(struct code)));
    code->operator = NOP;
    code->next = NULL;
    return code;
}

p_code pcode_constructor_op(p_operator operator)
{
    p_code code = pcode_constuctor();
    code->operator = operator;
    printf("OPERATOR %d\n", code->operator);
    return code;
}

注意事项

至于第一个版本,它依赖于有一个 NULL 指针来终止参数列表,并且您不在调用中提供这样一个终止 NULL 指针意味着您将当您超出传递的参数范围时,会有 未定义的行为

解决方法非常简单,只需要在调用中添加一个NULL指针即可:

pstack_push(stack_temp, pcode_constructor_op(START), NULL);

至于第二个版本的崩溃,你忘记了你应该使用的第一个 p_code 参数是 code 参数,你应该只在循环中最后得到下一个参数就像您在第一个函数中所做的那样。

也就是说你解引用的p_code指针是传递的secondp_code指针,但是你没有传递第二个指向undefined的指针行为和崩溃。