C scanf statements

Hi,

I know C is somewhat outdated and pretty limited (comparatively), but I have a question about scanf (equivalent to cin) statements. I'm used to programming on PC's using Microsoft Visual C++, and for a long time I've been using a certain command that goes something like:
scanf("%[^\n]", buffer);
which reads a string into 'buffer' until coming to a newline character. This command is recognized when compiled with xTools, but it does something weird where it doesn't wait for the user's input and scans in an empty string. Does anyone know how to make it not do this, or know another command for C that scans everything until a newline (including whitespace)?
And yes, I've already put "fflush(stdin);" before the scanf statements.

~Jason

iMac G5, 2GHz, 17", 1GB RAM Mac OS X (10.4.8) xTools ver. 2.4.1

Posted on Feb 17, 2007 10:33 AM

Reply
7 replies

Feb 17, 2007 11:08 PM in response to etresoft

The concept of a "newline" is much more uncertain that what people think. It can be 0x0a, 0x0d, or 0x0d0a. It isn't just OS-specific.

That last bit is a little confusing to me. Are you saying a given OS will use different characters for newlines at different times?

In any case, I was under the impression that in C++ at least, when any OS's newline is encountered in input, it is converted to a \n; and when any \n is written to output, it is converted to the OS's newline (with binary reading and writing being an exception). Does C not do the same thing? If that were not the case, I would think the op would have had prior problems using:

scanf("%[^\n]", buffer);

because on windows he would be reading in a \r before the read terminating \n since \r\n is the newline in a windows OS.

Also, since this:

scanf("%[^\n]", buffer);

apparently contains a regex, you can make the regex more general and have the read statement stop before reading in any newline character(or any portion of a newline sequence):
<pre>
[^\r\n] ----> don't read in any \r's or \n's</pre>

However, if your read statement is not waiting for user input and just terminating, that would indicate there is a newline in the buffer from previous input.

Feb 18, 2007 12:23 AM in response to nflemming2004

And yes, I've already put "fflush(stdin);" before the
scanf statements.


http://faq.cprogramming.com/cgi-bin/smartfaq.cgi?answer=1052863818&id=1043284351

stdin is a standard FILE* variable that points to the input stream normally used for keyboard input. The fflush() function is deemed to flush buffers. Put the two together and you have a method for clearing the input stream easily, right? WRONG! This is a common misconception in C and C++ programming, an extract from the C standard will help explain:

int fflush(FILE *ostream);
ostream points to an output stream or an update stream in which the
most recent operation was not input, the fflush function causes any
unwritten data for that stream to be delivered to the host environment to
be written to the file; otherwise, the behavior is undefined.

So, if the file stream is for input use, as stdin is, the behaviour is undefined, therefore it is not acceptable to use fflush() for clearing keyboard input.

<pre>
//C:
char data[100] = {0};
fputs("Enter data: ", stdout);
fgets (data, 100, stdin);
fputs (data, stdout);

//C++
string str;
cout<<"Enter data: ";
getline(cin, str);
cout<<str<<endl;
cout<<strlen(str.c_str())<<endl;</pre>

Feb 18, 2007 12:23 AM in response to 7stud

Thanks a lot. I still dont know what redex is, but you helped me solve 2 problems:
1) when I changed [^\n] to [^\r\n], it fixed a problem I was having (also only on my mac) where strcmp(string, string) was returning a strange value instead of the 0 it should have given me.

2) for my problem where it wouldn't wait for user input I changed the statement to: scanf("\n%[^\r\n]", buffer); to see if for some reason there was a newline char right before the scanf. This worked and I don't know how the \n got there, but this gets it out.

Now all I have to do is worry about whether or not ill need a different code for PC and Mac versions...

Feb 18, 2007 1:04 AM in response to nflemming2004

Thanks a lot. I still dont know what redex is,


It's a 'regex', and it is a sequence of symbols that is used to look for something in a string. The fragment:

[^\n]

says to look for any character that is not(^) a \n. You can add other characters inside the brackets, and then the pattern will match any character that is not(^) one of the ones listed inside the brackets, e.g.

[^\r\n]

You need to realize:

1) When a user hits <return> on their keyboard, invisible characters are entered into the input

2) When a user hits <return>, the invisible characters that are entered into the input depend on what OS the user has on their computer:

windows: \r\n
mac: \r (or \n depending on the version)
unix: \n

3) When reading input, C++ streams convert whatever newline is entered by the user into a \n. When writing output, C++ streams convert a \n that is output by the program to the OS's newline character.

4) I'm not sure about the particulars of C input/output, but I would expect it to work the same way. However, it appears that scanf() does not apply newline conversions since its operation does not involve looking for newlines--it looks for particular characters. On the other hand, C has two functions designed to read in whole lines of data:

gets()
fgets()

and they are geared to look for newlines, so I would expect the automatic newline conversions to take place, i.e. those functions will work on any OS.

Just because you have been reading in lines the wrong way in the past doesn't mean you should continue to do so in the future.

Feb 18, 2007 8:12 PM in response to nflemming2004

first, what is a regex (\r)? I won't claim to be
anything near proficient at programming in C, so I
simply just don't know what this is.


Regex is short for Regular Expression. The scanf format string is nowhere near being a real regex. By most accounts, Perl is the language with the best regular expression support. You can use regular expressions in C/C++ programs through 3rd party libraries like PCRE, ICU, or Boost.

Also, there shouldnt be any problem with scanning a
newline character randomly since i have the fflush();
right before the scanf


The built-in scanf and std::cin operators are simply inadequate for reading in data. For anything beyond the simplest program, you will probably have to get to the point of reading in an entire line at once and then parsing it yourself. For that reason, fgets, or the C++ getline (both with buffer overflow protection) are what you should use. Then, you don't have to worry about whether to use \r, \n, or \r\n.

And, for what it's worth, the "cannonical" line ending on the Internet is a CR-LF pair - 0x0d0a. Pretty much every Internet protocol is designed to use this type of line ending - regardless of what the OS considers a new line. Sometimes, by the time you get said Internet data into a file, it may have been converted into a "native" newline. That is why I say you can never really tell.

This thread has been closed by the system or the community team. You may vote for any posts you find helpful, or search the Community for additional answers.

C scanf statements

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple Account.