Re: Strtol vs sscanf

From: Eric Sosman (eric.sosman_at_sun.com)
Date: 10/20/04


Date: Wed, 20 Oct 2004 17:26:00 -0400

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".

-- 
Eric.Sosman@sun.com


Relevant Pages

  • Re: malloc() and alignment
    ... types of allocation function: ... malloc, generic allocator, same as current malloc ... And if you already need alignment sufficient ... pointer value invokes undefined behavior. ...
    (comp.lang.c)
  • double* p=malloc(1) // OK?
    ... Can the result of malloc always be assigned to a pointer whose ... The result of an allocation function is defined to be aligned suitably ... a pointer refers to an entity of the referenced type, ...
    (comp.std.c)
  • Re: (MS-)DOS PC on a microcontroller??
    ... memory block of zero bytes. ... all of malloc, realloc, and calloc and thus is isolated in the ... The pointer returned if the ... Each such allocation shall yield a pointer to ...
    (comp.arch.embedded)
  • Re: (part 10) More Schildt-like errors in Dicky Heathens book
    ... The pointer returned if the ... Each such allocation shall yield a pointer to ... The problem can be handled by appropriate care in the malloc ... and similarly for realloc and calloc. ...
    (comp.lang.c)
  • Re: malloc with size 0
    ... But the behavior of malloc on unix is if size is 0, ... > returned valid pointer for size 0 or only in recent releases. ... allocation until the deallocation. ...
    (microsoft.public.vc.language)