C语言 索引在应该工作时不工作

nle07wnf  于 2022-12-11  发布在  其他
关注(0)|答案(1)|浏览(85)

我尝试将我用C++编写的数学求值转换为C。当我试图循环通过表达式时,遇到了一个问题,并得到了分段错误。
我的树目录

├── main.c
├── math
│   ├── include.h
│   └── main.c
├── stack
│   ├── include.h
│   └── main.c

我的堆栈头文件和源文件

//HEADER
#ifndef STACK_H
#define STACK_H 

#include <stdio.h>

typedef struct{
    int top, max_height;
    float data[];
}Stack;

void stack_push(Stack* st, float value);
Stack stack_init(int max);
void stack_replace_top(Stack* st, float value);
void stack_print(Stack* st);
float stack_pop(Stack* st);
int stack_full(Stack* st);
int stack_top(Stack* st);
int stack_height(Stack* st);
int stack_empty(Stack* st);

#endif
//SOURCE
#include <stdio.h>
#include <stdlib.h>

#include "include.h"

int stack_top(Stack* st){return st->top;}
int stack_height(Stack* st){return st->max_height;}
void stack_push(Stack* st, float value){
    st->data[st->top] = value;
    (st->top)++;
}
float stack_pop(Stack* st){
    (st->top)--;
    return (st->data[st->top]);
}
Stack stack_init(int max){
    return (Stack){0,max};
}
int stack_full(Stack* st){return (st->top >= st->max_height);}
void stack_replace_top(Stack* st, float value){
    st->data[st->top - 1] = value;
}
int stack_empty(Stack* st){return (st->top <= 0);}
void stack_print(Stack* st){
    int i;
    if(st->top == 0){
        printf("Stack Is Empty.\n");
    }else{
        printf("Stack Contents:\n");
        for(i=0;i<st->top;i++){
            printf("%g\t",st->data[i]);
        }
        printf("\n\n");
    }
}

我的数学源,标题没有任何重要的内容

#include <math.h>
#include <string.h>

#include "include.h"
#include "../stack/include.h"
#include "../utils/include.h"

static float precedence(char op){
    switch(op){
        case '+':case '-':return 1;
        case '*':case '/':return 2;
        case '^':case '%':return 3;
        default: return 0;
    }
    return 0;
}
static float apply_op(float a,float b,char op){
    switch(op){
        case '+': return a + b;
        case '-': return a - b;
        case '*': return a * b;
        case '/': return a / b;
        case '^': return pow(a, b);
        case '%': return fmod(a, b);
    }
    return 0;
}
float evaluate(char* text){
    //evaluate a given expression for example (5+5)*7^2
    char* token = strtok(text, " ");
    //we will use two stacks one for numbers and one for operators
    Stack values =stack_init(100);
    Stack ops = stack_init(100);
    int i=0,size = strlen(token);
    printf("Eval: %s\n",token);
    printf("4: %c\n",token[4]);
    char c;
    for(;i<size;i++){
        printf("s %d\n",size);
        printf("i %d\n",i);
        printf("c %c\n",c);
        c = token[i];
        printf("passed\n");

        //if the current character is a number, push it to stack for numbers
        switch(c){
            case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':{
                float val = 0;
                //there may be more than one digits in number
                while(i < size && c >= '0' && c <= '9'){
                    val = (val*10) + (c - '0');
                    c = token[i];
                    i++;
                }
                //push the number into stack for numbers
                stack_push(&values,val);
                //as we are also incrementing the i in above while loop we need to decrement it here
                i--;
                break;
            }
            case '(':{
                //if current character is an opening brace, push it to 'ops'
                stack_push(&ops,'(');
                break;
            }
            case ')':{
                while(!stack_empty(&ops) && stack_top(&ops) != '('){
                    float val2 = stack_pop(&values);
                    float val1 = stack_pop(&values);
                    char op = stack_pop(&ops);
                    stack_push(&values,apply_op(val1,val2,op));
                }
                //pop opening brace
                stack_pop(&ops);
                break;
            }
            case '+': case '-': case '*': case '/': case '^': case '%':{
                while(!stack_empty(&ops) && precedence(stack_top(&ops)) >= precedence(c)){
                    float val2 = stack_pop(&values);
                    float val1 = stack_pop(&values);
                    char op = stack_pop(&ops);
                    stack_push(&values,apply_op(val1,val2,op));
                }
                //push current operator to 'ops'.
                stack_push(&ops,c);
                break;
            }
        }
    }
    // Entire expression has been parsed at this point, apply remaining ops to remaining values
    while(!stack_empty(&ops)){
        float val2 = stack_pop(&values);
        float val1 = stack_pop(&values);
        char op = stack_pop(&ops);
        stack_push(&values,apply_op(val1,val2,op));
    }
    // Top of 'values' contains result, return it
    
    return stack_pop(&values);
}

我的错误出现在数学源文件中for循环的“evaluation”函数中。当我的循环第二次运行时,我得到了错误。我真的很困惑,因为我传入的字符串是“20*2+1”,大小是6,但当我的循环第二次运行时,索引是4,所以它应该工作。我希望有人能帮助我解决我的错误。

h79rfbju

h79rfbju1#

问题似乎与索引无关。相反,您的堆栈实现是虚假的。这...

typedef struct{
    int top, max_height;
    float data[];
}Stack;

...声明了一个具有 flexible array member 的结构类型。所涉及的灵活性是,您可以使用为结构的任何给定示例分配的全部空间,就好像它的data成员是用维度声明的,该维度使它尽可能多地填充该空间。这只在与动态内存分配结合使用时才有用,而您目前没有使用动态内存分配。并且所产生的动态分配对象不能有效地通过值来传递或返回。
您有两个主要选项:
1.如果你想继续使用FAM,那么stack_init()必须被修改为动态分配足够大的示例,并返回一个指向分配结果的指针。例如:

Stack *stack_init(int max) {
    Stack *rval = malloc(sizeof(*rval) + max * sizeof(rval->data[0]));

    if (!rval) {
        abort();
    }

    rval->top = 0;
    rval->max = max;

    return rval;
}

需要进行其他更改以适应返回类型的更改,并在不再需要动态分配的堆栈对象时释放它们。

1.将Stack.data变更为指标,并动态配置堆栈空间。例如:

typedef struct {
    int top, max_height;
    float *data;
} Stack;

// ...

Stack stack_init(int max) {
    float *data = malloc(max * sizof(*data));

    if (!data && max != 0) {
        abort();
    }

    return (Stack) { 0, max, data };
}

当然,在这里,当不再需要分配的内存时,您需要再次提供释放。

相关问题