Home > Enterprise >  In C, how should I extract coefficients and exponents from polynomial input using strtok?
In C, how should I extract coefficients and exponents from polynomial input using strtok?

Time:11-07

Say the user enters "-4x^0 x^1 4x^3 - 4x^5 - 3x^7" as an input. I want to extract values from the string and pass them into coef[] and expo[] so it looks like this:

coef = [-4, 1, 0, 4, 0, -4, 0, -3]
expo = [ 0, 1, 2, 3, 4,  5, 6,  7]

Here's what I have so far but I don't know how to use tokens.

int main()
{
    char userInput[100];
    char temp[100];
    printf("Enter the polynomial: ");
    scanf("%[^\n]%*c", userInput);
    strcpy(temp, userInput);
    printf("\n");
    
    int coef[100];
    int expo[100];
    for (int i = 0; i < 100; i  ) {
        coef[i] = 0;
        expo[i] = 0;
    }
    
    char *tok = strtok(temp, "x^"); 
    int counter = 0;
    
    while (tok) { 
        printf("*%s*\n", tok); 
        tok = strtok(NULL, "x^"); 
        counter  ; 
    } 
    
    return 0;
}

I have tried the following but it didn't work:

    int counter = 0;
    while (tok) { 
        printf("*%s*\n", tok);        
        expo[counter] = atoi(tok);

        tok = strtok(NULL, "x^"); 
        counter  ; 
    } 

CodePudding user response:

This is a bit trickier problem than I first presumed due to the whitespace in the user-input and the possibility of missing exponents and coefficients -- and coefficients missing due to being 1 and omitted.

This can be done, but it requires a Decorate before you Tokenize where you decorate the string to be tokenized with new delimiters between the exponents and coefficient to ensure you can use strtok(). Otherwise because the /- must be kept and the input format can be, e.g. "4x^1 3x^2" there is no delimiter between the 1 and 3 except for whitespace surrounding the ' ' that must be considered part of 3.

A simple way to format the temporary string from the input is to remove all whitespace and add a new 'x' between the exponent and coefficient. That allows you to use the same delimiter string with strtok(), e.g. "x^\n" without adjustment.

The missing coefficients and exponents can be handled by looping from the current index to the exponent assigning 0 for coefficients and the loop counter for the exponent. Then you can add the current coefficient and exponent.

Putting it altogether and using sscanf() to minimally validate each conversion from string to int, you can do something similar to the following:

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

#define MAXC       1024   /* if you need a constant, #define one (or more) */
#define MAXCOEF     256
#define MAXEXP  MAXCOEF
#define DELIM    "x^\n"

int main (void) {
  
    char buf[MAXC], tmp[MAXC];              /* input & reformat buffers */
    int coef[MAXCOEF] = {0},                /* coefficient array */
        expo[MAXEXP] = {0},                 /* exponent array */
        n = 0, ndx = 0;                     /* counter and index */
    
    fputs ("enter polynomial: ", stdout);   /* prompt */
    
    if (!fgets (buf, MAXC, stdin)) {        /* read line in buf/validate */
      puts ("(user canceled input)");
      return 0;
    }
    
    for (int i = 0; buf[i]; i  ) {          /* loop remormat buf in tmp */
      if (buf[i] != ' ') {                  /* if not space */
        if (buf[i] == '-' || buf[i] == ' ') { /* if before next coef */
          tmp[n  ] = 'x';                     /* decorate with new 'x' */
        }
        tmp[n  ] = buf[i];                  /* add from buf to tmp */
      }
      else {  /* otherwise was ' ' */
        if (buf[i 1] == 'x') {              /* if next char is 'x' */
          tmp[n  ] = '1';                   /* coef not given - use 1 */
        }
      }
    }
    tmp[n] = 0;   /* nul-terminate tmp */
    
    /* separate each token with strtok */
    for (char *tok = strtok (tmp, DELIM); tok; tok = strtok (NULL, DELIM)) {
      int ctmp, etmp;   /* temp values for coefficient and exponent */
      
      if (sscanf (tok, "%d", &ctmp) != 1) { /* convert coefficient to int */
        fprintf (stderr, "conversion failed for '%s'.\n", tok);
        return 1;
      }
      
      if (!(tok = strtok (NULL, DELIM))) {  /* get exponent token */
        break;
      }
      if (sscanf (tok, "%d", &etmp) != 1) { /* convert exponent to int */
        fprintf (stderr, "conversion failed for '%s'.\n", tok);
        return 1;
      }
      
      for (int i = ndx; i < etmp; i  ) {    /* loop index to exponent */
        coef[ndx] = 0;                      /* add any missing values */
        expo[ndx  ] = i;                    /* increment index */
      }
      
      coef[ndx] = ctmp;                     /* add coefficient & exponent */
      expo[ndx  ] = etmp;                   /* increment index */
    }
    
    fputs ("\ncoef:", stdout);              /* output coefficients */
    for (int i = 0; i < ndx; i  ) {
      printf (" % d", coef[i]);
    }
    putchar ('\n');   /* tidy up with newline */
    
    fputs ("expo:", stdout);                /* output exponents */
    for (int i = 0; i < ndx; i  ) {
      printf (" % d", expo[i]);
    }
    putchar ('\n');
}

