Nahum
Nahum

Reputation: 7197

Get numbers separated by commas

I got the following string:

"312 ,22 ,+12 , -12 , 5331"

it is possible to have more than 1 space between numbers.

I need to convert it to an array like that:

int arr[] = {312,22,-12,12,5331};

Is there a pretty and elegant way to do this with C89?

Upvotes: 3

Views: 4685

Answers (6)

Gandaro
Gandaro

Reputation: 3443

Use strtok + atoi:

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

int main(int argc, char const *argv[])
{
    char numbers_str[] = "312 ,22 ,+12 ,-12 ,5331", *currnum;
    int numbers[5], i = 0;

    while ((currnum = strtok(i ? NULL : numbers_str, " ,")) != NULL)
        numbers[i++] = atoi(currnum);

    printf("%d\n", numbers[3]);
    return 0;
}

Upvotes: 5

Major Eccles
Major Eccles

Reputation: 491

I don't think there is any standard function to do this. This is such a common operation that most programmers have something like the following code in their personal toolkit. The answer lies in using the strtol() function. I quickly hacked the following from the man page for strtol:

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

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

  char sep = ',';  
  char string[] = "  312 ,, 22 ,+12 ,-12 ,5331";
  /*
   * count separators
   */
  char *str = string;
  int j = 0;
  while (*str)
    {
      printf ("str=%c\n", *str);
      if (*str == sep)
    j++;
      str++;
    }
  int n = j + 1;
  printf ("n=%d\n", n);
  long int *arr = malloc (n * sizeof (long int));

  char *endptr = NULL;
  str = string;
  j = 0;
  do
    {
      arr[j++] = strtol (str, &endptr, 10);
      if (*endptr != '\0')
    {
      while (*endptr != sep)
        endptr++;
      str = endptr + 1;
    }
    }
  while (j < n && *endptr);
  for (j = 0; j < n; j++)
    {
      printf ("%d:%ld\n", j, arr[j]);
    }
  exit (EXIT_SUCCESS);

} /* main */

Hope this is helpful

Upvotes: 0

hmjd
hmjd

Reputation: 122001

Suggest:

  1. Use strtok() to split the string into tokens.
  2. Use atoi() to convert the tokens to ints.

For allocating the array to store the ints you could either:

  1. Allocate as each token is processed, using realloc(), or
  2. Have two passses through the string, with the first pass counting the tokens in the string and malloc() the array in a single operation.

Example:

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

int* make_int_array(char* a_str, size_t* const a_elem_count)
{
    int* result      = 0;
    char* tmp        = a_str;
    char* last_comma = 0;

    /* Count how many ints will be extracted. */
    *a_elem_count = 0;
    while (*tmp)
    {
        if (',' == *tmp)
        {
            (*a_elem_count)++;
            last_comma = tmp;
        }
        tmp++;
    }

    /* Add space for trailing int. */
    *a_elem_count += last_comma < (a_str + strlen(a_str) - 1);

    result = malloc(sizeof(int) * (*a_elem_count));

    if (result)
    {
        size_t idx  = 0;
        char* token = strtok(a_str, ",");

        while (token)
        {
            assert(idx < *a_elem_count);
            *(result + idx++) = atoi(token);
            token = strtok(0, ",");
        }
    }

    return result;
}

int main()
{
    char s[] = "312 ,22 ,+12 ,-12 ,5331";
    int* int_list;
    size_t int_list_count = 0;

    printf("s=[%s]\n\n", s);

    int_list = make_int_array(s, &int_list_count);

    if (int_list)
    {
        size_t i;
        for (i = 0; i < int_list_count; i++)
        {
            printf("%d\n", *(int_list + i));
        }
        printf("\n");
        free(int_list);
    }

    return 0;
}

Output:

s=[312 ,22 ,+12 ,-12 ,5331]

312
22
12
-12
5331

Upvotes: 1

Ed Heal
Ed Heal

Reputation: 60017

Why not use sscanf(str+offset, "%d,%n", &newValue, &offset) repeatedly until it fails.

Upvotes: 0

Chris Gessler
Chris Gessler

Reputation: 23123

I'm not a C programmer, but ANSI C (or C89) does have a "split" function called strtok.

#include <string.h>
#include <stddef.h>

...

char string[] = "words separated by spaces -- and, punctuation!";
const char delimiters[] = " .,;:!-";
char *token;

...

token = strtok (string, delimiters);  /* token => "words" */
token = strtok (NULL, delimiters);    /* token => "separated" */
token = strtok (NULL, delimiters);    /* token => "by" */
token = strtok (NULL, delimiters);    /* token => "spaces" */
token = strtok (NULL, delimiters);    /* token => "and" */
token = strtok (NULL, delimiters);    /* token => "punctuation" */
token = strtok (NULL, delimiters);    /* token => NULL */

Upvotes: 0

ouah
ouah

Reputation: 145899

Yes, you can use the sscanf function to get the integers into the array elements. I assume here there is a small fixed number of integers in your string.

Upvotes: 0

Related Questions