braindead_
braindead_

Reputation: 21

How can I get certain things out of a string

I wanted to write an algorithm that takes an input which contains the name of a certain item and its price, and a dash between them. The output is supposed to state the name of the item and its price. I would also like to know how can I separate the input into two strings, one being the name, and the other being the price, since I can't really come up with anything.

int getprice(char item[]);
void printitem(char item[]);
    
int main()
{
    char item[40];
    int i, j, len;
    int price = 0;

    fgets(item, 40, stdin);

    price = getprice(item);
    printitem(item);

    return 0;
}
    
int getprice(char item[])
{
    int i = 0;
    int price = 0;
    int len = strlen(item);
    int temp;

    for (i = 0; i < len; i++)
    {
        if ((item[i] >= '0') && (item[i] <= '9'))
        {
            break;
        }
        i++;
    }

    for (i; i < len; i++)
    {
        temp = item[i] - '0';
        price = price * 10;
        price = price + temp;
    }

    printf("price is: %u\n", price);
    return price;
}

void printitem(char item[])
{
    int i = 0;
    int len = strlen(item);

    for (i = 0; i < len; i++)
    {
        if (item[i] != '-') 
        {
            printf("%c", item[i]);
        }
        else // if '-' is encountered the next char is checked if it stops or if it needs to keep going
        {
            i++; //the for loop increments by itself
            if (item[i] == ' ') //if there is a space after '-' that means we printed the whole thing
            {
                break;
            }
            i--; //if it needs to keep going
            printf("-");
        }
    }
}
Input:Chocolate-Chip Cookie - 30
Output:Item: Chocolate-Chip Cookie
       Price: 30
actual Output: Item: Chocolate-Chip Cookie
               Price: 262

Why is the output price wrong, and is there a better way of doing it?

Upvotes: 2

Views: 92

Answers (4)

Jerry Coffin
Jerry Coffin

Reputation: 490348

Seems to me that this can be simplified somewhat. Omitting error checking for clarity, you could do something like this:

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

int main() { 
    char input[] = "Chocolate-Chip Cookie - 30";

    char *sep = strstr(input, " - ");

    int len = sep-input;
    printf("Item: '%.*s'\nPrice: '%s'\n", len, input, sep + 3);
}

Result:

Item: 'Chocolate-Chip Cookie'
Price: '30'

Upvotes: 1

David C. Rankin
David C. Rankin

Reputation: 84579

Another way (that you can use to parse anything from any string), is to use a pair of pointers to walk-the-string setting a begin and end pointer at the start and end of each segment of the string you want and then copy those portions of the string to separate storage.

A short example (with comments) would be:

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

#define NUMC   32       /* if you need a constant, #define one (or more) */
#define MAXC 1024
#define DELIM " - "

int main (void) {
    
    /* read buffer, buffers for item, price and begin, end pointers */
    char buf[MAXC], item[MAXC], price[NUMC], *p_begin = buf, *p_end;
    size_t len;
    
    fputs ("input: ", stdout);              /* prompt */
    if (!fgets (buf, MAXC, stdin)) {        /* read/validate input */
        return 0;
    }
    
    if (!(p_end = strstr (buf, DELIM))) {   /* locate start of delim */
        fputs ("error: invalid input format.\n", stderr);
        return 1;
    }
    
    memcpy (item, p_begin, p_end - p_begin);    /* copy item */
    item[p_end - p_begin] = 0;                  /* nul-terminate item */
    
    p_begin = p_end + strlen(DELIM);    /* set begin to start of price */
    len = strcspn (p_begin, "\n");      /* get length of price */
    memcpy (price, p_begin, len);       /* copy to price */
    price[len] = 0;                     /* nul-terminate price */
    
    /* output results */
    printf ("\nitem  : '%s'\nprice : '%s'\n", item, price);
}

Example Use/Output

./bin/split_price-item
input: Chocolate-Chip Cookie - 30

item  : 'Chocolate-Chip Cookie'
price : '30'

Now, your delimiter must remain " - ", but you can easily pass that as a parameter instead of using a constant (up to you). Let me know if you have any questions.

Upvotes: 1

chux
chux

Reputation: 154245

Why is the output price wrong?

Code attempts to change "30\n" rather than "30" into the value 30.

is there a better way of doing it?

int getprice(const char *item){  // add const
  // Look for a non-digit
  while ((*item < '0' || *item > '9') && *item) {
    item++;
  }
  if (*item == 0) {
    // No digit found, maybe add error message
    return 0;
  }

  int price=0;
  while (*item >= '0' && *item <= '9') {  // Loop while a digit
    price = price*10 + (*item - '0');
    item++;
  }

  printf("price is: %d\n", price);  // %d not %u
  return price;
}

Upvotes: 0

Willis Blackburn
Willis Blackburn

Reputation: 8204

Well, right away, I see that you're incrementing i twice each time through this loop, probably not what you want:

for(i=0;i<len;i++)  // <- First increment
{
    if((item[i] >= '0') && (item[i] <= '9'))
    {
        break;
    }
    i++;            // <- Second increment
}

The i here is unnecessary:

for(i;i<len;i++)
 // ^ does nothing

You can print some values in your price-calculation loop to see what's going on:

for(i;i<len;i++)
{
printf("price = %d, item[i] = %d, new price = %d\n",
    price, item[i], price * 10 + (item[i] - '0'));
temp = item[i] - '0';
price = price * 10;
price = price + temp;
}
$ ./test
Chocolate-Chip Cookie - 30
price = 0, item[i] = 51, new price = 3
price = 3, item[i] = 48, new price = 30
price = 30, item[i] = 10, new price = 262   <-- Hmm
price is: 262

The issue is that fgets is adding the \n (the return you press after the input) to the string and you're interpreting it as part of the price.

Upvotes: 1

Related Questions