By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,247 Members | 1,517 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,247 IT Pros & Developers. It's quick & easy.

Reading numbers from a file

P: n/a
Hi,
I'm reading a string of numbers from a file (using Borland C++ Builder
6), and I'm doing it like this: first I use FileRead to store all the
data in the file to a char* variable (appropriately called 'data').
Then, I read every number using

char *ptr;
int value;

[...]

ptr = &data[position];
sscanf (ptr, "%i", &value);
position += IntToStr(value).Length();
numbers[i] = value;

(All of it inside of a loop, of course).
This method seems to be working OK, but Borland CodeGuard tells me that
there's an access overrun in each sscanf call, so I guess there is a
better way of doing it. Could you please help me?
Big thanks,

LuTHieR

Jun 10 '06 #1
Share this Question
Share on Google+
10 Replies


P: n/a
LuTHieR wrote:
Hi,
I'm reading a string of numbers from a file (using Borland C++ Builder
6), and I'm doing it like this: first I use FileRead to store all the
data in the file to a char* variable (appropriately called 'data').
Then, I read every number using

char *ptr;
int value;

[...]

ptr = &data[position];
sscanf (ptr, "%i", &value);
position += IntToStr(value).Length();
numbers[i] = value;

(All of it inside of a loop, of course).
This method seems to be working OK, but Borland CodeGuard tells me that
there's an access overrun in each sscanf call, so I guess there is a
better way of doing it. Could you please help me?
Big thanks,

LuTHieR


In C++ you should try avoid using the C I/O functions unless you have a
good reason to be using them. sscanf and its variants are notoriously
easy to use incorrectly. Here is an example of how to do the same using
C++'s stringstreams. Modify to your needs:

#include <iostream>
#include <sstream>

int main()
{
char data[] = "2 3 5 7 11 13 17 19 23 29 31 37 41 43 47" ;
std::istringstream ss(data) ;
int i ;
while (ss >> i)
std::cout << i << std::endl ;
}

--
Alan Johnson
Jun 10 '06 #2

P: n/a
Thanks :)
One more question...if data contains a String before the actual data
(something like data[] = "label 1 2 3 4 5 6 7 8"), how can I easily
read it?
Thanks again

LuTHieR

Alan Johnson ha escrito:
LuTHieR wrote:
Hi,
I'm reading a string of numbers from a file (using Borland C++ Builder
6), and I'm doing it like this: first I use FileRead to store all the
data in the file to a char* variable (appropriately called 'data').
Then, I read every number using

char *ptr;
int value;

[...]

ptr = &data[position];
sscanf (ptr, "%i", &value);
position += IntToStr(value).Length();
numbers[i] = value;

(All of it inside of a loop, of course).
This method seems to be working OK, but Borland CodeGuard tells me that
there's an access overrun in each sscanf call, so I guess there is a
better way of doing it. Could you please help me?
Big thanks,

LuTHieR


In C++ you should try avoid using the C I/O functions unless you have a
good reason to be using them. sscanf and its variants are notoriously
easy to use incorrectly. Here is an example of how to do the same using
C++'s stringstreams. Modify to your needs:

#include <iostream>
#include <sstream>

int main()
{
char data[] = "2 3 5 7 11 13 17 19 23 29 31 37 41 43 47" ;
std::istringstream ss(data) ;
int i ;
while (ss >> i)
std::cout << i << std::endl ;
}

--
Alan Johnson


Jun 10 '06 #3

P: n/a
Don't bother answering, it was as simple as using the >> operator to a
string type.
Thanks again

LuTHieR

LuTHieR ha escrito:
Thanks :)
One more question...if data contains a String before the actual data
(something like data[] = "label 1 2 3 4 5 6 7 8"), how can I easily
read it?
Thanks again

LuTHieR

Alan Johnson ha escrito:
LuTHieR wrote:
Hi,
I'm reading a string of numbers from a file (using Borland C++ Builder
6), and I'm doing it like this: first I use FileRead to store all the
data in the file to a char* variable (appropriately called 'data').
Then, I read every number using

char *ptr;
int value;

