将值推送到队列(链接列表)的前面时发生写访问冲突(@ 0xCDCDCDCD)

时间:2019-05-08 06:44:39

标签: c

我不确定为什么,但是当代码到达queue->tail->next = newLink;

void listQueueAddBack (struct Queue* queue, TYPE value) {
    /* FIXME: You will write this function */
    assert (queue != 0);
    struct Link* newLink = (struct Link*) malloc (sizeof (struct Link));
    assert (newLink != NULL);
    newLink->value = value;
    queue->tail->next = newLink;
    queue->tail = newLink;
}

我收到写访问冲突(地址0xCDCDCDCD)。我是否意外传递了空指针?我对C还是有点陌生​​,所以这对我来说是一种学习经验。

我也修改了listQueueIsEmpty,因为它存在读取访问冲突,但是我似乎已经克服了这一点。现在我是真正的推动者。

我不确定这是否太多,但是我真的不知道是什么原因造成的,因此这里是代码文件的所有有用内容。我不希望别人为我做功课,但是如果有任何超大代码错误,请告诉我,因为它可以帮助我学习将来的C项目。我试图将其折叠一点,所以没有人需要做100米的滚动才能到达底部(虽然时间不长,但仍然如此)

#include <assert.h>
#include <stdlib.h>
#include <stdio.h>

#ifndef TYPE
#define TYPE int
#endif

// Single link
struct Link {
    TYPE value;
    struct Link* next;
};

// Single linked list with head and tail pointers
struct Queue {
    struct Link* head;
    struct Link* tail;
};

// Stack with two Queue instances
struct Stack {
    struct Queue* q1;
    struct Queue* q2;
};

/**
    Internal func allocates the queue's sentinel. Sets sentinels' next to null,
    and queue's head and tail to the sentinel.
    param:  queue   struct LinkedList ptr
    pre:    queue is not null
    post:   queue sentinel not null
            sentinel next points to null
            head points to sentinel (always)
            tail points to sentinel (always point to last link unless empty)
 */
void listQueueInit(struct Queue* queue) 
{
    /* FIXME: You will write this function */
    assert(queue != 0);

    struct Link* sentinel = (struct Link*)malloc (sizeof (struct Link));
    assert (sentinel != 0);

    sentinel->next = 0;
    queue->head = sentinel;
    queue->tail = sentinel;
}

/**
    Allocates and initializes a queue.
    pre:    none
    post:   memory allocated for new struct Queue ptr
            queue init (call to _initQueue func)
    return: queue
 */
struct Queue* listQueueCreate() 
{

     /* FIXME: You will write this function */
    struct Queue* queue = (struct Queue*) malloc (sizeof (struct Queue));
    listQueueInit (queue);
    return queue;
}

/**
    Adds a new link with the given value to the back of the queue.
    param:  queue   struct Queue ptr
    param:  value   TYPE
    pre:    queue is not null
    post:   link is created with given value 
            link is added after the current last link (pointed to by queue tail)
 */

void listQueueAddBack (struct Queue* queue, TYPE value) 
{
    /* FIXME: You will write this function */
    assert (queue != NULL);
    assert (queue->tail != NULL);
    struct Link* newLink = (struct Link*) malloc (sizeof (struct Link));
    assert (newLink != NULL);
    newLink->value = value;
    newLink->next = NULL;
    queue->tail->next = newLink;
    queue->tail = newLink;
}

/**
    Returns the value of the link at the front of the queue.
    param:  queue   struct Queue ptr
    pre:    queue is not null
    pre:    queue is not empty (i.e., queue's head next pointer is not null)
    post:   none
    ret:    first link's value 
 */
TYPE listQueueFront(struct Queue* queue) 
{

   /* FIXME: You will write this function */
    assert (queue != NULL);
    assert (listQueueIsEmpty(queue) != 1);
    return ((queue->head)->next)->value;
}

