Extract integers from a string in C

I'm trying to extract all numbers from a string add 56 89 29. There is something wrong with my code which I'm not able to figure out. The output looks like this:

Current no: 56
Current no: 89
Current no: 9
Current no: 29
Current no: 9
Current no: 9
Current no: 0
Current no: 0

where as, I would expect this:

Current no: 56
Current no: 89
Current no: 29
Current no: 29
Current no: 29
Current no: 29

There are better ways to do it but I want to know what is wrong with this implementation.

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

int main(int argc, char * argv[]){
    char temp[100];
    char op[3];
    char *buf = "add 56 89 29";
    int offset = 0;
    int rcount = 0;
    int lastno = -999;
    int currno;
    bzero(&temp, sizeof(temp));
    sscanf(buf, "%s", op);  // Get the operator (add)
    if(!strcmp(op, "add")){
        while(1){
            sscanf(buf + offset + 4, "%s", temp);  // strlen("add ") == 4
            currno = atoi(temp);
            offset += strlen(temp);
            if(currno == lastno){
                rcount++;
                // Repeating numbers means string finished
                if(rcount == 3){
                    break;
                }
            }
            printf("Current no: %d\tOffset: %d\n", currno, offset + 4);
            lastno = currno;
        }
    }
    return 0;
}

Thanks in advance!

Answers


The "%n" specifier will record the number of characters used by a scan. The result can be added to the offset to advance through the string.

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

int main(int argc, char * argv[]){
    char temp[100];
    char op[4];
    char *buf = "add 56 89 29";
    int offset = 0;
    int used = 0;
    int rcount = 0;
    int lastno = -999;
    int currno;
    bzero(&temp, sizeof(temp));
    sscanf(buf, "%3s%n", op, &used);  // Get the operator (add)
    offset += used;
    if(!strcmp(op, "add")){
        while( ( sscanf(buf + offset, "%99s%n", temp, &used)) == 1) {
            currno = atoi(temp);
            offset += used;
            printf("Current no: %d\tOffset: %d\n", currno, offset);
            lastno = currno;
        }
    }
    return 0;
}

There are a few things I can see that would cause your program to fail

  1. It's unecessary to write a loop like while (1) and then check for the variable inside the loop to break, because there is do {} while ();, this makes the code hard to understand.

  2. This initialization bzero(&temp, sizeof(temp)); is wrong, unecessary, and inefficient. And also, bzero() is deprecated use memset().

  3. You have a very important mistake in scanf("%s", op); you allocate space for 3 characters and type add which requires 3 + 1 for the nul terminator. The correct way to do it would be

    char op[4];
    if (sscanf(buf, "%3s", op) != 1)
     {
        fprintf("unexpected problem while reading the operator.\n");
        return -1;
     }
    
  4. sscanf(buf + offset + 4, "%s", temp) is very dangerous too, because you could easily overflow buf or temp, and besides it's much more readable like this

    sscanf(&buf[offset + 4], "%s", temp)
    

This implementation would work better

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

int main(int argc, char * argv[])
{
    char        op[4];
    const char *buffer;
    int         count;
    int         last;
    int         length;
    int         offset;
    const char *pointer;

    buffer = "add 56 89 29";
    if (sscanf(buffer, "%3s%n", op, &length) != 1)
     {
        fprintf(stderr, "unexpected problem while reading the operator.\n");
        return -1;
     }
    pointer = &buffer[length];
    if (strcmp(op, "add") != 0)
     {
        fprintf(stderr, "sorry, I can't understand this operator `%s'.\n", op);
        return -1;
     }

    count  = 0;
    last   = -999;
    offset = length;
    do {
        int number;
        int length;

        if (sscanf(pointer, "%d%n", &number, &length) != 1)
         {
            fprintf(stderr, "input format error, exiting.\n");
            return -1;
         }
        pointer += length;
        if (number == last)
            ++count;
        printf("Current no: %d\tOffset: %d\n", number, offset);

        last    = number;
        offset += length;
    } while ((count < 3) && (*pointer != '\0'));

    return 0;
}

read about the scanf() "%n" specifier.

You can also use strtol() like this

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

int main(int argc, char * argv[])
{
    char  op[4];
    char  buffer[] = "add 56 89 29";
    int   count;
    int   last;
    int   length;
    int   offset;
    char *pointer;

    if (sscanf(buffer, "%3s%n", op, &length) != 1)
     {
        fprintf(stderr, "unexpected problem while reading the operator.\n");
        return -1;
     }
    pointer = &buffer[length];
    if (strcmp(op, "add") != 0)
     {
        fprintf(stderr, "sorry, I can't understand this operator `%s'.\n", op);
        return -1;
     }

    count  = 0;
    last   = -999;
    offset = length;
    do {
        int   number;
        char *previous;

        previous = pointer;
        number   = strtol(pointer, &pointer, 10);
        if (number == last)
            ++count;
        printf("Current no: %d\tOffset: %d\n", number, offset);
        last    = number;
        offset += pointer - previous;
    } while ((count < 3) && (*pointer != '\0'));

    return 0;
}

Hi I tried your code and the following worked for me. I am not a hardcore C programmer so please forgive me if I am used any non standard C functions here and but I love to work in C.

int main(int argc, const char * argv[])
{
  char *buf = "add 56 89 29";
  int sum = 0;

  if(!strncmp(buf, "add", 3))
  {
    buf += 3;

    while(*buf != '\0')
    {
        if(isdigit(*buf) == 0)
        {
            ++buf;
            continue;
        }

        int digit;
        int num = 0;

        while(isdigit(*buf))
        {
            digit = (int)*buf - 48;
            num = (num * 10) + digit;
            ++buf;
        }

        sum += num;
        printf("Current no: %d\t Sum: %d\n", num, sum);
      }
   }

   return 0;
 }

A much better and convenient way of doing this is with strtok which you can use to get tokens one after the other.

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

int main(int argc, char * argv[]){
    char *buf = "add 56 89 29";
    char *token;
    int count = 0;

    token = strtok(buf, " ");
    while(token != NULL){
        count++;
        if(count == 1)
            continue;
        printf("%s\n", token)
        token = strtok(NULL, " ");
    }
}

Need Your Help

Fragment goes out of the screen

android android-fragments navigation-drawer

I just added fragments to the Main_Activity and now I am swapping them with the drawer layout,

Does Internet Explorer 11 still have quirks mode?

internet-explorer quirks-mode internet-explorer-11

Does Internet Explorer 11 still have quirks mode available? We use a very old system which relies on the quirks mode.