1

I'm writing a C program that reads a file given as input. I should create a calculator, each line of the file is composed like this:

*2
+6
-8
+33
.......

I was trying to use strtok to separate operation from number. My problem is that strtok doesn't behave as it should. Why does my program always enter all ifs?

typedef struct{
    long result;
    long number;
    char done;
}shm_data;

void create_operation(char* buffer,shm_data* data){

    char* add,*sottr,* molt;
    long number=0;

    if(((add=strtok(buffer,"+"))!=NULL))
    {
        printf("add: %s\n",add);
    }
     
    if(((sottr=strtok(buffer,"-"))!=NULL))
    {
        printf("sottr: %s\n",sottr);
    }
    
    if(((molt=strtok(buffer,"*"))!=NULL))
    {
        printf("molt: %s\n",molt);
    }

}

void child_mng(shm_data* data,int sem_id,char* path){
    
    FILE* r_stream;
    char tmp[DIM];

    if((r_stream=fopen(path,"r"))==NULL)
    {
        perror("fopen");
        exit(1);
    }

    while(fgets(tmp,DIM,r_stream))
    {
        if(tmp[strlen(tmp)-1]=='\n')
            tmp[strlen(tmp)-1]='\0';

        printf("read file: %s\n",tmp);
        create_operation(tmp,data);

    }

    exit(0);

}

es.

Suppose the file contains only one line:

+80

This is my output:

./calculator list.txt 
read file: +80
add: 80
sottr: +80
molt: +80

but the output should be this:

./calculator list.txt 
read file: +80
add: 80

why does this happen? Could I do it differently?

anatolyg
  • 26,506
  • 9
  • 60
  • 134
  • 1
    "My problem is that strtok doesn't behave as it should." In your own words, **exactly what do you think it should do instead, and why**? Please be detailed. Also, consider *reading the documentation* in order to make sure your understanding is correct. – Karl Knechtel Apr 03 '23 at 08:18
  • Does this answer your question? [How does strtok() split the string into tokens in C?](https://stackoverflow.com/questions/3889992/how-does-strtok-split-the-string-into-tokens-in-c) – Karl Knechtel Apr 03 '23 at 08:20
  • 1
    The `strtok` function isn't really suitable here. I would personally do some manual parsing here, going through the string until I get a digit character. Then copy everything before the digit into a separate string (which I then "trim" by removing leading and trailing spaces). Use `strcmp` on the operator string in an `if ... else if ...` chain, and use `strtol` to get the numeric value. Don't forget error checking and input validation. – Some programmer dude Apr 03 '23 at 08:24
  • 2
    99.9% strtok does behave the way it should, just not the way you think it should. Use a debugger. – gnasher729 Apr 03 '23 at 08:29
  • how to compare only the first character? i tried like this (strcmp(buffer[0],"+")==0), but i get error – Valentino Fabris Valenti Apr 03 '23 at 09:04
  • @ValentinoFabrisValenti `if(buffer[0] == '+')` would compare only the first character. Another option is to create an operator map. [Example](https://godbolt.org/z/Ecvzex3T5) – Ted Lyngmo Apr 03 '23 at 09:11

2 Answers2

3

If the format is guaranteed to always be like <op><number>, where

  • <op> is '+', '-', '*' or '/'; And
  • <number> is a valid integer; And
  • There's no space at all between <op> and <number>; And
  • <op> is the first character in the string

then a simple switch (buffer[0]) would work fine, and using &buffer[1] as the string for the number will work.

Like for example:

const char *number = &buffer[1];
switch (buffer[0])
{
case '+':
    printf("Add %s\n", number);
    break;
// Etc. for '-', '*' and '/'

default:
    printf("Invalid operator\n");
    break;
}

If you need the integer value then use e.g. strtol to convert it:

long number = strtol(&buffer[1], NULL, 10);
printf("The number is %ld\n", number);

Note that this will not work if the input is not guaranteed to follow the rules set out in the list above. Also note that you really need to add input validation and error checking, to guard against input that doesn't follow the rules.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
0

I agree that strtok is not suitable for this task.

You could use sscanf here. The format string of sscanf can contain literal characters; sscanf will then check whether they match, and do the rest of its work if they do (and report failure if they don't).

int number;

if (sscanf(buffer, "+%d", &number) == 1)
    printf("Let's add\n");
else if (sscanf(buffer, "-%d", &number) == 1)
    printf("Let's subtract\n");
else if (sscanf(buffer, "*%d", &number) == 1)
    printf("Let's multiply\n");
else
    printf("Error!\n");
printf("The number we are going to manipulate is: %d\n", number);
anatolyg
  • 26,506
  • 9
  • 60
  • 134