【发布时间】:2021-07-16 05:31:43
【问题描述】:
现在在我们的课堂上,我们正在学习节点和链表,并且正在开发我们的第一个链表程序。
老师给了我们以下指导:
确保您的
main函数将接受来自 STDIN 的 10 个字符并使用这些字符创建一个链表(这样您的节点将有一个 char 成员)。然后,添加一个名为reverse的附加函数。 reverse 函数的目的是创建一个链表的副本,其中节点反转。最后,打印出原链表和反向链表。
我已经把它全部写出来了,而且我已经编译它没有错误 - 但程序没有按预期工作,我不完全确定为什么。我确信这与我如何设置指针以“遍历”节点有关 - 因为我放入的调试显示它每个用户输入字母循环两次。规范是我们只应该使用一个函数,我们将Node* 传递给函数,它返回相同的值。该函数无法打印出任何内容 - 只能创建与第一个相反的第二个列表。
任何帮助将不胜感激,我在这方面还不是很擅长,我确信我犯了一些相当愚蠢的错误。
#include <stdio.h>
#include <stdlib.h>
//struct declaration with self-reference to make a linked list
struct charNode {
char data;
struct charNode *nextPtr;
struct prevNode *prevPtr;
};
typedef struct charNode Node; //makes Node an alias for charNode
typedef Node *NodePtr; //makes NodePtr an alias for a pointer to Node (I think?)
//function declaration for a reverse function
Node* reverse(Node *stPtr);
int main(void)
{
//main function takes 10 letters and puts them in a linked list
//after that, it calls the reverse function to create a reversed list of those characters
//lastly it prints both lists
NodePtr newNode = NULL;
char input;
Node* revStart;
unsigned int counter = 0;
printf("Enter 10 letters to make a list: ");
NodePtr currentPtr = NULL; //sets currentPointer to startNode.
NodePtr previousPtr = NULL; //set previousPointer to null to start
while(counter<= 10)
{
scanf("%c", &input); //gather next letter
NodePtr newNode = malloc(sizeof(Node)); //creates a new node
if (newNode != NULL) //checks to make sure the node was allocated correctly
{
newNode->data = input; //makes the new node's data == input
newNode->nextPtr = NULL; //makes the nextPtr of the newNode NULL
}
currentPtr = newNode; //sets currentPtr to the address of the newNode
if(previousPtr == NULL) { //first time around previousPtr == NULL
newNode->nextPtr = newNode;
previousPtr = newNode; //sets previousPtr to the address of the new node (1st time only)
} else { //afterwards, currentPtr won't be NULL
previousPtr->nextPtr = currentPtr; //last node's pointer points to the current node
previousPtr = newNode; //update previous pointer to the current node
}
++counter;
//debug
printf("\nLoop #%d\n", counter);
}
revStart = reverse(newNode);
puts("The list is: ");
while (newNode != NULL){
printf("%c --> ", newNode->data);
currentPtr = currentPtr->nextPtr;
}
puts("NULL\n");
}
//reversing the nodes
Node* reverse(Node *stPtr)
{
//make a new node
NodePtr currentPtr = stPtr->nextPtr; //get the next letter ready (this will point to #2)
NodePtr prevRevPtr = NULL; //previous reverse node pointer
Node* revStart;
for(unsigned int counter = 1; counter <= 10; ++counter)
{
NodePtr revNode = malloc(sizeof(Node));
if(revNode != NULL) //if reverseNode is allocated...
{
if(prevRevPtr = NULL) //if previousReversePointer = NULL it's the "first" letter
{
revNode->data = stPtr->data; //letter = current letter
revNode->nextPtr = NULL; //this is the "last" letter, so NULL terminate
prevRevPtr = revNode; //previousReversePointer is this one
}else //after the first loop, the previous ReversePointer will be set
{
revNode->data = currentPtr->data; //set it's data to the pointer's data
revNode->nextPtr = prevRevPtr; //reverseNode's pointer points to last node entered
currentPtr = currentPtr->nextPtr; //moves to next letter
prevRevPtr = revNode; //changes previous reverse node to current node
if(counter == 10)//on the last loop...
{
revStart = revNode; //set revStart as a pointer to the last reverse node
//which is technically the "first"
}
}
}
}
return revStart;
}
【问题讨论】:
-
首先,您不需要在您的反向函数中有
counter循环或执行任何malloc调用。除非您还想制作列表的副本,否则列表反转不需要额外的内存。您需要做的就是重新链接指针。另请注意,在您当前的代码中,revStart仅在您的计数器达到 10 时才设置。这非常危险,因为否则它未初始化并用于返回。更不用说您假设列表具有特定长度。您的测试prevRevPtr = NULL是一项作业。使用==运算符进行比较。 -
您的代码过于复杂。您不需要双链接来反转列表。忽略“prev”指针并像这样反向:
Node *rev = NULL; while (list) { /* pop from list */ Node *elt = list; list = list->next; /* push onto rev */ elt->next = rev; rev = elt; } // rev now points to head of reversed list现在您可以遍历反向列表一次并修复“prev”指针,如果您真的需要它们。还有几行。 -
如果你想争辩说,列表反转函数有一个前提条件是它只反转长度为 10 的列表,在较短的列表上有未定义的行为,并且只部分反转较长的列表,我我不会坐在这里和你在 cmets 争论。你已经下定决心了。
-
while (list)等价于while (list != NULL)。与 Python 无关。 -
我的意思是执行列表反转的函数应该是通用的。它不需要知道您的列表是否有 10 个节点、一百万个节点、1 个节点或为空。无论如何它都应该工作。这样也会更简单。
标签: c linked-list nodes