Ahmad Abu Abdou
Ahmad Abu Abdou

Reputation: 33

get numbers value from a char array in C

I have this char array:

char movimiento[]="L30 G10 L50 G-45 L-10 G50"

I want to get the value of the number after the letter 'L' and store them into an integer variable to use it afterward

eg. 30, 50, -10

I've tried this as ASCII code numbers start from 0==48 but I don't know how to store the chars into an integer: concat 3, 0 and store them into an integer.

int i = 0;
while(movimiento[i] != '\0'){
    if(movimiento[i]=='L'){
        while(movimiento[i]!=' '){
        printf("%d",(movimiento[i+1]-48));
        i++;
        }
    }
    i++;
}

Upvotes: 1

Views: 835

Answers (3)

AndersK
AndersK

Reputation: 36092

For this you could use sscanf

char movimiento[]="L30 G10 L50 G-45 L-10 G50";

struct coords { int l; int g; } coords[3];
if ( sscanf(movimiento, "L%d G%d L%d G%d L%d G%d"
  , &coords[0].l 
  , &coords[0].g
  , &coords[1].l 
  , &coords[1].g
  , &coords[2].l 
  , &coords[2].g
  ) == 6 )
{
  for (int i = 0; i < sizeof(coords)/sizeof(coords[0]); ++i)      
  {
    printf( "%d, %d\n", coords[i].l, coords[i].g );
  }
}

Upvotes: 0

David C. Rankin
David C. Rankin

Reputation: 84642

You extract each integer following a "prefix" character, by first locating the prefix character using strchr and then calling strtol beginning with the next character after the prefix.

With your string, some prefix character taken from the command line (or using 'L' by default if no argument is given) and a pointer to the beginning of your string:

int main (int argc, char **argv) {

    char movimiento[]="L30 G10 L50 G-45 L-10 G50",  /* string */
        prefix = argc > 1 ? *argv[1] : 'L',         /* prefix (L default) */
        *p = movimiento;                            /* pointer to string */

You can then locate each occurrence of the prefix in your string with:

    while ((p = strchr (p, prefix))) {  /* while next prefix found */
        ...

Then it is just a matter of attempting the conversion to long beginning with the next character:

        errno = 0;          /* set errno zero */
        char *endptr;       /* end-pointer for strtol */
        long tmp = strtol (p + 1, &endptr, 0);  /* convert from next char */

and validating the return from strtol along with endptr to check for any error condition resulting from the conversion attempt:

        if (p == endptr)    /* no digits convertedd */
            p++;            /* advance to next and try again */

If digits were converted and errno remains unset and the value of the long returned by strtol is within the range of int, then you have a good integer value, use it any way you like:

        else {
            /* if no error and in range of int -- good value */
            if (!errno && INT_MIN <= tmp && tmp <= INT_MAX) {
                int val = (int)tmp;
                printf (n ? ", %d" : "%d", val);    /* output int */
                n++;        /* increment counter */
            }
            p = endptr;     /* advance to one-past last digit converted */
        }

(note: so long as there were digits converted, p is updated with endptr to point to the next character after the last digit converted, see man 3 strtol)

You are basically done. You can check whether at least one number was output and tidy up by outputting a newline in that case with:

    if (n) putchar ('\n');  /* if integers found tidy up with newline */
}

Putting it altogether, you would have:

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

int main (int argc, char **argv) {

    char movimiento[]="L30 G10 L50 G-45 L-10 G50",  /* string */
        prefix = argc > 1 ? *argv[1] : 'L',         /* prefix (L default) */
        *p = movimiento;                            /* pointer to string */
    int n = 0;                                      /* counter */

    while ((p = strchr (p, prefix))) {  /* while next prefix found */
        errno = 0;          /* set errno zero */
        char *endptr;       /* end-pointer for strtol */
        long tmp = strtol (p + 1, &endptr, 0);  /* convert from next char */

        if (p == endptr)    /* no digits convertedd */
            p++;            /* advance to next and try again */
        else {
            /* if no error and in range of int -- good value */
            if (!errno && INT_MIN <= tmp && tmp <= INT_MAX) {
                int val = (int)tmp;
                printf (n ? ", %d" : "%d", val);    /* output int */
                n++;        /* increment counter */
            }
            p = endptr;     /* advance to one-past last digit converted */
        }
    }
    if (n) putchar ('\n');  /* if integers found tidy up with newline */
}

Example Use/Output

$ ./bin/intafterprefix
30, 50, -10

or, using the prefix 'G':

$ ./bin/intafterprefix G
10, -45, 50

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


Handle Multiple Prefixes with strpbrk

Also note if you wanted to be able to pass a string of prefixes allowing you to use "G" or "L" or "GL" as the prefix characters, you can make prefix a string and use strpbrk instead of strchr. For example using:

    char movimiento[]="L30 G10 L50 G-45 L-10 G50",  /* string */
        *prefix = argc > 1 ? argv[1] : "L",         /* prefix (L default) */
    ...
    while ((p = strpbrk (p, prefix))) { /* while next prefix found */
       ...

Example Use/Output

That would then allow you to search for any or all prefixes, e.g.

$ ./bin/intafterprefix2
30, 50, -10

$ ./bin/intafterprefix2 G
10, -45, 50

$ ./bin/intafterprefix2 GL
30, 10, 50, -45, -10, 50

Upvotes: 3

John DeBord
John DeBord

Reputation: 705

#include <ctype.h>  // isalnum
#include <stdio.h>  // printf
#include <stdlib.h> // atoi
#include <string.h> // memset

int main() {
    char arr[256] = "L30 G10 L55434 G-45 L-10 G50 L3";
    char buf[256];
    memset(buf, 0, 256);

    for (size_t i = 0; i < sizeof(arr); ++i) {
        if (arr[i] == 'L') {
            size_t count = 0;
            while (isalnum(arr[i]) || arr[i] == '-') {
                ++i;
                buf[count++] = arr[i];
            }
            int number = atoi(buf);
            printf("%d\n", number);
            memset(buf, 0, 256);
        }
    }

    return 0;
}

Upvotes: 0

Related Questions