我不确定为什么,但是当代码到达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并在那里进入了
答案 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)
交换队列中存在一个问题:
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;
}
在断言内的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));
您的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]
}