Indexing isn't working when it is supposed to - c

I made an attempt to translate a math evaluation I had written in C++ to C. I have faced an issue when I try to loop through the expression and get a segmentation fault.
My tree directory
├── main.c
├── math
│   ├── include.h
│   └── main.c
├── stack
│   ├── include.h
│   └── main.c
My Header and Source File for Stack
//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");
}
}
My Math source, header doesn't have anything important
#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);
}
My mistake appears in the "evaluation" function of the for loop in the math source file. When my loop goes the second time, I get the error. I am really confused because the string the I pass in is "20*2+1" and it is size 6, but when my loop go the second time the index is 4, so it should work. I hope that somebody could help me with my bug.

The problem does not appear to be related to indexing. Instead, your stack implementation is bogus. This ...
typedef struct{
int top, max_height;
float data[];
}Stack;
... declares a structure type with a flexible array member. The flexibility involved is that you can make use of the full amount of space allocated for any given instance of the struct, as if its data member were declared with dimension that made it fill as much of that space as possible. That is useful only in conjunction with dynamic memory allocation, which you are not using, and the resulting dynamically-allocated objects cannot usefully be passed or returned by value.
You have two main options:
If you want to stick with the FAM, then stack_init() must be modified to dynamically allocate large enough instances, and to return a pointer to the allocated result. For example:
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;
}
Other changes would be required to accommodate the change of return type, and to free the dynamically allocated stack objects when they were no longer needed.
OR
Change Stack.data to a pointer, and allocate stack space dynamically . For example:
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 };
}
Of course, here again you need to provide for freeing the allocated memory when it is no longer needed.

Related

Error 'is_empty' was not declared in this scope.why does it give error?

output=[Error] 'is_empty' was not declared in this scope
must be:
Example
Input string : abbccbaabccbba message will be The string is valid
aaabbcbbcbaab message will be The string is invalid
aadbxcy*ycxbdaa message will be Wrong character!!!
what should i do?
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<string.h>
typedef struct
{
char home[35];
int top;
} My_stack;
void push(My_stack * s, char c) // push (insert) operation
{ // assume there is enough space for pushing next element!
s -> top ++;
s -> home[s -> top] = c;
}
int pop(My_stack * s) // pop (remove) operation
{
if(is_empty (*s)) {
printf("ERROR: Nothing to pop - program terminates\n");
exit(1);
}
return (s ->home[s ->top --]);
}
int is_empty(My_stack * s) // checking whether stack is empty or not
{
return(s -> top < 0 ? 1 : 0);
}
int main(){
char ch[25];
int i,l;
My_stack stack;
printf("give the string");
scanf("%s",ch);
l=strlen(ch);
i=0;
while(ch[i]!='\0') {
if(ch[i]!='A'&&ch[i]!='B'&& ch[i]!='*') {
printf("the string is not accepted allowed caracters are A,B and * ");
exit(0);
}
i++;
}
i=0;
while(ch[i] != '*') {
push(&stack, ch[i]);
i++;
}
i++; // one step forward to pass '*
while(ch[i] != '\0') {
if(ch[i] != pop(&stack)) {
printf("the string is not valid");
exit(0);
}
i++;
}
printf("the string is valid");
return 0;
}
First of all, you need to pass the pointer to the function, not the actual value, so your functioncall must be changed to:
is_empty (s)
instead of
is_empty (*s)
Then, the reason is because you define your function is_empty after your first use. To prevent this error, you should declare your function first. This tells the compiler "hey, there exists this function with this signature, the definition is given later though" so then you can use it in your program before having implemented it explicitly.
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<string.h>
typedef struct
{
char home[35];
int top;
} My_stack;
int is_empty(My_stack * s); // <----- DECLARATION OF FUNCTION
int pop(My_stack * s) // pop (remove) operation
{
if(is_empty (s)) {
printf("ERROR: Nothing to pop - program terminates\n");
exit(1);
}
return (s ->home[s ->top --]);
}
int is_empty(My_stack * s) // checking whether stack is empty or not
{
return(s -> top < 0 ? 1 : 0);
}
Or, you put the entire definition before your first use so then there's no need for a declaration:
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<string.h>
typedef struct
{
char home[35];
int top;
} My_stack;
int is_empty(My_stack * s) // checking whether stack is empty or not
{
return(s -> top < 0 ? 1 : 0);
}
int pop(My_stack * s) // pop (remove) operation
{
if(is_empty (s)) {
printf("ERROR: Nothing to pop - program terminates\n");
exit(1);
}
return (s ->home[s ->top --]);
}

