473,385 Members | 1,536 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

Strtol vs sscanf

Hello: I am trying to write code to read in a bunch of lines from
stdin,
each containing a (variable) number of integers and writing each
integer
in a separate line to stdout.

I came up the code below.

I could not get sscanf to work because it does not increment its
position
on conversion (like scanf does). Is there some workaround for it ?

Please criticize the code below: I have a feeling I am missing a simple
and elegant solution, since the problem is so simple itself.

Moreover, there is a *bug* in the code: what happens when I have a 0 as
a number ?
Reading will stop then. How do I get around that ?

Are my malloc() error statements correct ? In general, is it not better
to state in
the malloc error's before exiting which variables failed to get
malloc'ed ?
#include <stdio.h>
#define MAX 80

int main() {
int i, n;
char *line, **errline, *lineA, *lineB;

line=malloc(MAX*sizeof(char));
errline=malloc(sizeof(*errline));

if ((line == NULL) || (errline==NULL)) {
fprintf(stderr, "Could not allocate memory");
exit(-1);
}

while (fgets(line,MAX, stdin)!=NULL) {
lineA=line;
while ((n=(int)strtol(lineA, errline, 0))!=0) {
printf("%d \n", n);
lineA=*errline;
// printf("Line is now at %s \n",lineA);
}
}
}

Nov 14 '05 #1
3 4725
whisper wrote:
Hello: I am trying to write code to read in a bunch of lines from
stdin,
each containing a (variable) number of integers and writing each
integer
in a separate line to stdout.

I came up the code below.

