tags:

views:

362

answers:

5

Hi, I was wondering if someone could please help me with this:

printf("Enter path for mount drive (/mnt/Projects) \n");
scanf("%s", &cMountDrivePath);  

Is it possible to allow the user to simply press Enter and accept the default (in this case: /mnt/Projects)? At present, if the user presses Enter, the cursor simply goes to the next line and input is still required.

I get the impression scanf does not allow this, in which case, what should I use?

Thanks!

A: 

scanf is evil because it does no bounds-checking!

Please use getline from the GNU C library.

If your compiler supports C++, simply use istream::getline

Thorsten79
*cough*... getline() is **NOT** part of the language standard.
DevSolar
But it was added to the POSIX-2008 standard, which is why it is in new enough versions of glibc.
dmckee
No, use std::getline in C++. scanf is not evil, and you may tell it the maximum width to use. Were you thinking of gets? (And note fgets fixes this problem.)
Roger Pate
scanf is still almost never used in favor of fgets and sscanf.
Joshua
+4  A: 

I think fgets() gives you a bit more possibilities in input, especially blank lines.

extraneon
see my answer to DevSolar
Riaz
I originally opened this question under Objective C tag and someone changed it to C.Maybe I didn't ask the question well enough but I was hoping there's an alternative in Objective C (and Foundation / Cocoa).My answer is NSFileHandle (using fileHandleWithStandardInput)Thanks for all the answers (re: C !)
Riaz
A: 

No, scanf() can not be made to accept "default values". You have to get the input, check it for emptyness, and assign a default value yourself.

As you found out, scanf() is tricky; I concur with extraneon that fgets() is probably what you are looking for.

Edit:

The reason why scanf() is not reacting... scanf() returns after it a) processed all conversion specifiers or b) encountered an error. As with all conversion specifiers ("%s" in this case), leading whitespace is skipped. Additionally, "%s" reads all characters until the next whitespace.

Pressing return inserts a '\n' into standard input. So, if you press return before you entered anything else (except perhaps a couple of tabs and spaces), scanf() skips your input and proceeds to wait for non-whitespace input.

Whatever you enter, scanf() won't "see" it until you press return, because your input is held in the console buffer. (You wouldn't be able to backspace through your input otherwise.) Pressing return again enters "\n" into the input stream, so your "%s" is terminated even if you did not enter any tabs / spaces on the line you typed.

If you did enter whitespaces, your cMountDrivePath would only contain the first "word" up to the first whitespace, which is why leaving spaces in directory or file names makes things so damn annoying. It would also leave the rest of the line in the input buffer, so the next time you call scanf() it wouldn't immediately ask for input, but proceed to process whatever was buffered during the previous call - another annoying detail for scanf() beginners to watch out for.

I hope this cleared things up a bit for you (and others yet to come).

DevSolar
The next line (where I check the input) isn't firing if I simply press Enter (without any other characters). A new line is inserted but the console is still waiting for an input. Hope that makes sense.By the way, I don't know if things behave directly on the Mac and Objective C but it's a console app in Objective C.I'll check if I get luckier with fgets.Thanks for your reply
Riaz
+1  A: 

Or, if you're determined to use scanf, use a format string that limits the number of characters that will be scanned (to prevent buffer overrun errors).

For example, if your buffer is 128 bytes (including the nul terminator):

scanf("%127s", &cMountDrivePath);
David Gelhar
Doesn't work sorry.
Joshua
+3  A: 

No, scanf() cannot be configured to accept a default value. To make things even more fun, scanf() cannot accept an empty string as valid input; the "%s" conversion specifier tells scanf() to ignore leading whitespace, so it won't return until you type something that isn't whitespace and then hit Enter or Return.

To accept empty input, you'll have to use something like fgets(). Example:

char *defaultPath = "/mnt/Projects";
...
printf("Enter path for mount drive (%s): ", defaultPath);
fflush(stdout);

/**
 * The following assumes that cMountDrivePath is an
 * array of char in the current scope (i.e., declared as
 * char cMountDrivePath[SIZE], not char *cMountDrivePath)
 */
if (fgets(cMountDrivePath, sizeof cMountDrivePath, stdin) != NULL)
{
  /**
   * Find the newline and, if present, zero it out
   */
  char *newline = strchr(cMountDrivePath, '\n');
  if (newline)
    *newline = 0;

  if (strlen(cMountDrivePath) == 0) // input was empty
  {
    strcpy(cMountDrivePath, defaultPath)
  }
}

EDIT

Changed default to defaultPath; forgot that default is a reserved word. Bad code monkey, no banana!

John Bode
A good example, but why the flush?
Roger Pate
For some reason, if I try using fgets in XCode and Objective-C (as a console app), it doesn't 'block' on stdin.The code compiles OK but it ignores the request for an input on stdin.
Riaz
@Riaz: You've given conflicting messages about blocking, see my comment on your new question. (http://stackoverflow.com/questions/2311842/)
Roger Pate
Roger, I see your point now, thanks
Riaz
@Riaz: if there's a stray newline left in the input stream (say from a prior call to `scanf()` or `fgets()`) that can cause future calls to `scanf()` or `fgets()` to return immediately. For interactive input, it's really best to use `fgets()` to read everything as text up to the next newline, then parse and covert that text buffer as necessary.
John Bode
@Roger: just to make sure the prompt gets displayed, especially since there isn't a newline.
John Bode