今天是个好日子。我是C语言的新手,而且堆栈溢出,所以请对我轻松一点:)
我对C中的此堆栈代码有几个疑问:

1)push(&stackPtr, value);为什么stackPtr必须具有&符号?没有它会得到什么功能?

2)topPtr = newPtr;为什么topPtr必须是* topPtr?没有它的代码又是怎么回事?

3)*topPtr = (*topPtr)->nextPtr;为什么* topPtr必须具有*?没有*号怎么办?

感谢您提前提出任何答案。

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

// self-referential structure
struct stackNode {
   int data; // define data as an int
   struct stackNode *nextPtr; // stackNode pointer
};

typedef struct stackNode StackNode; // synonym for struct stackNode
typedef StackNode *StackNodePtr; // synonym for StackNode*

// prototypes
void push(StackNodePtr *topPtr, int info);
int pop(StackNodePtr *topPtr);
void printStack(StackNodePtr currentPtr);
void instructions(void);

// function main begins program execution
int main(void)
{
   StackNodePtr stackPtr = NULL; // points to stack top
   int value; // int input by user

   instructions(); // display the menu
   printf("%s", "? ");
   unsigned int choice; // user's menu choice
   scanf("%u", &choice);

   // while user does not enter 3
   while (choice != 3) {

      switch (choice) {
         // push value onto stack
         case 1:
            printf("%s", "Enter an integer: ");
            scanf("%d", &value);
            push(&stackPtr, value);
            printStack(stackPtr);
            break;
         // pop value off stack
         case 2:
            // if stack is not empty
            if (stackPtr != NULL) {
               printf("The popped value is %d.\n", pop(&stackPtr));
            }

            printStack(stackPtr);
            break;
         default:
            puts("Invalid choice.\n");
            instructions();
            break;
      } // end switch

      printf("%s", "? ");
      scanf("%u", &choice);
   }

   puts("End of run.");
}

// display program instructions to user
void instructions(void)
{
   puts("Enter choice:\n"
      "1 to push a value on the stack\n"
      "2 to pop a value off the stack\n"
      "3 to end program");
}

// insert a node at the stack top
void push(StackNodePtr *topPtr, int info)
{
   StackNodePtr newPtr = malloc(sizeof(StackNode));

   // insert the node at stack top
   if (newPtr != NULL) {
      newPtr->data = info;
      newPtr->nextPtr = *topPtr;
      topPtr = newPtr;
   }
   else { // no space available
      printf("%d not inserted. No memory available.\n", info);
   }
}

// remove a node from the stack top
int pop(StackNodePtr *topPtr)
{
   StackNodePtr tempPtr = *topPtr;
   int popValue = (*topPtr)->data;
   *topPtr = (*topPtr)->nextPtr;
   free(tempPtr);
   return popValue;
}

// print the stack
void printStack(StackNodePtr currentPtr)
{
   // if stack is empty
   if (currentPtr == NULL) {
      puts("The stack is empty.\n");
   }
   else {
      puts("The stack is:");

      // while not the end of the stack
      while (currentPtr != NULL) {
         printf("%d --> ", currentPtr->data);
         currentPtr = currentPtr->nextPtr;
      }

      puts("NULL\n");
   }
}

最佳答案

这都是非常基本的C语言,因此我会尽量保持清晰,但是我建议您仔细阅读有关该主题的参考书。

该代码定义了一个包含某些数据的结构stackNode和一个指向该相同结构的“指针”。

因为stackNode是结构,所以当您将其作为参数传递给函数时,编译器会创建它的副本并将其提供给函数。这称为“通过副本传递参数”。范例:

StackNode node;
foo(node) ;

void foo(StackNode  n) {
   /* foo() function can use the parameter n which is a local copy of node.
      you can modify n in the foo() function, that will not modify the node variable */
}


这意味着该函数无法修改您的原始数据。它可以修改函数的本地副本,该副本在函数末尾丢失。

如果要修改给定的参数,则必须“按地址”而不是“按副本”传递参数。您可以这样进行:

StackNode node;
foo(&node) ;

void foo(StackNode  *n) {
   /* foo() function accesses the node variable via its address n. (*n) represents
      the content at address n, which is node. */
}


在此代码中,函数foo()获取StackNode的地址(而不是StackNode的副本)。通过“取消引用”地址,您可以访问指针“指向”的内容,因此可以“实际”对其进行修改。 “取消引用”由“ *”运算符执行,而“&”运算符给出变量的“引用”(地址)。

所以现在,到您的代码。我会以稍微不同的顺序回答您的问题,以使其更清楚(我认为)。

void push(StackNodePtr *topPtr, int info)的作用是malloc一个新节点,使其指向当前的topPtr,然后修改topPtr以指向该新节点。

因此,它修改了topPtr。

因此,topPtr需要通过引用传递。

因此,您需要void push(StackNodePtr *topPtr, int info)而不是void push(StackNodePtr topPtr, int info)

因此,您需要使用push(&stackPtr ,value)进行调用

如果您呼叫push(stackPtr ,value),则:


首先,您的编译器应该抱怨(至少发出警告)
当您修改内存的未知区域时,您将有一天或一天​​崩溃


您现在还应该了解为什么需要(*topPtr) = newPtr而不是topPtr = newPtr的原因。因为您要修改stackPtr,所以需要取消引用topPtr。

在后面的代码中相同。

这就是说,我可以想到实现堆栈要容易得多... ;-)

关于c - C栈实现。有关取消引用和双指针的问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58633245/

10-09 09:40