[...]

ptr = &data[position];
sscanf (ptr, "%i", &value);
position += IntToStr(value).Length();
numbers[i] = value;

(All of it inside of a loop, of course).
This method seems to be working OK, but Borland CodeGuard tells me that
there's an access overrun in each sscanf call, so I guess there is a
better way of doing it. Could you please help me?
Big thanks,

LuTHieR


In C++ you should try avoid using the C I/O functions unless you have a
good reason to be using them. sscanf and its variants are notoriously
easy to use incorrectly. Here is an example of how to do the same using
C++'s stringstreams. Modify to your needs:

#include <iostream>
#include <sstream>

int main()
{
char data[] = "2 3 5 7 11 13 17 19 23 29 31 37 41 43 47" ;
std::istringstream ss(data) ;
int i ;
while (ss >> i)
std::cout << i << std::endl ;
}

--
Alan Johnson


Jun 10 '06 #4

P: n/a
LuTHieR wrote:
Thanks :)
One more question...if data contains a String before the actual data
(something like data[] = "label 1 2 3 4 5 6 7 8"), how can I easily
read it?


Please don't top-post. Your comments belong following or interspersed
with properly trimmed quotes. See below for further information:
<http://www.parashift.com/c++-faq-lite/how-to-post.html#faq-5.4>


Brian
Jun 10 '06 #5

P: n/a

Default User ha escrito:
LuTHieR wrote:
Thanks :)
One more question...if data contains a String before the actual data
(something like data[] = "label 1 2 3 4 5 6 7 8"), how can I easily
read it?


Please don't top-post. Your comments belong following or interspersed
with properly trimmed quotes. See below for further information:
<http://www.parashift.com/c++-faq-lite/how-to-post.html#faq-5.4>


Brian


Sorry 0:-)

Jun 10 '06 #6

P: n/a
> In C++ you should try avoid using the C I/O functions unless you have a
good reason to be using them. sscanf and its variants are notoriously
easy to use incorrectly. Here is an example of how to do the same using
C++'s stringstreams. Modify to your needs:

#include <iostream>
#include <sstream>

int main()
{
char data[] = "2 3 5 7 11 13 17 19 23 29 31 37 41 43 47" ;
std::istringstream ss(data) ;
int i ;
while (ss >> i)
std::cout << i << std::endl ;
}

--
Alan Johnson


I must be really dumb :S Basing on the example you gave me, I was
trying to read many lines from the string, but on the second iteration
of the for loop, ss2 >> j evaluates to false, thus outputting just the
first line of the data string, and I can't figure out why. I guess the
problem is the use of the str method, but I don't know how to assign
the line variable to the istringstream in another way. Here's the code:
#include <iostream>
#include <sstream>

int main()
{
char data[] = "2 3 5 7 11 13\n 17 19 23 29 31\n 37 41 43 47" ;
char line[20];
int i,j;
std::istringstream ss(data);
std::istringstream ss2;

for (i=0; i<3; i++) {
ss.getline(line, 20);
ss2.str(line);
while (ss2 >> j)
std::cout << j << std::endl;
}
}

Thanks in advance.

Jun 11 '06 #7

P: n/a
LuTHieR wrote:
In C++ you should try avoid using the C I/O functions unless you have a
good reason to be using them. sscanf and its variants are notoriously
easy to use incorrectly. Here is an example of how to do the same using
C++'s stringstreams. Modify to your needs:

#include <iostream>
#include <sstream>

int main()
{
char data[] = "2 3 5 7 11 13 17 19 23 29 31 37 41 43 47" ;
std::istringstream ss(data) ;
int i ;
while (ss >> i)
std::cout << i << std::endl ;
}

--
Alan Johnson


I must be really dumb :S Basing on the example you gave me, I was
trying to read many lines from the string, but on the second iteration
of the for loop, ss2 >> j evaluates to false, thus outputting just the
first line of the data string, and I can't figure out why. I guess the
problem is the use of the str method, but I don't know how to assign
the line variable to the istringstream in another way. Here's the code:
#include <iostream>
#include <sstream>

