1

So I have a text file called num.txt that has a string of integers separated by a space.

So let's say num.txt contains: 5 3 21 64 2 5 86 52 3

I want to open the file in read format and get the numbers. So I can say

int iochar;
FILE *fp;

fp = fopen("num.txt", "r");
while ((iochar=getc(fp)) !=EOF){
    if(iochar!=' '){
        printf("iochar= %d\n", iochar); //this prints out the ascii of the character``
    }

^this works for single-digit numbers. but how should I handle numbers with two or three or more digits?

truffle
  • 455
  • 1
  • 9
  • 17

5 Answers5

4

Use strtol() for parsing a list of integers:

char buf[BUFSIZ];

while (fgets(buf, sizeof buf, stdin)) {
    char *p = buf;

    while (1) {
        char *end;

        errno = 0;
        int number = strtol(p, &end, 10);

        if (end == p || errno) {
            break;
        }

        p = end;

        printf("The number is: %d\n", number);
    }
}

If you wish to parse floating-point numbers, use strtod().

  • What if I am reading from a file, so I don't know how big the input will be to set the char bu[BUFSIZ] in this case? – truffle Jun 11 '14 at 07:03
  • @Taz Then you query the size of the file (e. g. using `fseek()` and `ftell()` or `stat` on POSIX), and use `malloc()` to allocate a large enough buffer. Mind the terminating zero! – The Paramagnetic Croissant Jun 11 '14 at 07:04
  • 1) No need for `number == 0`, simply `if (end == p) ...`. 2) Could also do `errno = 0; int number = strtol(p, &end, 10); if (errno) ...` to detect overflow. – chux - Reinstate Monica Jun 11 '14 at 11:12
  • BTW: `fgets()` will only read 1 line (up to a `'\n'`), not necessarily the whole file as comment suggests. Likely will work as OP says file is "string of integers separated by a space". – chux - Reinstate Monica Jun 11 '14 at 11:31
  • @chux You're right, added the overflow detection and handling of multiple-line files as well. – The Paramagnetic Croissant Jun 11 '14 at 18:36
  • Instead of using malloc(). can I use fseek and ftell to get the length of the file, store it into a variable length. and declare an array like this char page_array[length]? – truffle Jun 12 '14 at 08:16
2

Use a buffer to store read bytes until you hit the separator, then parse the string using atoi:

char simpleBuffer[12];    //max 10 int digits + 1 negative sign + 1 null char string....if you read more, then you probably don't    have an int there....
int  digitCount = 0;
int iochar;

int readNumber; //the number read from the file on each iteration
do {

    iochar=getc(fp);

    if(iochar!=' ' && iochar != EOF) {
        if(digitCount >= 11)
            return 0;   //handle this exception in some way

        simpleBuffer[digitCount++] = (char) iochar;
    }
    else if(digitCount > 0)
        simpleBuffer[digitCount] = 0; //append null char to end string format

        readNumber = atoi(simpleBuffer);    //convert from string to int
       //do whatever you want with the readNumber here...

       digitCount = 0;  //reset buffer to read new number
    }

} while(iochar != EOF);
warwolf
  • 65
  • 7
1

Why do not you read the data into buffer and use sscanf to read the integers.

char nums[900];
if (fgets(nums, sizeof nums, fp)) {
    // Parse the nums into integer. Get the first integer.
    int n1, n2;
    sscanf(nums, "%d%d", &n1, &n2);
    // Now read multiple integers
}
doptimusprime
  • 9,115
  • 6
  • 52
  • 90
0
char ch;
FILE *fp;
fp = fopen("num.txt","r"); // read mode

if( fp != NULL ){
    while( ( ch = fgetc(fp) ) != EOF ){
        if(ch != ' ')
           printf("%c",ch);
    }
     fclose(fp);
}
Himanshu
  • 4,327
  • 16
  • 31
  • 39
  • `char ch;` --> `int ch;` – chux - Reinstate Monica Jun 11 '14 at 11:16
  • @chux why `int`? if we use `int` then also we will get ascii value that will be same like this. – Himanshu Jun 11 '14 at 11:19
  • 1) What [ASCII](http://en.wikipedia.org/wiki/ASCII) value? 2) On platforms where `char` is `unsigned char`, `while( ( ch = fgetc(fp) ) != EOF )` is always true. 3) On platforms where `char` is `signed char` and `EOF == -1`, if code reads a `ch` with the value of -1, it is indistinguishable from `EOF`. – chux - Reinstate Monica Jun 11 '14 at 11:24
  • @chux suppose `1` is written in file and by using `fgetc(fp)` we can get `1` i.e char but if we assign it to integer variable it will be `49` not `1`. As in below answer also u can see, he is comparing `iochar != EOF` where `iochar` is char type. – Himanshu Jun 11 '14 at 11:39
  • No. On reading a `'1'` using `fgetc()` (assuming ASCII), the value returned is 49 regardless in `ch` is `char ch` or `int ch`. The value stored in `ch` is 49 either way too. Using `printf("%c",ch);`, the output is `'1'`, either way. OP is correctly using `int iochar`. "As in below answer", note that order of answers change, so I am not certain of your thought on that - best to reference by poster's name. – chux - Reinstate Monica Jun 11 '14 at 11:52
  • @chux I'm agree with your answer, as you are getting character value in integer variable and converting into integer using `sum += iochar - '0';` – Himanshu Jun 11 '14 at 12:14
0

In keeping with OPs style:
Detect groups of digits and accumulate the integer as you go.

As OP did not specify the type of integer and all examples were positive, assume type unsigned.

#include <ctype.h>

void foo(void) {
  int iochar;
  FILE *fp;

  fp = fopen("num.txt", "r");
  iochar = getc(fp);
  while (1) {
    while (iochar == ' ')
      iochar = getc(fp);
    if (iochar == EOF)
      break;
    if (!isdigit(iochar))
      break;  // something other than digit or space
    unsigned sum = 0;
    do {

      /* Could add overflow protection here */

      sum *= 10;
      sum += iochar - '0';
      iochar = getc(fp);
    } while (isdigit(iochar));
    printf("iochar = %u\n", sum);
  }
  fclose(fp);
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256