C栈实现。有关取消引用和双指针的问题

时间:2019-10-30 20:33:10

标签: c stack dereference

大家好。我是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");
   } 
}

1 个答案:

答案 0 :(得分:0)

这都是非常基本的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)的工作是分配一个新节点,使其指向当前的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。

与后面的代码相同。

这就是说,我认为实现堆栈要容易得多...;-)