int main()
{
char data[] = "2 3 5 7 11 13\n 17 19 23 29 31\n 37 41 43 47" ;
char line[20];
int i,j;
std::istringstream ss(data);
std::istringstream ss2;

for (i=0; i<3; i++) {
ss.getline(line, 20);
ss2.str(line);
while (ss2 >> j)
std::cout << j << std::endl;
}
}

Thanks in advance.


When the while loop ends, it is because ss2 has reached EOF (or end of
string, as the case may be), and its failbit is set. You need to clear
the failbit, which you can do by calling ss2.clear() at the beginning of
the for loop. However, you can avoid the issue completely by
constructing ss2 inside the for loop.

While I'm making suggestions, let's also get rid of the arbitrary number
20 for a line length, by using std::string and std::getline. Making
both of these changes, your code will look something like:

#include <iostream>
#include <sstream>
#include <string>

int main()
{
std::string data = "2 3 5 7 11 13\n 17 19 23 29 31\n 37 41 43 47";
std::istringstream ss(data);
int j;

for (size_t i=0; i<3; i++)
{
std::string line;
std::getline(ss, line);
std::istringstream ss2(line);
while (ss2 >> j)
std::cout << j << std::endl;
}
}
Unless you have a reason, though, there is no need to process this on a
line by line basis. operator>> will skip newlines just like any other
whitespace, and you could reduce this to:

#include <iostream>
#include <sstream>
#include <string>

int main()
{
std::string data = "2 3 5 7 11 13\n 17 19 23 29 31\n 37 41 43 47";
std::istringstream ss(data);
int j ;

while (ss >> j)
std::cout << j << std::endl ;
}

--
Alan Johnson
Jun 11 '06 #8

P: n/a
In article <1149954290.927527.16870
@h76g2000cwa.googlegroups.com>, gr*************@gmail.com
says...
Hi,
I'm reading a string of numbers from a file (using Borland C++ Builder
[ ... ]
This method seems to be working OK, but Borland CodeGuard tells me that
there's an access overrun in each sscanf call, so I guess there is a
better way of doing it. Could you please help me?


[...and elsethread mentioned wanting to ignore other data
in the file]

You've gotten a number of replies, but I thought I'd add
one more way this could be done. At least as I understand
the situation, you only want to read the numbers from the
file, and ignore everything else.

One way to handle this would be to create a locale to
reflect that for your purposes, the file contains only
numbers (digits) and other "stuff" you're going to ignore
between the digits. From a viewpoint of reading the
numbers, everything is basically the same as whitespace
-- it separates one number from another, but otherwise
has no meaning. Therefore, we start by creating a ctype
facet that says it IS whitespace:

class number_only: std::ctype<char> {
number_only() : std::ctype<char>(get_table()) {}
static std::ctype_base::mask const *get_table() {
static std::ctype_base::mask *rc;

if ( rc == 0) {

// create a character classification table
rc = new std::ctype_base::mask
[std::ctype<char>::table_size];

// say that _everything_ is whitespace
std::fill_n(rc, std::ctype,char>::table_size,
std::ctype_base::space);

// except for [0-9]:
for (int i='0'; i<='9'; i++)
rc[i] = std::ctype_base::digit;
]
return rc;
}
};

From there, we imbue the stream with a locale using that
facet, and we can just treat it as a file of numbers:

int main() {
std::ifstream x(wherever);

number_only n;
x.imbue(std::locale(std::locale(), n);

// now we can read in numbers, and everything
// else is ignored automagically.
std::vector<int> numbers;

// read in all the numbers:
std::copy(std::istream_iterator<int>(x),
std::istream_iterator<int>(),
std::back_inserter(numbers));

// just for grins, we'll display them, one per line:
std::copy(numbers.begin(), numbers.end(),
std::ostream_iterator<int>(std::cout, "\n"));

return 0;
}

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jun 12 '06 #9

P: n/a
Alan Johnson wrote:
When the while loop ends, it is because ss2 has reached EOF (or end of
string, as the case may be), and its failbit is set. You need to clear
the failbit, which you can do by calling ss2.clear() at the beginning of
the for loop. However, you can avoid the issue completely by
constructing ss2 inside the for loop.

While I'm making suggestions, let's also get rid of the arbitrary number
20 for a line length, by using std::string and std::getline. Making
both of these changes, your code will look something like:

#include <iostream>
#include <sstream>
#include <string>

int main()
{
std::string data = "2 3 5 7 11 13\n 17 19 23 29 31\n 37 41 43 47";
std::istringstream ss(data);
int j;

for (size_t i=0; i<3; i++)
{
std::string line;
std::getline(ss, line);
std::istringstream ss2(line);
while (ss2 >> j)
std::cout << j << std::endl;
}
}
Unless you have a reason, though, there is no need to process this on a
line by line basis. operator>> will skip newlines just like any other
whitespace, and you could reduce this to:

#include <iostream>
#include <sstream>
#include <string>

int main()
{
std::string data = "2 3 5 7 11 13\n 17 19 23 29 31\n 37 41 43 47";
std::istringstream ss(data);
int j ;

while (ss >> j)
std::cout << j << std::endl ;
}

--
Alan Johnson


Thanks once again. In fact, the line by line processing is required, I
need to know how many numbers have been read in every line and output
an error if there are more/less numbers than expected. Oh, and the line
length set to 20 was only for the example :)
Regards,

LuTHieR

Jun 12 '06 #10

P: n/a

Jerry Coffin wrote:
In article <1149954290.927527.16870
@h76g2000cwa.googlegroups.com>, gr*************@gmail.com
says...
Hi,
I'm reading a string of numbers from a file (using Borland C++ Builder


[ ... ]
This method seems to be working OK, but Borland CodeGuard tells me that
there's an access overrun in each sscanf call, so I guess there is a
better way of doing it. Could you please help me?


[...and elsethread mentioned wanting to ignore other data
in the file]

You've gotten a number of replies, but I thought I'd add
one more way this could be done. At least as I understand
the situation, you only want to read the numbers from the
file, and ignore everything else.

One way to handle this would be to create a locale to
reflect that for your purposes, the file contains only
numbers (digits) and other "stuff" you're going to ignore
between the digits. From a viewpoint of reading the
numbers, everything is basically the same as whitespace
-- it separates one number from another, but otherwise
has no meaning. Therefore, we start by creating a ctype
facet that says it IS whitespace:

class number_only: std::ctype<char> {
number_only() : std::ctype<char>(get_table()) {}
static std::ctype_base::mask const *get_table() {
static std::ctype_base::mask *rc;

if ( rc == 0) {

// create a character classification table
rc = new std::ctype_base::mask
[std::ctype<char>::table_size];

// say that _everything_ is whitespace
std::fill_n(rc, std::ctype,char>::table_size,
std::ctype_base::space);

// except for [0-9]:
for (int i='0'; i<='9'; i++)
rc[i] = std::ctype_base::digit;
]
return rc;
}
};

From there, we imbue the stream with a locale using that
facet, and we can just treat it as a file of numbers:

int main() {
std::ifstream x(wherever);

number_only n;
x.imbue(std::locale(std::locale(), n);

// now we can read in numbers, and everything
// else is ignored automagically.
std::vector<int> numbers;

// read in all the numbers:
std::copy(std::istream_iterator<int>(x),
std::istream_iterator<int>(),
std::back_inserter(numbers));

// just for grins, we'll display them, one per line:
std::copy(numbers.begin(), numbers.end(),
std::ostream_iterator<int>(std::cout, "\n"));

return 0;
}

--
Later,
Jerry.

The universe is a figment of its own imagination.


Now that's a clever solution if I ever saw one. You are right, I only
want to read numbers from the file, but I also need to know if there is
anything *strange* within the file to warn the user that it might be
corrupted, so I'm afraid your solution might not work in this case.
However I found it a really interesting way to solve the problem, and
you can be sure that I'll save it and use it in the future :)
Thanks,

LuTHieR

Jun 12 '06 #11

This discussion thread is closed

Replies have been disabled for this discussion.