4

I have a text file input.txt whose contents are of the form:

12 3 /
2 3 -
3 4 *
1 2 4 + - 5 * 7 /

My end goal is to read each line of the file and evaluate the given RPN expression. I have written the following code snippet to read the contents of the file from stdin and store it in a character array:

char expression[1000][256];
int i = 0;
while (fgets(expression[i], 256, stdin)) 
{   
    expression[i][strcspn(expression[i],"\r\n")] = 0;
    i++;
}

Now, I have all the lines in the array. My issue here is that I want to store these such that there are no spaces and each number (with all digits) or character is in a separate index.

For example, here, expression[0][0] is 1 and expression[0][1] is 2. But, I want expression[0][0] to be 12 and expression[0][1] to be 3, etc.

2 Answers2

1

Good work with your example so far! Thanks for posting a question that explains what you want, and making an attempt at solving it.

The main problem you've got is that you're storing an array of array of chars, when you need an array of array of strings (remember a string is a char *).

I've used the [strtok][1] method, which splits a string (using a NULL character) every time it hits one of the characters listed in its call. I then allocate memory, and copy the string into the array.

I made up some example code (try it online) which does just this.

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

int main() {
    char* expression[1000][256];
    char buffer[256];
    int line = 0;

    while (fgets(buffer, 256, stdin)) {
        int word = 0;
        char* token = strtok(buffer, " \r\n");
        do {
            expression[line][word] = calloc(sizeof(char), strlen(token) + 1);
            strcpy(expression[line][word], token);
            word++;
        } while ((token = strtok(NULL, " \r\n")) != NULL);
        line++;;
    }
    printf("'%s', '%s', '%s'\n", expression[0][0], expression[0][1], expression[0][2]);
    return 0;
}
Addison
  • 7,322
  • 2
  • 39
  • 55
  • This works for 1000 lines, but when I use 5000+, segmentation fault occurs. Is there a way to prevent this? –  Aug 24 '18 at 16:21
  • @fereydoon318 : yes, there are various ways to prevent this; one is to not store each line at all -- just process each line upon input (see e.g. the relevant aspects of the answer from chqrlie, below); or, you can dynamically allocate memory as you read in more input lines -- dynamic memory allocation is a general need in C programming (and in other languages), and there are lots of resources on-line to guide you; HTH – landru27 Aug 24 '18 at 22:03
0

You probably do not need to store the whole file in memory, but instead read one line at a time, evaluate it and print the result:

  • define a buffer long enough for a line of input
  • define an array of int to use as an RPN stack
  • in a loop, read each line of input
  • in a nested loop, using strtok, parse tokens:

    • if the token is a number, push its value onto the stack
    • if the token is an operator, perform this operation between the top 2 elements of the stack and store the result onto the stack after popping them.
  • at the end of the line, print the value at the top of the stack

You want to perform simple checks for stack overflow and underflow.

Here is a sample implementation:

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

int main() {
    char buffer[256];
    int stack[sizeof(buffer) / 2]; // no need for stack overflow check
    int i, sp, tos;

    while (fgets(buffer, sizeof buffer, stdin)) {
        char *p = buffer, *token, *q;
        sp = -1;
        stack[++sp] = 1;
        stack[++sp] = 1;
        while ((token = strtok(p, " \t\r\n")) != NULL) {
            p = NULL;
            tos = stack[sp];
            if (!strcmp(token, "+")) {
                stack[--sp] += tos;
            } else
            if (!strcmp(token, "-")) {
                stack[--sp] -= tos;
            } else
            if (!strcmp(token, "*")) {
                stack[--sp] *= tos;
            } else
            if (!strcmp(token, "/")) {
                if (tos == 0 || (tos == -1 && stack[sp - 1] == INT_MAX)) {
                    printf("division overflow\n");
                    break;
                }
                stack[--sp] /= tos;
            } else
            if (!strcmp(token, "%")) {
                if (tos == 0 || (tos == -1 && stack[sp - 1] == INT_MAX)) {
                    printf("division overflow\n");
                    break;
                }
                stack[--sp] %= tos;
            } else {
                tos = strtol(token, &q, 0);
                if (q == token || *q != '\0') {
                    printf("invalid token: %s\n", token);
                    break;
                }
                stack[++sp] = tos;
            }
            if (sp < 2) {
                printf("stack underflow for %s\n", token);
                break;
            }
        }
        if (token == NULL) {
            for (i = 2; i <= sp; i++) {
                printf("%d%c", stack[i], i == sp ? '\n' : ' ');
            }
        }
    }
    return 0;
}

Input:

12 3 /
2 3 -
3 4 *
1 2 4 + - 5 * 7 /

Output:

4
-1
12
-3
chqrlie
  • 131,814
  • 10
  • 121
  • 189