Reading integers of unknown length correctly.

I am writing data to a file (using fprintf) and then reading it back in (using fscanf).

The result of this program is:
i(12)=12462 j(462)=0 c(D)=D

With this dummy data, I am aware that I could format the fscanf command (giving each of the integers a width) so that it would read-in correctly, but the real situation is not quite that simple.

The real data consists of a structure, consisting of 4 integers, a character, a 5th integer & a final character - at the moment, but it is a work in progress and this may change - and the integers could be anything from 0 to over 1000 and there is no easy way of identifying how many digits any of the integers will be in advance of reading them. Neither is it possible to rearrange the elements so all the integers have a different datatype between them.

I've checked the reference section but cannot see a way of getting fscanf to do this. Can I get the result I want using fscanf?

Thanks.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <stdio.h>
#include <stdlib.h>
#include <iostream>

using std::cout;
using std::endl;

int main()
{
int i=12;
int j=462;
char c='D';
	{
	// this bit writes record to file
	FILE * pfile;
	pfile=fopen("test1.dat", "a");
	fprintf(pfile, "%d", i);
	fprintf(pfile, "%d", j);
	fprintf(pfile, "%c", c);
	fclose(pfile);
	}
i=0; j=0; c='F';	// this line changes the variables before reading them back in from file
	{
	// this bit reads record from file
	FILE * rfile;
	rfile=fopen("test1.dat", "r");
	fscanf(rfile, "%d", &i);
	fscanf(rfile, "%d", &j);
	fscanf(rfile, "%c", &c);
	fclose(rfile);
	}
cout<<"i(12)="<<i<<" j(462)="<<j<<" & c(D)="<<c<<endl;	// Does the data match?
}
Last edited on
I'm confused. What is it that's unknown? The length of the integers in digits, or the number of integers that must be read?
Sorry for not being clear. It is the length of the integers in digits.
If you have say 12462 as file data and you want this read as 12 and 462 then you must have some way of knowing that the separation is between the 2 and 4. This can be either a fixed number of digits or a separation char.

If you have 4 integers stored as 123456789654 - what are the 4 integers without having additional info?
> the integers could be anything from 0 to over 1000.
Option 1 - write integers in a fixed width format.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <cstdio>               // correct C++ names for C headers
#include <cstdlib>
#include <iostream>
using std::cout;
using std::endl;

int main()
{
  int i = 12345;
  int j = 54321;
  char c = 'D';
  {
    // this bit writes record to file
    FILE *pfile;
    pfile = fopen("test1.dat", "w");
    fprintf(pfile, "%5d", i);
    fprintf(pfile, "%5d", j);
    fprintf(pfile, "%c", c);
    fclose(pfile);
  }
  int i2 = 0, j2 = 0;
  char c2 = 'F';
  {
    // this bit reads record from file
    FILE *rfile;
    rfile = fopen("test1.dat", "r");
    fscanf(rfile, "%5d", &i2);
    fscanf(rfile, "%5d", &j2);
    fscanf(rfile, "%c", &c2);
    fclose(rfile);
  }
  cout << "i(" << i << ")=" << i2
       << " j(" << j << ")=" << j2
       << " c(" << c << ")=" << c2 << endl;
}

$ g++ foo.cpp
$ ./a.out 
i(12345)=12345 j(54321)=54321 c(D)=D
$ hd test1.dat 
00000000  31 32 33 34 35 35 34 33  32 31 44                 |1234554321D|
0000000b


Option 2, write and read binary data.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <cstdio>               // correct C++ names for C headers
#include <cstdlib>
#include <iostream>
using std::cout;
using std::endl;

int main()
{
  int i = 12345;
  int j = 54321;
  char c = 'D';
  {
    // this bit writes record to file
    FILE *pfile;
    pfile = fopen("test1.dat", "wb");
    fwrite(&i, sizeof(i), 1, pfile);
    fwrite(&j, sizeof(j), 1, pfile);
    fwrite(&c, sizeof(c), 1, pfile);
    fclose(pfile);
  }
  int i2 = 0, j2 = 0;
  char c2 = 'F';
  {
    // this bit reads record from file
    FILE *rfile;
    rfile = fopen("test1.dat", "rb");
    fread(&i2, sizeof(i2), 1, rfile);
    fread(&j2, sizeof(j2), 1, rfile);
    fread(&c2, sizeof(c2), 1, rfile);
    fclose(rfile);
  }
  cout << "i(" << i << ")=" << i2
       << " j(" << j << ")=" << j2
       << " c(" << c << ")=" << c2 << endl;
}

$ g++ foo.cpp
$ ./a.out 
i(12345)=12345 j(54321)=54321 c(D)=D
$ hd test1.dat 
00000000  39 30 00 00 31 d4 00 00  44                       |90..1...D|
00000009


Thank you for the responses.

Looks like option 1 is the way to go.

My confusion lay in thinking the width added to the %d instruction had to be exact, i.e. %5d would not work with 2- or 3-digit numbers. However a little testing (based on your response) has clearly shown that it does and so I only need to use a maximum.

Thanks.
Topic archived. No new replies allowed.