atof() removes one character at the end

I am aware of the low quality of the code, I am a beginner to programming in C.
The following program attemps to receive input from the user, turn it into tokens and then perform basic math with them. If the input exceeds 8 characters: ('256 + 256'), it fails to properly return a correct result, instead 256 + 256 is interpreted as `256 + 25.
It's been hours and hours of debugging and I cannot pinpoint the error.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#define MAX 1024
typedef struct tokenReturn {
int arrayMembers;
char* tokens[];
}
t_return;
t_return *getAndTokenize(char* delim) {
// Get user input and store it as a string literal.
char* input = malloc(1024);
char lit_in[MAX];
if (fgets(input, MAX, stdin) == NULL) {
perror("Error: ");
exit(EXIT_FAILURE);
}
strncpy(lit_in, input, MAX);
free(input);
// Create the return structure to return not only the char* array but the max index as well.
t_return *return_struc = malloc(sizeof(t_return) + MAX);
if (return_struc == NULL) {
puts("Allocation error");
perror("Error");
exit(EXIT_FAILURE);
}
// Assign first member due to the weird behaviour the strtok function has.
char *token = strtok(lit_in, delim);
return_struc->tokens[0] = token;
int i = 1; // We have to start at one since we already have one token stored in the array
while (true)
{
// Check to see if all the tokens have been obtained.
if((token = strtok(NULL, delim)) == NULL) {
break;
}
return_struc->tokens[i] = token;
i++;
}
// Assign i to arrayMembers so that we can determine array length.
return_struc->arrayMembers = i;
return return_struc;
}
float sum(float x, float y) {
return x + y;
}
float multiply(float x, float y) {
return x * y;
}
float subs(float x, float y) {
return x - y;
}
float division(float x, float y) {
return x / y;
}
int main(void) {
// Init
printf("Operation: ");
t_return* tokens = getAndTokenize(" ");
float a = atof(tokens->tokens[0]);
char symbol = tokens->tokens[1][0];
float b = atof(tokens->tokens[2]);
float result;
// Check for the operation being done
switch (symbol) {
case '+':
result = sum( a, b );
break;
case '-':
result = subs(a, b);
break;
case '/':
result = division( a, b );
break;
case '*':
result = multiply( a, b );
break;
default:
puts("Operation not recognized!");
exit(EXIT_FAILURE);
}
printf("Result is: %.3lf\n", result);
exit(EXIT_SUCCESS);
}
getAndTokenize copies the input into lit_in, which is an automatic object inside getAndTokenize. Once getAndTokenize returns, the memory for lit_in is no longer reserved, and the pointers you put into the t_return structure pointing into lit_in are no longer valid. Some of the other code in main does things that reuse that memory for other purposes. Change getAndTokenize to keep the input in an allocated buffer that is not freed until the program is done using the data in it.

How is printf avoiding a segmentation fault?

--Important Edit--
Thanks for the tip on compiling with -fsanitize=address -g, it allowed me to track down the problem. I'm almost done and I've isolated the issue (which happens near the top of the cleanup function). To simplify things, why does the following (when compiled with the above flags) fail?
#include <stdio.h>
#include <stdlib.h>
struct pair {
char *left;
char *right;
};
int main() {
struct pair *pairs = malloc(100 * sizeof(*pairs));
for (int x = 0; x < 100; x++) {
printf("%i\n", x);
pairs->left = pairs->right = NULL;
pairs += sizeof(*pairs);
}
return 0;
}
After printing 0-7 on new lines, I get ==9803==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61b000000788 at pc 0x00010cb90d88 bp 0x7ffee306fa90 sp 0x7ffee306fa88...Address 0x61b000000788 is a wild pointer.
--Original Question--
I've been working on a brainfuck interpreter in C, but I keep inconsistently getting a segfault. While trying to debug this for a day, I've done many things which, rather than catching where the problem is, simply cause it not to happen. I think at this point I'm encountering undefined behavior, but after rereading my code multiple times I don't see where it could be happening. All of these things cause the program to work as intended:
Printing a variable amount of characters between the bottom of the function body of cleanup and the top of the function body of execute (including inside the main function), though this isn't always consistent
Compiling with the -g flag for debugging
At the top of the execute function
unsigned char *pointer = (unsigned char*) calloc(30000, 1);
unsigned char *leftbound = pointer, *rightbound = pointer;
rightbound += 29999;
changing 30000 to 1000 and 29999 to 999
I've read the documentation on malloc, realloc, and calloc, and browsed for other answers, and I still can't tell the problem. As far as I can tell, I have no memory leaks (even when I realloc a struct pair*, the memory at the pointers within each struct is not leaked because it is within the char *program block) or other issues. That's why I would provide the minimal answer to reproduce the problem, but I'm beginning to doubt that removing seemingly unrelated parts of my source code will have no effect on it (though I have stripped down my code a lot still).
I'm using Mac OS X 10.14, bash "gcc -o brainfc brainfc.c" OR "clang -o brainfc brainfc.c" to compile, "brainfc mandelbrot.b" to run program.
The mandelbrot.b file can be found here: http://esoteric.sange.fi/brainfuck/utils/mandelbrot/mandelbrot.b
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *program = NULL;
struct pair {
char *left;
char *right;
};
//Reads into global variable program from file
void fileinput(char *filename) {
FILE *fp;
fp = fopen(filename, "rb");
if (fp) {
size_t inputlen = 0;
fseek(fp, 0, SEEK_END);
int filesize = ftell(fp);
rewind(fp);
program = malloc(filesize + 1);
fread(program, filesize, 1, fp);
*(program + filesize) = 0;
fclose(fp);
}
}
//Removes unwanted characters from program, as well as compiling lookup table of pairs
//This happens in a single sweep through the program for efficiency,
//though again this problem might not occur if I optimized for readability
struct pair* cleanup() {
int pairsize = 200;
struct pair *pairs = calloc(pairsize, sizeof(*pairs));
char *src, *dest;
struct pair *buildptr = pairs;
int bracketlevel = 0;
for (src = dest = program; *src; dest += (strchr("<>+-[].,", *src++) != NULL)) {
*dest = *src;
if (*dest == '[') {
bracketlevel++;
while (buildptr->left) {
if (buildptr == pairs + (pairsize - 1) * sizeof(*pairs)) {
pairsize += 100;
pairs = realloc(pairs, pairsize * sizeof(*pairs));
for (int x = 0; x < 100; x++) {
buildptr += sizeof(*pairs);
buildptr->left = buildptr->right = NULL;
}
buildptr -= sizeof(*pairs) * 100;
}
buildptr += sizeof(*pairs);
}
buildptr->left = dest;
} else if (*dest == ']') {
bracketlevel--;
if (bracketlevel < 0) {
return NULL;
}
while (buildptr->right) {
buildptr -= sizeof(*pairs);
}
buildptr->right = dest;
}
}
if (bracketlevel != 0) {
return NULL;
}
*dest = 0;
program = realloc(program, strlen(program) + 1);
return pairs;
}
//Executes program
int execute(struct pair *pairs) {
unsigned char *pointer = (unsigned char*) calloc(30000, 1);
unsigned char *leftbound = pointer, *rightbound = pointer;
rightbound += 29999;
for (char *pc = program; *pc; pc++) {
switch (*pc) {
case '<':
if (pointer == leftbound) return 1;
pointer--;
break;
case '>':
if (pointer == rightbound) return 1;
pointer++;
break;
case '+':
(*pointer)++;
break;
case '-':
(*pointer)--;
break;
case '[':
while (pairs->left != pc) pairs += sizeof(*pairs);
if (!(*pointer)) pc = pairs->right;
break;
case ']':
while (pairs->right != pc) pairs -= sizeof(*pairs);
if (*pointer) pc = pairs->left;
break;
case '.':
printf("%c", *pointer);
break;
case ',':
printf("Inputting 10 (for now)\n");
*pointer = 10;
break;
}
}
return 0;
}
//Parses command line arguments, calls each function in order
int main(int argc, char *argv[]) {
if (argc > 0) {
char *filepath = argv[1];
fileinput(filepath);
}
if (program == NULL) {
printf("Error: File not found\n");
return 3;
}
struct pair *pairs = cleanup();
if (pairs == NULL) {
printf("Error: Invalid program\n");
return 4;
}
int execstatus = execute(pairs);
switch (execstatus) {
case 1:
printf("\nError: Pointer out-of-bounds\n");
return 1;
case 2:
printf("\nError: Byte overflow\n");
return 2;
default:
return 0;
}
}
Any help would be greatly appreciated.
pairs += sizeof(*pairs);
Pointer arithmetic in C is always in units of the type pointed to - here, it's in units of struct pairs. So if you want pairs to point to the next struct pair in the array, add 1. (The compiler will internally translate this into adding the appropriate number of bytes, or however pointers happen to work on your system.) This line should be pairs += 1; or pairs++; or ++pairs; according to your taste.
As it stands, if sizeof(*pairs) happens to be, say, 16 on your system, you are skipping past 15 more struct pairs every time you iterate. You will end up accessing the 0th, 16th, 32nd, ... 1584th struct pair in the array. Since it only contains 100, obviously most of these will be out of bounds. Hence your segfault.
As previously mentioned the usage of pointers is a bit messed up.
Instead of
pairs->left = pairs->right = NULL;
pairs += sizeof(*pairs);
Use
pairs[x].left = pairs[x].right = NULL;
As a bonus you have pairs still intact to do the clean up

Why queue using two stacks not functioning?

I'm trying to implement a queue using 2 stacks but my code isn't functioning.
Can you spot the error?
#include <stdio.h>
#include<stdlib.h>
#define MAX 5
typedef struct stack {
int top;
int arr[MAX];
} stack;
void enque(stack*s1, int ele) {
printf("entering");
push(&s1, ele);
printf("what a pain");
}
void push(stack*s, int ele) {
if (s->top == MAX - 1) {
printf("OVERFLOW");
} else {
s->arr[++s->top] = ele;
}
}
int deq(stack*s1, stack*s2) {
int x;
if (s1->top == -1 && s2->top == -1) {
printf("empty");
} else {
if (s2->top == -1) {
while (s1->top != -1) {
push(&s2, pop(&s1));
}
}
x = pop(&s2);
return x;
}
}
int pop(stack *s) {
if (s->top == -1) {
printf("UNDERFLOW");
} else {
return s->arr[s->top--];
}
}
void display(stack*s) {
printf("entered display");
int i;
for (i = 0; i <= s->top; i++) {
printf(" %d", s->arr[i]);
}
}
int main() {
int ch, ele, c;
stack s1, s2;
s1.top = -1, s2.top = -1;
do {
printf("1 - Enqueue2-deq3-display4-exit\n");
printf("Enter choice");
scanf("%d", &ch);
switch (ch) {
case 1:
printf("enter ele of ur choice");
scanf("%d", &ele);
enque(&s1, ele);
break;
case 2:
c = deq(&s1, &s2);
printf("%d", c);
break;
case 3:
display(&s1);
break;
case 4:
exit(0);
default:
printf("Wrong choice");
}
} while (ch != 5);
}
Can you spot the error?
The compiler can spot the error faster than Stack-overflow.
OP is not compiling with all warnings enabled or is using a weak compiler
Enable all warnings to save time.
int deq(stack*s1, stack*s2) and int pop(stack *s) both have the same problem.
A common waning in such cases is warning: control reaches end of non-void function [-Wreturn-type]
Make certain each function path returns a value.
int pop(stack *s) {
if (s->top == -1) {
printf("UNDERFLOW"); // Notice, no return
} else {
return s->arr[s->top--];
}
}
Also push(&s1, ele); used before declaration. This make for conflicting function signature. Declare or define push() before using. Likely undefined behavior (UB) and this makes the code unreliable.
I recommend to print an '\n' more often.
// printf("entering");
printf("entering\n");
// or
puts("entering"); // \n automatically added.
You are passing pointer address in deque and enque functions.
push(&s2, pop(&s1)); --> push(s2, pop(s1));
x = pop(&s2); --> x = pop(s2);
push(&s1, ele);-->push(s1, ele);
since s1 and s2 are received as pointers to deque and enque functions
Also consider changes suggested by #Mr.Chux by considering compiler warnings you could have resolved all the issues by yourself.

C - K&R expr: evaluate a reverse Polish expression from the command line

I've been trying to complete exercise 5-10 from K&R using a dynamically allocated stack. I based my code on the code from chapter 4 (they used global variables to implement the stack). The problem is that my programme doesn't work at all and I can't figure out what is wrong. Here's the code:
/* expr: evaluates a reverse Polish expression from the command line */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define MAXOP 100 /* maximal operator length */
#define NUMBER '0' /* signal that a number was found */
int getop(char *argv);
void push(double **top, double val);
double pop(double **top);
int main(int argc, char *argv[])
{
if (argc == 1) {
printf("usage: evaluate a reverse Polish expression from the command line\n");
return 1;
}
double *stack = malloc((argc-1)*sizeof(double));
if (stack == NULL) {
printf("error: couldn't allocate enough space for the stack\n");
return 2;
}
int i, type;
double op1, op2, *top = stack; /* top points to the next free stack position */
char s[MAXOP];
for (i = 1; argv[i] != NULL; i++) {
type = getop(argv[i]);
switch (type) {
case NUMBER :
push(&top, atof(argv[i]));
break;
case '+' :
op2 = pop(&top);
op1 = pop(&top);
push(&top, op1+op2);
break;
case '-' :
break;
case '*' :
break;
case '/' :
break;
case '%' :
break;
default :
printf("error: unknown command %s\n", argv[i]);
return 3;
break;
}
}
printf(" = %.8g\n", pop(&top));
free(stack);
return 0;
}
int getop(char *argv)
{
int i, c;
if (!isdigit(argv[0]))
return argv[0];
else
return NUMBER;
}
void push(double **top, double val)
{
**top = val;
(*top)++;
/* is error checking needed? */
}
double pop(double **top)
{
(*top)--;
return *(*top+1);
/* is error checking needed? */
}
It seems not to take operators into account - for example input ./expr 1 12 13 + + produces output 13.
EDIT:
Thanks for all the help guys, it turns out that push and pop didn't work properly. I've managed to fix that code, although now from the hindsight I see that I could've prepared better before writing the code.
Here is the code after the changes:
/* expr: evaluates a reverse Polish expression from the command line */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define MAXOP 100 /* maximal operator length */
#define NUMBER '0' /* signal that a number was found */
int getop(char *argv);
void push(double **top, double val);
double pop(double **top);
int main(int argc, char *argv[])
{
if (argc == 1) {
printf("usage: evaluate a reverse Polish expression from the command line\n");
return 1;
}
double *stack = (double*) malloc((argc-1)*sizeof(double));
if (stack == NULL) {
printf("error: couldn't allocate enough space for the stack\n");
return 2;
}
int i, type;
double op1, op2, *top = stack; /* top points to the next free stack position */
char s[MAXOP];
for (i = 1; argv[i] != NULL; i++) {
type = getop(argv[i]);
switch (type) {
case NUMBER :
push(&top, atof(argv[i]));
break;
case '+' :
op2 = pop(&top);
op1 = pop(&top);
push(&top, op1+op2);
break;
case '-' :
op2 = pop(&top);
op1 = pop(&top);
push(&top, op1-op2);
break;
case 'x' :
op2 = pop(&top);
op1 = pop(&top);
push(&top, op1*op2);
break;
case '/' :
op2 = pop(&top);
op1 = pop(&top);
if (op2 != 0)
push(&top, op1/op2);
else {
printf("error: division by zero\n");
return 3;
}
break;
default :
printf("error: unknown command %s\n", argv[i]);
return 4;
break;
}
}
printf(" = %.8g\n", pop(&top));
free(stack);
return 0;
}
int getop(char *argv)
{
int i, c;
if (!isdigit(argv[0]))
return argv[0];
else
return NUMBER;
}
void push(double **top, double val)
{
**top = val;
(*top)++;
}
double pop(double **top)
{
double temp = *(*(top)-1);
(*top)--;
return temp;
}
Your code seems to not understand that you allocated an array with malloc, and you're trying to use the "add to front" method that is used with pointer-based stacks. You should be pushing new values after the most recent item pushed onto the stack and popping the item most recently pushed onto the stack (i.e. at the "end" of the stack).
The following should work for you. Note that pcount is a pointer to the number of items on the stack, else you won't know whether the stack is empty (e.g. 2 + would be invalid input because + requires 2 values but there's only 1 on the stack) or even where to add another value because you won't be able to determine where the "end" of the stack is.
#include <math.h> // for HUGE_VAL; may need to link the math library?
// Push a value onto the stack and update the number of items on the stack.
void push(double *stk, double value, int *pcount)
{
// Add new values at the end of the stack (technically after the last item pushed).
stk[*pcount] = value;
++*pcount;
}
// Pop a value off the stack and update the number of items remaining on the
// stack. If there are no values, HUGE_VAL is returned. Since it is possibly
// a valid value on some implementations, checking for an error should be done
// using the value pcount points to:
//
// n = pop(stk, &stkCount);
// if (stkCount < 0) {
// // error: stack had no elements before pop
// }
//
double pop(double *stk, int *pcount)
{
if (*pcount >= 0) {
// Remove items from the end of the stack.
--*pcount;
return stk[*pcount];
}
return HUGE_VAL;
}
As #AnttiHaapala pointed out, your push and pop are a mess. Also, your data is organized in a way that makes error checking difficult, if not impossible.
Here are correct push and pops.
typedef struct
{
double* base; // base address of stack, allocated with malloc.
double* end; // top address of stack + 1 double, init to base + number of elements
double* ptr; // stack pointer, initialize to equal base
} stack;
int init_Stack(struct stack* p, int items)
{
p->base = malloc(items * sizeof(double));
if (!p->base)
return -1;
p->end = p->base + items;
p->ptr = p->base;
return 0;
}
void push(struct stack* p, double val)
{
if (p->ptr >= p->end)
{
//stack overflow!
exit(3);
}
*(p->ptr++) = val;
}
double pop(struct stack* p)
{
if (p->ptr <= p->base)
{
// stack underflow!
exit(4);
}
return *(--(p->ptr));
}

Resources