C中的队列变量推送

时间:2015-08-10 09:22:01

标签: c variadic-functions

我有一个关于在用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));

结果方法1

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

注意

  • p_queuep_code始终是inizializated
  • 施展va_arg(vars, p_code)不要&#39;改变一切
  • p_queue不是指针,&#34; p&#34;记住我的概念&#34; pcode&#34; (p_queue包含p_code)

1 个答案:

答案 0 :(得分:2)

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

解决方案非常简单,只需在调用中添加NULL指针:

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

对于第二个版本中的崩溃,您忘记了您应该使用的第一个p_code参数是code参数,并且您应该只在循环中获得下一个参数,就像您一样做第一个功能。

这意味着您取消引用的p_code指针是传递的第二个 p_code指针,但是您没有传递第二个指针导致未定义的行为,崩溃。