0

I want to read in a dataset with numbers in strings like: (in this example each number has 3 digits: 128, 6, -3 and 224)

128  6 -3224

and write them into floats like:

nbr[0] = 128;
nbr[1] = 6;
nbr[2] = -3;
nbr[3] = 224;

then calculate something (e.g. times 2) and write them in another file of the same type:

256 12 -6448
Holt
  • 36,600
  • 7
  • 92
  • 139
  • 2
    It is unclear what you are asking. Is the first number `123` or `128`? Why do you merge the last two numbers? What have you tried, and what is the question? – Weather Vane Aug 11 '17 at 18:47
  • `-1555` ==> `-21110` ? – BLUEPIXY Aug 11 '17 at 18:53
  • 1
    Why do you say "each number has 3 digits" and then post numbers with 3, 1 and 4 digits? – Weather Vane Aug 11 '17 at 18:53
  • The first number is 128 not 123 (a mistake). –  Aug 11 '17 at 19:05
  • The first number is 128 not 123 (a mistake). All numbers have 3 digits, also counting whitespaces: 128,__6,_-3,224. They are written in a string as a combination of chars. In Fortran this is a simple task, just read in the complete line, split them into substrings each 3 digits long and the convert them to floats. In C i read in the line with: fgets with a string for each line but dont know how to split this string into substrings. here is another example for a line: string:127625141 into floats:127, 625, 141 –  Aug 11 '17 at 19:15
  • Welcome to Stack Overflow, Please read the [About] and [Ask] pages, but more urgently, please read about creating an MCVE ([MCVE]). [What have you tried?](http://mattgemmell.com/2008/12/08/what-have-you-tried/) Why floats? The numbers shown are all integers and handling integers is easier. And … oh, you've updated the question a bit. So, each number occupies three places (has a width of 3), hence `" -3"` (3 places) and `"224"` (also 3 places). So, `scanf("%3d", &integer_var)` would work, along with `printf("%3d", integer_var);`. – Jonathan Leffler Aug 11 '17 at 19:17
  • You should probably also read [Using `sscanf()` in loops](http://stackoverflow.com/questions/3975236/how-to-use-sscanf-in-loops). – Jonathan Leffler Aug 11 '17 at 19:19

1 Answers1

0

Using scanf() or its relatives is hard; very hard.

All the conversion specifiers except %c, %[…] (scan sets) and %n skip leading white space. That makes it hard to apply a numeric conversion for a fixed width.

All the code below tacitly assumes that there are no more than 20 numbers on the line — it doesn't check bounds to ensure that (but operational code most certainly should — or could use dynamic memory allocation to allocate more space for numbers when needed).

Bogus code — looks simple, but fails

/* SO 4564-1845 */
#include <stdio.h>
#include <string.h>

int main(void)
{
    char line[4096];
    while (fgets(line, sizeof(line), stdin) != 0)
    {
        int nbr[20];
        int num = 0;
        int n;
        int val;
        int off = 0;
        while (sscanf(line + off, "%3d%n", &val, &n) == 1)
        {
            printf("Got: %d - [%s] %d\n", val, line + off, n);
            off += n;
            nbr[num++] = val;
        }

        for (int i = 0; i < num; i++)
            printf("%3d", nbr[i]);
        putchar('\n');
    }
    return 0;
}

Example output

This program was called rd31. Note there is debug output here too:

$ rd31 < data
Got: 128 - [128  6 -3224
] 3
Got: 6 - [  6 -3224
] 3
Got: -32 - [ -3224
] 4
Got: 24 - [24
] 2
128  6-32 24
$

The %3d format skips the leading blank in " -3" and takes the 2 of 224 as the third character. This isn't what you want.

Working code — more complex, but passes

This code keeps using sscanf(), invoking it twice per number, which may be sub-optimal.

/* SO 4564-1845 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char line[4096];
    while (fgets(line, sizeof(line), stdin) != 0)
    {
        line[strcspn(line, "\n")] = '\0';
        int nbr[20];
        int num = 0;
        int n;
        int val;
        char data[4];
        int off = 0;
        while (sscanf(line + off, "%3c%n", data, &n) == 1)
        {
            data[n] = '\0';
            if (sscanf(data, "%d", &val) != 1)
            {
                fprintf(stderr, "Oops! [%s]\n", data);
                break;
            }
            printf("Got: [%s] - [%s] = %d (%d)\n", data, line + off, val, n);
            off += n;
            nbr[num++] = val;
        }

        for (int i = 0; i < num; i++)
            printf("%3d", nbr[i]);
        putchar('\n');
    }
    return 0;
}

This has different diagnostic output. It reads the data into a string, and then converts the string. Using data[n] = '\0'; nulls the end of what was read.

Example output

This program was called rd53.

$ rd53 < data
Got: [128] - [128  6 -3224] = 128 (3)
Got: [  6] - [  6 -3224] = 6 (3)
Got: [ -3] - [ -3224] = -3 (3)
Got: [224] - [224] = 224 (3)
128  6 -3224
$

This is what you want, I believe.

Alternative code — using sscanf() just once per value

This code uses memmove() to copy data from the line into a buffer for conversion.

/* SO 4564-1845 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char line[4096];
    while (fgets(line, sizeof(line), stdin) != 0)
    {
        line[strcspn(line, "\n")] = '\0';
        int nbr[20];
        int num = 0;
        int val;
        char data[4];
        int off = 0;
        int len = strlen(line);
        while (off < len)
        {
            memmove(data, line + off, 3);
            data[3] = '\0';
            if (sscanf(data, "%d", &val) != 1)
            {
                fprintf(stderr, "Oops! [%s]\n", data);
                break;
            }
            printf("Got: [%s] - [%s] = %d\n", data, line + off, val);
            off += 3;
            nbr[num++] = val;
        }

        for (int i = 0; i < num; i++)
            printf("%3d", nbr[i]);
        putchar('\n');
    }
    return 0;
}

You could also use atoi() or strtol() to convert the string to a number. Overflow isn't an issue with at most 3 digits to convert. Still, non-numeric data would cause some minor issues; you can protect against them better if you use strtol(), but doing so requires considerable care. (See Correct usage of strtol()? for more details.)

Example output

This program was called rd89.

$ rd89 < data
Got: [128] - [128  6 -3224] = 128
Got: [  6] - [  6 -3224] = 6
Got: [ -3] - [ -3224] = -3
Got: [224] - [224] = 224
128  6 -3224
$
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278