/**
    Removes the link at the front of the queue and returns the value
    of the removed link.
    param:  queue   struct Queue ptr
    pre:    queue is not null
    pre:    queue is not empty (i.e., queue's head next pointer is not null)
    post:   first link is removed and freed (call to removeLink)
 */
int listQueueIsEmpty (struct Queue* queue);
TYPE listQueueRemoveFront(struct Queue* queue) 
{
    /* FIXME: You will write this function */
    assert (queue != 0);
    assert (!listQueueIsEmpty(queue));
    struct Link* toDelete = queue->head->next;
    if (toDelete == queue->tail) {
        queue->tail = queue->head;
    }
    else {
        queue->head->next = toDelete->next;
    }
    return toDelete;
    free (toDelete);
}

/**
    Returns 1 if the queue is empty and 0 otherwise.
    param:  queue   struct Queue ptr
    pre:    queue is not null
    post:   none
    ret:    1 if queue head next pointer is null (empty); 
            otherwise 0 (not null; not empty)
 */
int listQueueIsEmpty(struct Queue* queue) 
{
    /* FIXME: You will write this function */
    assert (queue != NULL);
    assert (queue->tail != NULL);
    if ((queue->head)->next == NULL) {
        return 1;
    }
    else {
        return 0;
    }
}

/**
    Deallocates every link in the queue including the sentinel,
    and frees the queue itself.
    param:  queue   struct Queue ptr
    pre:    queue is not null
    post:   memory allocated to each link is freed
            " " sentinel " "
            " " queue " "
 */
void listQueueDestroy(struct Queue* queue) 
{

        assert(queue != NULL);
    while(!listQueueIsEmpty(queue)) {
        listQueueRemoveFront(queue);
    }
    free(queue->head);
    free(queue);
    queue = NULL;

}

/**
    Allocates and initializes a stack that is comprised of two 
    instances of Queue data structures.
    pre:    none
    post:   memory allocated for new struct Stack ptr
            stack q1 Queue instance init (call to queueCreate func)
            stack q2 Queue instance init (call to queueCreate func)
    return: stack
 */
struct Stack* listStackFromQueuesCreate() 
{
     /* FIXME: You will write this function */
    struct Stack* stack = (struct Stack*) malloc (sizeof (struct Stack));
    stack->q1 = listQueueCreate();
    stack->q2 = listQueueCreate();
    return (stack);
};

/**
    Deallocates every link in both queues contained in the stack,
    (inc.the sentinel), the queues themselves and the stack itself.
    param:  stack   struct Stack ptr
    pre:    stack is not null
    pre:    queues are not null
    post:   memory allocated to each link is freed along with the 
            two queues and stack themselves

    Note that I checked that q1 and q2 are not null in this function
    also when I could have just left the assertion to fail in queueDestroy
    if either were pointing to null, but I thought it best to be explicit,
    albeit slightly repetitive.
 */
void listStackDestroy(struct Stack* stack)
{
    assert(stack != NULL);
    assert(stack->q1 != NULL && stack->q2 != NULL);
    listQueueDestroy(stack->q1);
    listQueueDestroy(stack->q2);
    free(stack);
    stack = NULL;
}

/**
    Returns 1 if the stack is empty and 0 otherwise.
    param:  stack   struct Stack ptr
    pre:    stack is not null
    post:   none
    ret:    1 if q1 is empty; else, 0
 */
int listStackIsEmpty(struct Stack* stack)
{

    /* FIXME: You will write this function */
    assert (stack != NULL);
    if (listQueueIsEmpty (stack->q1)) {
        return 1;
    }
    else {
        return 0;
    }
}

/**
    This internal function swaps what q1 and q2 pointers, such that
    q1 points to q2 and q2 points to q1.
    param:  stack   struct LinkedList ptr
    param:  value   TYPE
    pre:    stack is not null
    post:   q1 points to the actual 'stack' with links
 */
void listSwapStackQueues(struct Stack* stack)
{
    /* FIXME: You will write this function */
    assert (stack != 0);
    struct Queue* temp = stack->q1;
    stack->q1 = stack->q2;
    stack->q2 = temp;
}

