理解指针和C中的堆栈

时间:2013-11-16 23:34:52

标签: c

我正在编写一个程序,使用堆栈将反向抛光符号输入从命令行转换为中缀符号。它没有解决rpn表示法,它只是用中缀表示法输出输出。我一直遇到堆栈行为的问题。该程序不包含所有代码函数(为简单起见)。我省略了打印数据和执行输入错误检查的函数,但它们不会更改堆栈。 因此,假设输入了正确的数据,例如2 5 +,那么我们可以继续讨论该程序的行为方式。该程序使用三个文件,客户端,接口和实现文件。当从命令行输入输入时,程序循环argv []数组并检查数据是否为数字,如果是,则它会在创建的堆栈上推送数字数据。如果某些数据不是数字,那么这意味着我们有一个算术运算符字符。发生这种情况时,会从堆栈中弹出两个值,并与算术运算符函数合并在一起。然后合并的结果被推到堆栈上。表格4 5 +的输入正常工作正确输出4 + 5,以及输入形式9 8 + 6 - 输出9 + 8 - 6工作。

当输入这个表格3 4 + 5 8 + +时出现问题,我得到输出5 + 8 + 5 + 8,但正确的输出应该是3 + 4 + 5 + 8.这可能是由于我传递给push_stack函数的参数,这是一个在传入之前合并的字符串。我是学习指针的新手,所以也许有人可以告诉我堆栈中发生了什么。我包含了三个文件,其中包含修改堆栈的函数和调用。任何帮助表示赞赏

//stackfunctions.c file
#include "stackfunctions.h"

struct stackelements{
   SType items[STORAGE];
   int top;
};

pointer_stack stack_new(){
    pointer_stack stack = malloc(sizeof(struct stackelements));
    stack->top = -1; // empty initially
    return stack;
}

int stack_push(pointer_stack stack, Stype stack_value){
    if(stack->top == STORAGE - 1){
       return 0;
     }

     stack->top++;
     stack->items[stack->top] = stack_value;
     return 1;
}

Stype stack_pop(pointer_stack stack){
     if(stack->top == -1)
         abort();//
     stack->top--;
     return stack->items[stack->top+1];
}

void stack_print(pointer_stack stack){
    int i;
    printf("\n--------Top------------\n");

    for(i = stack->top; i >= 0; i--) {
        printf("   %s\n", stack->items[i]);
     }
     printf("---------Bottom----------\n");
}

stackfunctions.h文件

//stackfunctions.h file
#include<stdio.h>
#include<stdlib.h>

#define STORAGE 128

typedef struct stackelements *pointer_stack;

typedef char *Stype;

extern pointer_stack stack_new();

extern int stack_push(pointer_stack stack, Stype stack_value);

extern Stype stack_pop(pointer_stack stack);

extern void stack_print(pointer_stack stack);

主程序文件

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stackfunctions.h"

int main(int argc, char *argv[]){

    int i,j;
    float x = 0;
    char *operator[1], *point_b[1], *point_a[1];
    char result[100], a[30], b[30], op[3];

    pointer_stack stackP;

    stackP = stack_new(); // Create new stack

    // Loop through command line argument input

    for(i=1; i < argc; i++){     
        // Check to see if input is numeric.
        if(sscanf(argv[i], " %f ", &x)){
            stack_push(stackP, argv[i]); // If input is numeric push them into stack.

        else{ // Input is an operator, then we must

            operator[0] = argv[i];

            //Pop two items off stack

            point_b[0] = stack_pop(stackP);

            // create strings from pointer returned by atack_pop function

            memcpy(b, point_b[0] , strlen(point_b[0])+1);

            point_a[0] = stack_pop(stackP);

            memcpy(a, point_a[0] , strlen(point_a[0])+1);

            memcpy(op, operator[0] , strlen(operator[0])+1);

            // The we have to merge the popped off values and push the new 
            // result back on stack.

            sprintf(result, "%s %s %s", a, op, b);

            stack_push(stackP, result);

            stack_print(stackP); // Function that prints the stack, function
                                 // not included in other files, but it only
                                 // prints out the stackP pointer values. I use this
                                 // to check the output.

     }// close else

  }// close for loop

  free(stackP);

  return 0;
}

2 个答案:

答案 0 :(得分:1)

看起来你正在破坏你的存储空间(result)。

您将结果存储到result,然后将其推送到堆栈中。精细。 但是你只保存指向result的指针。在使用3 4 +的第一个参数后,结果应为3 + 4。但是,当您打开下一个参数时,将5 8 +转换为结果。但是,因为您只有一个结果数组,所以您将覆盖已经拥有的3 + 4结果。

相反,您可能希望每次推入堆栈时分配空间并在弹出时释放该内存。

答案 1 :(得分:1)

您永远不会初始化operator数组。那么,您希望通过operator[0]来电从memcpy复制的内容完全不清楚。如果您使用的operator[0]值包含未初始化的垃圾,您是如何期望这样的?您的代码生成您描述的结果的事实实际上表明您发布的代码不是真实的。在您的真实代码中,您可能记得给operator[0]一个有意义的值。

将指向本地result数组的指针推入堆栈。然后重用result数组。这显然会“改变”你之前推入堆栈的内容。这是您描述的错误结果的实际原因。

此外,函数sscanf可以在早期匹配失败的情况下返回非零EOF值。这与if (sscanf(...条件无法正常配合。它会假设读取了一个数字,而实际上却没有。

代码中还有许多其他“怪异”的东西,不一定是错误,但无论如何都值得一提。

为什么sscanf格式在开头和结尾都包含额外的空格?为什么operatorpoint_bpoint_a被声明为数组(每个1个元素)?通过strcpy - 和 - strlen组合“手动”实施memcpy功能有什么意义?