Jump to content

help with scanf(); ?

- - - - -

This topic has been archived. This means that you cannot reply to this topic.
5 replies to this topic

#1
lionaneesh

lionaneesh

    Learning Programmer

  • Members
  • PipPipPip
  • 49 posts
scanf("%[^\n]",line);

:cursing:

tell me the logic of this scanf statement and why " [^\n] " is used instead of %s ...
and how this statement works...

i know that this statement inputs lines till enter is pressed..

but what is the format of the scanf statements please tell...

#2
dargueta

dargueta

    Writes binary right handed and hex left handed

  • Moderators
  • 4,717 posts
The %s specifier reads in characters until the first whitespace character (space, tab, etc.) is hit. This code, on the other hand, reads in any and every character until it hits a newline, so it reads in an entire line. EDIT: Epic fail, dcs corrected me again. :)

Edited by dargueta, 24 March 2010 - 06:13 PM.

sudo rm -rf /

#3
dcs

dcs

    Programming God

  • Members
  • PipPipPipPipPipPipPip
  • 775 posts

dargueta said:

The %s specifier reads in characters until the first whitespace character (space, tab, etc.) is hit. This code, on the other hand, reads in any and every character until it hits a newline, so it reads in an entire line. This should actually be "%[^\n]c" instead of just "%[^\n]" .
A scanset is a directive all by itself -- not a helper for another directive. Meaning, "This should actually be "%[^\n]c" instead of just "%[^\n]" ," is false.

#4
dargueta

dargueta

    Writes binary right handed and hex left handed

  • Moderators
  • 4,717 posts
Hmm...weird. That's the way I was always taught.

EDIT: Stupid question removed.

Edited by dargueta, 24 March 2010 - 06:14 PM.
Stupid question

sudo rm -rf /

#5
Ancient Dragon

Ancient Dragon

    Programming Expert

  • Members
  • PipPipPipPipPipPip
  • 400 posts
Same thread posted and answered on DaniWeb.

#6
ZekeDragon

ZekeDragon

    Writes binary right handed and hex left handed

  • Moderators
  • 2,103 posts
I guess most people know but I suppose it bears repeating that scanf() should be avoided in almost all cases. The scanf() function is "notoriously ill behaved", and there are far better ways to deal with user input. Especially the way you are using it currently, you might as well be using gets(). Now, while using these methods in educational programs, or throw-away code that you intend to use as an experiment is generally okay, you should take in interactive user input by different means, and preferably just altogether avoid taking in user input VIA interactive input. You will notice that many of the released and frequently used by users command line programs take in input using command line arguments and/or files, which happens to be far safer (and the way I recommend you deal with input whenever possible).

Consider the following three echoing programs, the first takes in interactive input through scanf(), the second takes in input using a function that is much safer for user input, and the third uses command line input:
#include <stdio.h>

int main(void)
{
    char buffer[40];
    scanf("%[^\n]", buffer);
    printf("%s", buffer);
    return 0;
}
Simple, yes, but entirely unsafe. In the case of getting more than 40 characters your program will overrun the buffer, and will lead to undefined behavior (the worst kind of behavior).

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Requires C99 and to include stdio.h, stdlib.h, and string.h
size_t get_input(char **retval)
{
    // RETVAL IS ASSUMED NULL!!!
    size_t curlen = 0;
    char buffer[40];
    while (fgets(buffer, sizeof buffer, stdin))
    {
        size_t slen = strlen(buffer) + 1;
        if (!buffer) break;
        curlen += slen;
        char *temp = realloc(retval, curlen);
        if (temp)
        {
            *retval = temp;
        }
        else
        {
            free(*retval);
            *retval = NULL
            return 0; // Indicate failure.
        }
        strncat(*retval, buffer, slen);
        if (buffer[slen - 2] == '\n') break;
    }
    return curlen;
}

int main(void)
{
    char *str = NULL;
    if (get_input(&str)) // You should check the return value of get_input
                         // in case it is zero.
    {
        printf("%s", str);
    }
    free(str);
}
A lot better. It doesn't make many assumptions (except that it is, in fact, interactive input, and not piped in input), but like I just said, there's the issue of piped in file input, which may or may not cut off the piped in file at an arbitrary point. Notice that it only checks if the last character at the end of the buffer happens to be an end-line character, which if that happens to occur while reading in piped input then it'll just leave the rest in the input buffer and carry on. This isn't to say that it's no better than scanf(), just that it's got it's own problems as well. If you want interactive input, use something like that.

#include <stdio.h>

int main(int argc, char **argv)
{
    if (argc > 1)
    {
        printf("%s\n", argv[1]);
    }
    return 0;
}
This is also very simple, and most importantly, entirely safe. Using input in this manner, in my opinion, is how new C programmers should be taught to take in input, since it's extremely simple to figure out, simple to utilize once you understand it, and most importantly, won't cause problems for them in the future if they use it.

Yeah, just had to say that.
Wow I changed my sig!