/**
    Adds a new link with the given value to the back of the Queue q2.
    Then while Queue q1 isn't empty, the first link of the queue is 
    dequeued/removed and added to the back of Queue q2, so that in
    the end, Queue q2 has the new order to represent the stack properly
    with the new value at the front of the queue.
    param:  stack   struct LinkedList ptr
    param:  value   TYPE
    pre:    stack is not null
    post:   new link is created w/ given value and added to end of q2
            the first link of q1 is removed and added to end of q2 until
            it's empty
            q1 and q2 are swapped
 */
void listStackPush(struct Stack* stack, TYPE value) 
{
    /* FIXME: You will write this function */
    assert (stack != NULL);
    listQueueAddBack (stack->q2, value);
    while (!listQueueIsEmpty(stack->q1))
    {
        TYPE valueTemp = listQueueRemoveFront (stack->q1);
        listQueueAddBack (stack->q2, valueTemp);
    }
    listSwapStackQueues (stack);
}

/**
    Removes the link at the top of the stack and returns its value.
    param:  stack   struct Stack ptr
    pre:    stack is not null
    pre:    stack is not empty
    post:   first link is removed and freed (call to removeLink)
    ret:    value of the removed link
 */
TYPE listStackPop(struct Stack* stack) 
{
    /* FIXME: You will write this function */
    assert (stack != 0);
    assert (!listQueueIsEmpty (stack->q1));
    return listQueueRemoveFront (stack->q1);
}

/**
    Returns the value of the link at the top of the stack.
    param:  stack   struct Stack ptr
    pre:    stack is not null
    pre:    stack is not empty
    post:   none
    ret:    first link's value 
 */
TYPE listStackTop(struct Stack* stack) 
{
    /* FIXME: You will write this function */
    assert (!listQueueIsEmpty (stack->q1));
    assert (stack != 0);
    return listQueueFront (stack->q1);
}

/**
    Used for testing the stack from queue implementation.
 */

void assertTrue(int pred, char* msg) 
{
    printf("%s: ", msg);
    if(pred)
        printf("\tPASSED\n");
    else
        printf("\tFAILED\n");
}

int main() 
{
    struct Stack* s = listStackFromQueuesCreate();
    assert(s);
    printf("\n-------------------------------------------------\n"); 
    printf("---- Testing stack from queue implementation ----\n");
    printf("-------------------------------------------------\n"); 
    printf("stack init...\n");
    assertTrue(listStackIsEmpty(s) == 1, "stackIsEmpty == 1");

    printf("\npushing 4, 5, -300...\n");
    listStackPush(s, 4);
    listStackPush(s, 5);
    listStackPush(s, -300);

    assertTrue(listStackIsEmpty(s) == 0, "stackIsEmpty == 0");
    assertTrue(listStackPop(s) == -300, "\npopping; val == -300");
    assertTrue(listStackPop(s) == 5, "popping; val == 5");
    assertTrue(listStackTop(s) == 4, "top val == 4\t");
    assertTrue(listStackPop(s) == 4, "popping; val == 4");
    assertTrue(listStackIsEmpty(s) == 1, "stackIsEmpty == 1");
    // listStackPop(s);     // should fail assert
    // listStackTop(s);     // should fail assert

    printf("\npushing 0-9...\n");
    for(int i = 0; i < 10; i++) {
        listStackPush(s, i);
    }
    assertTrue(listStackTop(s) == 9, "top val == 9\t");

    listStackDestroy(s);

    return 0;
}

〜-〜-〜-编辑1-〜-〜-〜

上面更新的代码,现在应该已经返回。

此外,我目前将Visual Studio 2019用于编译器。我的大学有一个Unix编译器,但是我还没有测试它,因为必须先将VPN插入其中,否则就不能。我最终将对其进行测试,只是没有像执行此代码那样。

〜-〜-〜-编辑2-〜-〜-〜 再次添加了代码编辑(这次固定了返回derp)

