Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 580 Vote(s) - 3.45 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How to get newline character from scanf even if it's the only input

#1
I'm doing homework that asks me to read an integer `n` representing the size of a loop and then read a line of characters `n` times and print it right after the user's input. So I used `scanf` and then I print it with `printf`. The problem is that if the user's input is only a newline character, it should print another `\n`, but `scanf` seems to ignore the input when it's a single `\n`.

Is there any way to make this assignment with `scanf` or should I try something else?

int i;
scanf("%d", &i);
for(int ct=0; ct<i; ct++)
{
char buff[28];
scanf("%s", buff); // if I just press enter here
prtinf("%s\n", buff); // then I must get \n\n here
}
Reply

#2
One option is to read one line at a time using `gets` and then parse each line using `sscanf`.

EDIT based on comments: Using `fgets` is more appropriate since you can avoid buffer overrun.
Reply

#3
I have two solutions for this:

- Use `fgets` instead of `scanf`.
- Append a `\n` at the end of the string, because you know the use will end the input with `\n`.


##First solution:##

...
char buf[28];
fgets(buf, 28, stdin);
...

##Second solution:##

#include <string.h>

...
char buf[28];
scanf("%s", buf);
strcat(buf, "\n"); // add the newline to the string
...
Reply

#4
Using `fgets` to read in a line is simpler and more robust:

if (!fgets(buff, 28, stdin))
{
// reading failed, do appropriate error handling
// we're just exiting here
exit(EXIT_FAILURE);
}
// We have successfully read in a line, or at least the first 27
// characters of the line. Check whether a full line was read,
// if it was, whether the line was empty
size_t l = strlen(buff); // <string.h> must be included
if (buff[l-1] == '\n')
{
// a full line was read, remove trailing newline unless
// the line was empty
if (l > 1)
{
buff[l-1] = 0;
}
}
else
{
// the input was too long, what now?
// leave the remaining input for the next iteration or
// empty the input buffer?
}
printf("%s\n",buff);

It doesn't work with `scanf("%s",buff)` because most `scanf` conversions ignore leading white space:

> Input white-space characters (as specified by the `isspace` function) are skipped, unless
the specification includes a `[`, `c`, or `n` specifier.

So if the user inputs an empty line, `scanf` ignores that input unless its format is one of the exceptional.

You can use `scanf` with a character set format instead,

scanf("%27[^\n]%*c", buff);

to read all characters until a newline (but limited to `28 - 1` here to avoid buffer overruns), and then consume a newline without storing it (the `*` in the `%*c` conversion specifier suppresses assignment), that would handle non-empty lines consisting entirely of whitespace, which the `%s` conversion would not. But if the first character of the input is a newline, the `%27[^\n]` conversion fails (thanks to [chux][chux] for drawing attention to that), the newline is left in the input buffer, and subsequent scans with that format would also fail if the newline isn't removed from the input buffer.

A somewhat robust (but ugly; and not dealing with too long input) loop using `scanf` would, as far as I can see, need to check for a newline before scanning, e.g.

for(int ct = 0; ct < i; ++ct)
{
int ch = getchar();
if (ch == EOF)
{
// something bad happened; we quit
exit(EXIT_FAILURE);
}
if (ch == '\n')
{
// we had an empty line
printf("\n\n");
}
else
{
// The first character was not a newline, scanning
// with the character set format would have succeeded.
// But we don't know what comes next, so we put the
// character back first.
// Although one character of pushback is guaranteed,
if (ungetc(ch,stdin) == EOF)
{
// pushback failed
exit(EXIT_FAILURE);
}
scanf("%27[^\n]%*c",buff);
printf("%s\n",buff);
}
}

Use `fgets`, really. It's better.

[chux]:https://stackoverflow.com/users/2410359/chux
Reply

#5
Yes, scanf() **can** do it if you use the right format-specifiers:<br>
--To accept a string of no more than 27 chars and <br>
--To accept all chars for that string (including space) except newline '\n', and <br>
--To see if scanf() made any conversions, write: <br>

scanRet = scanf("%27[^\n]s", buf); // fills buf[28] with a string.
if(scanRet < 1) printf("Sorry, scanf didn't change buf[] array.\n");

CAUTION! Repeated scanf() calls or conversions often get spoiled by unexpected inputs from users and/or leftover 'junk' in stdin. You can clear stdin between each scanf() call like this:

char junk;
do {
junk = getc(stdin);
printf("junk: %c (int %d)\n", junk, (int)junk); // show me the junk we cleared
}
while(junk != '\n' || junk != EOF);

Here's my best 'clean' solution using only scanf():

char buf[28] = ""; // sets buf[0] = '\0';
char junk;
int i, iMax, scanRet;

printf("how many lines? (integer>0):\n");
scanRet = scanf(" %d", &iMax);
if(scanRet < 1) {
printf("Sorry, I couldn't read your integer. Bye.\n");
return 1; // error exit.
}
printf("please enter %d lines of text (<=27 chars/line):\n",iMax);
for(i=0; i<iMax; i++) {
// but first, clear any leftover junk in stdin;
do {
junk = getc(stdin);
printf("junk: %c (int %d)\n", junk, (int)junk); // VERBOSE.
}
while (junk != '\n' && junk != EOF);
// THEN try to read user's latest text string:
scanRet = scanf("%27[^\n]",buf); // [^\n]== accept ALL chars except newline
if(scanRet < 1) { // format conversion failed. Nothing new in buf.
printf("(empty line)\n");
}
else {
printf("%s\n", buf); // non-empty user string
}
}
return 0; // normal exit.
}
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through