Example Use/Output

$ ./bin/strtokpoly
enter polynomial: -4x^0   x^1   4x^3 - 4x^5 - 3x^7

coef: -4  1  0  4  0 -4  0 -3
expo:  0  1  2  3  4  5  6  7

Which corresponds to your needed output.

Look things over and let me know if you have questions.

CodePudding user response:

strtok() is not a good approach for this problem, especially using "x^" as the list of separators because it will overwrite these characters with null bytes, hence making it impossible to distinguish 2x from 2.

Also note that scanf("%[^\n]%*c", userInput) has undefined behavior if the polynomial entered by the user is longer than 99 bytes. The return value of scanf() should be tested to detect an unexpected end of file. It is safer to use fgets() and test the return value.

To parse the polynomial, it is recommended to test one character at a time and convert numbers with strtol or a similar function.

Here is a modified version:

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

unsigned char skip_spaces(char *p, char **pp) {
    unsigned char c;
    while (isspace(c = *p))
        p  ;
    *pp = p;
    return c;
}

void show_error(const char *error, const char *str, const char *p) {
    fprintf(stderr, "error: %s\n%s%*s^\n", error, str, (int)(p - str), "");
}

#define TERM_COUNT 100

int main() {
    char userInput[100];

    printf("Enter the polynomial: ");
    if (fgets(userInput, sizeof userInput, stdin)) {
        int coef[TERM_COUNT] = { 0 };
        int expo[TERM_COUNT] = { 0 };
        int counter;
        char *p = userInput;

        for (counter = 0; counter < TERM_COUNT; counter  ) {
            int sign = 1;
            unsigned char c = skip_spaces(p, &p);
            if (c == '\0')
                break;
            if (c == ' ') {
                c = skip_spaces(p   1, &p);
            } else
            if (c == '-') {
                sign = -1;
                c = skip_spaces(p   1, &p);
            }
            if (c == '\0') {
                show_error("missing term", userInput, p);
                break;
            }
            if (isdigit(c)) {
                coef[counter] = sign * strtol(p, &p, 10);
                c = skip_spaces(p, &p);
            } else {
                coef[counter] = sign;
            }
            if (c == 'x') {
                c = skip_spaces(p   1, &p);
                if (c == '^') {
                    c = skip_spaces(p   1, &p);
                    if (isdigit(c)) {
                        expo[counter] = strtol(p, &p, 10);
                        c = skip_spaces(p, &p);
                    } else {
                        show_error("missing exponent", userInput, p);
                        break;
                    }
                } else {
                    expo[counter] = 1;
                }
            } else {
                expo[counter] = 0;
            }
            if (c != '\0' && c != ' ' && c != '-') {
                show_error("syntax error", userInput, p);
                break;
            }
        }
        for (int i = 0; i < counter; i  )
            printf("% dx^%d", coef[i], expo[i]);
        printf("\n");
    }
    return 0;
}

The above code uses your approach and populates 2 arrays with the coefficients and exponents.

  •  Tags:  
  • c
  • Related