使用相同程序的单个队列和多个队列不起作用

时间:2013-08-27 19:34:54

标签: c data-structures crash queue

这是两个以简单形式实现队列数据结构的程序

  • 第一个:

    定义一个队列,它完美地运作

  • 第二个:

    定义多个队列,并在执行时崩溃

函数在两个程序中都是相同的,除了main()是实现 有点不同。

所以这里的问题是:为什么第二个代码不起作用?

*这里是代码*

代码1:

/*
 Single queue  -- this work perfectly
*/
#include <stdio.h>
#define Q_MAX_SIZE 255

struct queue {
    int* pointer;
    int* currentValue;
    int max, count, theQueue[Q_MAX_SIZE];
};

//prototyps
void initQueue(struct queue*);
unsigned short pushQueue(struct queue*, int);
int* popQueue(struct queue*);

int main(void) {
    int j;
    struct queue q;

    initQueue(&q);

    for (j = 0; j < 6; j++)
        pushQueue(&q, j);

    int* inputobj = popQueue(&q);
    while (inputobj != NULL)
    {
        printf("%d  ", *inputobj);
        inputobj = popQueue(&q);
    }

    printf("\n\ndone..Queue is empty\n");

    return 0;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

void initQueue(struct queue *Q)
{
    Q->pointer = Q->theQueue;
    Q->max = Q_MAX_SIZE;
    Q->count = 0;
}

unsigned short pushQueue(struct queue *Q, int input) {
    if (Q->count < Q->max)
    {
       *Q->pointer = input;
        Q->pointer++;
        Q->count++;
        return 1;
    }
    else
        return 0;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

int* popQueue(struct queue *Q) {
    int i;
    if (Q->count > 0)
    {

       *Q->currentValue = *Q->theQueue;
        Q->pointer--;
        Q->count--;

        for (i = 0; i < Q->count; i++)
        {
            int* currentPtr = Q->theQueue + i;
            int* nextPtr = currentPtr + 1;
            *currentPtr = *nextPtr;
        }

        return Q->currentValue;
    }
    else
        NULL;
}

代码2:

/*
 Multiple queues  -- this not work and crash at execution
*/
#include <stdio.h>
#define Q_MAX_SIZE 255

struct queue {
    int* pointer;
    int* currentValue;
    int max, count, theQueue[Q_MAX_SIZE];
};

//prototyps
void initQueue(struct queue*);
unsigned short pushQueue(struct queue*, int);
int* popQueue(struct queue*);

int main(void) {
        int i, j;
    struct queue obj[5];

    for(i=0; i<5; i++)
    {
        initQueue(&obj[i]);

        for(j = 0; j<3; j++)
        {
            pushQueue(&obj[i], j);
        }
    }

    for(i=0; i<5; i++)
    {
        printf("Queue[%d]:\n", i);
        int* inputobj;
        inputobj = popQueue(&obj[i]);

        while(inputobj != NULL)
        {
            printf("Queue[No.%d] = %d\n", i, *inputobj);
            inputobj = popQueue(&obj[i]);
        }
        putchar('\n');
    }

    return 0;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

void initQueue(struct queue *Q)
{
    Q->pointer = Q->theQueue;
    Q->max = Q_MAX_SIZE;
    Q->count = 0;
}

unsigned short pushQueue(struct queue *Q, int input) {
    if (Q->count < Q->max)
    {
       *Q->pointer = input;
        Q->pointer++;
        Q->count++;
        return 1;
    }
    else
        return 0;
}

//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

int* popQueue(struct queue *Q) {
    int i;
    if (Q->count > 0)
    {

       *Q->currentValue = *Q->theQueue;
        Q->pointer--;
        Q->count--;

        for (i = 0; i < Q->count; i++)
        {
            int* currentPtr = Q->theQueue + i;
            int* nextPtr = currentPtr + 1;
            *currentPtr = *nextPtr;
        }

        return Q->currentValue;
    }
    else
        NULL;
}

更新:问题发生在initQueue(),并通过分配内存解决了问题  for Q->currentValue这里是编辑后的函数:

void initQueue(struct queue *Q)
{
    Q->currentValue = malloc(sizeof(int));
    Q->pointer = Q->theQueue;
    Q->max = Q_MAX_SIZE;
    Q->count = 0;
}

4 个答案:

答案 0 :(得分:3)

正如两个答案已经说明的那样,问题是Q->current_value从未被赋值给它,因此它指向一个未定义的地址,并且每个解除引用如*Q->currentValue = ..都是未定义的行为。代码1看似有效的事实并不能证明任何其他因为由于UB的性质而没有保证行为,你的程序可能会或可能不会崩溃(或者你的狗可能会爆炸,龙会飞出你的鼻子......: - ))

当然,有多种解决方案都意味着不同的东西:

  1. 如果currentValue只保留某个值的副本,则可以是int currentValue而不是int *...,并且分配将是

    Q-&gt; currentValue = * Q-&gt; theQueue;

    ,return语句为return &Q->currentValue。在这种情况下,您将返回指向原始theQueue[0]

  2. 的指针
  3. 如果你想指向theQueue中的位置,Jim的anser告诉了正确的方法:

    Q-&gt; currentValue = Q-&gt; theQueue;

    在这种情况下,您将返回指向theQueue[0]值的指针(可能是您不想要的)

  4. 您可以将内存分配给Q->currentValue我的malloc( sizeof (int) );,然后保留分配原样。在这种情况下,您将返回指向原始theQueue[0]的指针,如(1)

答案 1 :(得分:1)

我认为这实际上是非常微妙的问题。问题(我认为)是popqueue()中的这一行:

*Q->currentValue = *Q->theQueue;

我仔细检查了你的初始代码(没有数组)也会出现故障。它不像你说的那样有效。你应该写:

Q->currentValue = Q->theQueue;

C可以通过指针稍微理解并适当地分配东西,但是当你添加另一个级别(数组)时,我认为赋值被强制转换为无效的东西。这是我的看法。我想我会提出赏金,这样你就可以得到更好的答案。

答案 2 :(得分:1)

首先,我不会尝试将这样的代码放在生产中。事情可以做得更简单,更清晰,更高效,更不容易出错。

我通过在尽可能少的地方改变事物来“修复”你的程序。必须清楚的是,这并不能使事情更加优雅。只有重新思考和重写才能让事情变得更加优雅。

您遇到的错误(包括第一个和第二个程序)都是常规popQueue。

  1. 在else子句中没有返回任何内容。你应该“返回NULL”。这至少是草率的编程。

  2. 例程返回1 2 3 4 5 5和1 2 2作为队列。这是因为Q-&gt; CurrentValue指向theQueue数组中的第一个位置,并且您向上移动所有值。这意味着CurrentValue事实指向下一个值。

  3. 解决方案(再次:它不优雅,也不会将其投入生产,但它对原始版本的改动很小)对你的问题是:

    1. 更改结构(保存实际的CurrentValue)

      struct queue
      {
        int* pointer;
        int currentValue;
        int max, count, theQueue[Q_MAX_SIZE];
      };
      
    2. 更改例程popQueue

      int* popQueue(struct queue *Q) {
          int i;
          if (Q->count > 0)
          {
      
              Q->currentValue = *Q->theQueue;
              Q->pointer--;
              Q->count--;
      
              for (i = 0; i < Q->count; i++)
              {
                  int* currentPtr = Q->theQueue + i;
                  int* nextPtr = currentPtr + 1;
                  *currentPtr = *nextPtr;
              }
      
              return &(Q->currentValue);
          }
          else
              return NULL;
      }
      
    3. 亲切的问候, PB

答案 3 :(得分:0)

无法访问位置Q-&gt; currentValue,这就是问题所在。它没有分配。

解决方案是在init例程中分配正确的内存部分:

Q = malloc(sizeof(struct queue));

也许还会在此之后初始化所有变量的值。