I could not get sscanf to work because it does not increment its
position
on conversion (like scanf does). Is there some workaround for it ?
One possibility is to use the "%n" specifier in the
sscanf() format string. This tells you how many characters
the sscanf() operation "swallowed," which you can use to
get the next sscanf() to begin its scan after the already-
used characters.
Please criticize the code below: I have a feeling I am missing a simple
and elegant solution, since the problem is so simple itself.
You are certainly working *much* too hard. I see no
reason to use malloc() at all for this task; every dynamic
allocation requires a pointer, but it does not follow that
every pointer requires a dynamic allocation!
Moreover, there is a *bug* in the code: what happens when I have a 0 as
a number ?
Reading will stop then. How do I get around that ?
sscanf() will detect the "no more data" condition and
report it "out of band," independently of the converted
number, so you need not reserve any special value. strtol()
sets a pointer (`errline' in your code) to the first byte
after converted material, or to the start of the string if
nothing could be converted; use that pointer to discover
when you've reached the end of the line.
Are my malloc() error statements correct ? In general, is it not better
to state in
the malloc error's before exiting which variables failed to get
malloc'ed ?
Halting the program on a malloc() failure is reasonable
for some programs, unreasonable for others; there is no one
error-handling strategy that works in all cases. exit(-1)
is a dubious practice, since -1 will have different meanings
on different C implementations; it's better to use either
EXIT_SUCCESS or EXIT_FAILURE (both from <stdlib.h>, which
you should have included anyhow since that's where malloc()
and strtol() are declared -- in fact, your compiler ought to
have given a diagnostic for this use of malloc() without a
declaration).

Printing out the names of internal variables involved
in a failure condition may be useful to you the programmer
(it may help your debugging), but is spectacularly unhelpful
to an end user who doesn't have access to your source code.
If your newsreader told you "Could not allocate memory for
buffer_3 in function filter_redo_delegate()", would you be
able to make any sense of it?
#include <stdio.h>
#define MAX 80

int main() {
int i, n;
char *line, **errline, *lineA, *lineB;

line=malloc(MAX*sizeof(char));
errline=malloc(sizeof(*errline));

if ((line == NULL) || (errline==NULL)) {
fprintf(stderr, "Could not allocate memory");
exit(-1);
}

while (fgets(line,MAX, stdin)!=NULL) {
lineA=line;
while ((n=(int)strtol(lineA, errline, 0))!=0) {
printf("%d \n", n);
lineA=*errline;
// printf("Line is now at %s \n",lineA);
}
}
}


Here's a considerably simpler version, using no dynamic
memory allocation at all:

#include <stdio.h>
#include <stdlib.h>
#define MAX 80

int main(void) {
char line[MAX];

while (fgets(line, sizeof line, stdin) != NULL) {
char *here, *next;
for (here = line; ; here = next) {
long value;
value = strtol(here, &next, 0);
if (next == here)
break;
printf ("%ld\n", value);
}
}

return EXIT_SUCCESS;
}

With not much more effort you could detect garbage inputs
like "123XYZ" and "99999999999999999999999999999999999999".

--
Er*********@sun.com

Nov 14 '05 #2
whisper wrote:
Hello: I am trying to write code to read in a bunch of lines from
stdin,
each containing a (variable) number of integers and writing each
integer
in a separate line to stdout.
Question: Do you want to know whether a line break happened between
numbers?
I came up the code below.

I could not get sscanf to work because it does not increment its
position
on conversion (like scanf does). Is there some workaround for it ?

Please criticize the code below: I have a feeling I am missing a simple
and elegant solution, since the problem is so simple itself.

Moreover, there is a *bug* in the code: what happens when I have a 0 as
a number ?
Reading will stop then. How do I get around that ?

Are my malloc() error statements correct ? In general, is it not better
to state in
the malloc error's before exiting which variables failed to get
malloc'ed ?
#include <stdio.h> #include <stdlib.h> /* malloc, exit */ #define MAX 80 Rather call that LINE_MAX or some such: It is clearer.
int main() {
int i, n; i is unused char *line, **errline, *lineA, *lineB; lineB is unused
line=malloc(MAX*sizeof(char)); sizeof(char) is _always_ 1. Use MAX*sizeof *line or just MAX. errline=malloc(sizeof(*errline));

if ((line == NULL) || (errline==NULL)) {
fprintf(stderr, "Could not allocate memory"); Insert
free(line);
here: If line==NULL, free(line) does nothing, otherwise
the malloc()ed memory gets freed.
Better yet: Check immediately after trying to malloc().
Apart from that: Instead of char **errline, use char *endptr
and pass &endptr -- saves one malloc() and free() and is IMO
less opaque.
exit(-1); exit(EXIT_FAILURE); }

while (fgets(line,MAX, stdin)!=NULL) {
lineA=line;
while ((n=(int)strtol(lineA, errline, 0))!=0) { you are losing information here, moreover, if LONG_MAX>INT_MAX
(or LONG_MIN<INT_MIN), you are in trouble, having invoked undefined
behavior. printf("%d \n", n);
lineA=*errline;
// printf("Line is now at %s \n",lineA);
}
} Do not forget to free()!!!
free(line);
free(errline); }


Your program stops (without errors encountered) only at
reading of EOF. Is that intended?
Moreover: Your use of strtol is rather strange.
I will comment further on that later on.

If you want to use a scanf()-like function, do not use sscanf(),
rather use fscanf() for an arbitrary number of numbers per line:

#include <stdio.h>

int main (void)
{
int num;

while (fscanf(stdin," %d",&num)==1)
printf("%d\n", num);

return 0;
}

Back to strol:
I would do it like that

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>

#define LINE_MAX 80

int main (void) {
int num;
char *line, *nptr, *endptr;

line = malloc(LINE_MAX*sizeof *line);
if ( line == NULL ) {
fprintf(stderr, "Could not allocate memory");
exit(EXIT_FAILURE);
}

while (fgets(line,LINE_MAX, stdin) != NULL) {
int err=0;
nptr=line;
while (!err) {
long tmp = strtol(nptr, &endptr, 0);

switch (tmp) {
case LONG_MIN:
case LONG_MAX:
/* Check for range error */
errno = 0;
tmp = strtol(nptr, &endptr, 0);
if (errno==ERANGE)
err = 1;
break;
case 0:
if (nptr==endptr) {
err = 1;
break;
}
default:
if (tmp>INT_MAX || tmp<INT_MIN) {
err = 1;
break;
}

printf("%d\n",num=(int)tmp);
break;
}
nptr = endptr;
}
}

free(line);
return 0;
}
Note, however, that fgets() is not safe. Have a look at the
FAQ or google for one of the various Pop's Device vs fgets()
discussions.
For the future: Read the manpage of functions you are using
(google for "man strtol", e.g.)

Cheers
Michael
--
E-Mail: Mine is a gmx dot de address.
Nov 14 '05 #3


whisper wrote:

Hello: I am trying to write code to read in a bunch of lines from
stdin,
each containing a (variable) number of integers and writing each
integer
in a separate line to stdout.

I came up the code below.

I could not get sscanf to work because it does not increment its
position
on conversion (like scanf does). Is there some workaround for it ?

Please criticize the code below: I have a feeling I am missing a simple
and elegant solution, since the problem is so simple itself.

Moreover, there is a *bug* in the code: what happens when I have a 0 as
a number ?
Reading will stop then. How do I get around that ?

Are my malloc() error statements correct ? In general, is it not better
to state in
the malloc error's before exiting which variables failed to get
malloc'ed ?

#include <stdio.h>
#define MAX 80

int main() {
int i, n;
char *line, **errline, *lineA, *lineB;

line=malloc(MAX*sizeof(char));
errline=malloc(sizeof(*errline));

if ((line == NULL) || (errline==NULL)) {
fprintf(stderr, "Could not allocate memory");
exit(-1);
}

while (fgets(line,MAX, stdin)!=NULL) {
lineA=line;
while ((n=(int)strtol(lineA, errline, 0))!=0) {
This is not how you use strtol - you seem to be confused about how to
use the second argument. The proper way is:

char *ptr;
long int n;
char *line;

/* assume 'line' has been filled with a null-terminated string */

n = strtol( line, &ptr, 0 );

At this point, ptr points to the first character in 'line' that was not
read as part of the number that translates into 'n'.

printf("%d \n", n);
lineA=*errline;
// printf("Line is now at %s \n",lineA);
}
}
}


--
Fred L. Kleinschmidt
Boeing Associate Technical Fellow
Technical Architect, Common User Interface Services
M/S 2R-94 (206)544-5225
Nov 14 '05 #4

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

11
by: nrk | last post by:
Isn't: char s = "--4"; char *endptr; strtol(s, &endptr, 0); supposed to return 0 and set endptr to s? I have run into an implementation (not gcc, gcc does what I expect) that is returning...
10
by: Peter Dunker | last post by:
Hi, I will check a String which should contain a HEX value. I know that strtol is the right function for this job. But what happens when I will check a hex string with 8 bytes? That I can...
16
by: David Scarlett | last post by:
Another two questions... Is behaviour defined when the first argument of strtol is NULL? And if the string contains only digits, is the 2nd argument (assuming it wasn't NULL) guaranteed to be...
2
by: Marlene Stebbins | last post by:
Suppose I'm using strtol() to convert a command line string to a number and I want to check that the input to strtol() is not non-numeric. strtol() returns zero if input is non-numeric, so I can...
10
by: baumann | last post by:
hi, 1) first test program code #include <stdio.h> int main(void) { char * file = "aaa 23 32 m 2.23 ammasd"; int i2,i3;
4
by: baumann | last post by:
hi all there has 2 program 1) the first test program code #include <stdio.h> int main(void) {
5
by: jchludzinski | last post by:
I'm using strtok() to parse thru a line and read different numbers: float value; char *token; token = strtok( line, " " ); .... sscanf( token, "%f", &value ); These results are less...
3
by: dstevel | last post by:
The signature for strtol is: strtol( const char*, char**, int) So.. if we start with a passed "const char*" (pointer to const char), then we can't create a non-const char pointer pointer to...
8
by: lovecreatesbea... | last post by:
Does this part of C code call and check strtol() correctly? port = strtol(argv, &endptr, 10); if (argv == endptr){ fprintf(stderr, "%s\n", "Invalid port number form"); return 1; } if (port ==...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.