对于错误的数量感到抱歉,由于我不得不以一种很奇怪的顺序上初中,因此我回到了C编码中,这主要是由于类的可用性,因为我的数据结构通常不会有效期至明年秋天。我只是碰巧很幸运,然后转移到Uni并在那里进入了

2 个答案:

答案 0 :(得分:0)

您的代码有多个问题。但是您的特定问题是由listSwapStackQueues引起的。

您正在为临时队列分配一些内存,然后将指向该内存的指针分配给q2。然后,使用free释放内存,使q2指向不再存在的内存。

实际上,您根本不需要在这里分配任何内存,因为您可能想要的只是交换指针。在这种情况下,您需要做的只是:

struct Queue *temp = stack->q1;    
stack->q1 = stack->q2;
stack->q2 = temp;

您是否正在使用调试器来调试程序?如果不这样做,则应该熟悉一下。如果没有适当的调试器,很难找到这样的内存错误。

您将遇到更多此类问题,因此拥有一个良好的调试器非常重要。如果您使用的是Windows,我建议您只购买Visual Studio,因为它是免费的并且功能强大。

编辑:

在其他人给出的答案旁边,还有以下内容: 当您将新节点添加到列表中时,接下来将其初始化为NULL。即在您的函数listQueueAddBack中:

    struct Link* newLink = (struct Link*) malloc (sizeof (struct Link));
    assert (newLink != NULL);
    newLink->value = value;
    // Initialize next. 
    newLink->next = NULL;

答案 1 :(得分:0)

  1. 交换队列中存在一个问题:

    void listSwapStackQueues(结构堆栈*堆栈) {     / * FIXME:您将编写此函数 /     断言(堆栈!= 0);     struct Queue temp =(struct Queue *)malloc(sizeof(struct Queue));     temp = stack-> q1;     stack-> q1 =堆栈-> q2;     stack-> q2 = temp;     免费(临时); }

这将释放stack->q1指针,因此使列表头无效并向上泄漏内存。正在执行:

type *pnt = malloc(...); 
pnt = ...

总是错误的并且会泄漏内存。只需交换指针,而不执行任何malloc和free操作即可:

void listSwapStackQueues(struct Stack* stack)
{
    assert (stack != 0);
    struct Queue* temp;
    temp = stack->q1;
    stack->q1 = stack->q2;
    stack->q2 = temp;
}
  1. 在断言内的listQueueIsEmpty内部传递给listQueueRemoveFront的指针类型无效:

    TYPE listQueueRemoveFront(结构队列*队列) {     断言(listQueueIsEmpty(queue-> head)); //无效

您要传递队列,即。 listQueueIsEmpty(queue),转到该功能。此外,列表队列在删除时为空,因此您可能想对表达式求反:

TYPE listQueueRemoveFront(struct Queue* queue)
{
    assert (!listQueueIsEmpty(queue));

还请记住向前声明函数,以便编译器可以警告您:

int listQueueIsEmpty(struct Queue* queue);
TYPE listQueueRemoveFront(struct Queue* queue)
{
    assert (!listQueueIsEmpty(queue));
  1. 您的return函数中没有listQueueRemoveFront语句。因此,该代码无效并调用未定义的行为:

    TYPE listQueueRemoveFront(结构队列*队列) {     //这里没有返回 }

    ..稍后在Push中...     TYPE valueTemp = listQueueRemoveFront(stack-> q1);

请记住始终在启用警告的情况下进行编译(使用gcc-Wall -Wextra -Werror)并修复所有警告。在启用警告的情况下进行编译时,编译器会解决此问题:

1.c: In function ‘listQueueFront’:
1.c:98:13: warning: implicit declaration of function ‘listQueueIsEmpty’; did you mean ‘listQueueInit’? [-Wimplicit-function-declaration]
     assert (listQueueIsEmpty(queue) != 1);
             ^~~~~~~~~~~~~~~~
1.c: In function ‘listQueueRemoveFront’:
1.c:123:1: warning: control reaches end of non-void function [-Wreturn-type]
 }