I am working on a C program that will read user input as Strings separated by spaces. I wanted a way to read these strings up until the blank spaces. I know that scanf does this with ease, but I was wondering if it was possible to do the same with gets() or sscanf() or some combination of the 2. I am very new to C, only having just started it and I come from a Java background. Thank you all in advance, I really appreciate any and all help!!!! Find below the code I have so far as well as well as a sample input (***The wanted functionality is achieved if the scanf() portion is uncommented, but the goal is achieve the same functionality as scanf() only using gets() and sscanf()).
int main()
{
printf("Enter words seperated by spaces:(. or EOF to stop):\n");
do
{
char s[255];
//scanf("%s",s);
gets(s);
if(strcmp(s,".")==0 || strcmp(s,"EOF")==0)
{
insert_dictionary_order(s);//adding to list
break;
}
else
{
insert_dictionary_order(s);//adding to list
}
}
while(1);
//now printing list
print_list();
return 0;
}
This is a sample text.
The file will be terminated by a single dot: .
The program continues processing the lines because the dot (.)
did not appear at the beginning.
. even though this line starts with a dot, it is not a single dot.
The program stops processing lines right here.
.
You won't be able to feed any more lines to the program.
Edit: The answer MUST implement either get() or sscanf() or both.
First, Never, Ever, Ever use gets(). It is so insecure and prone to exploit by buffer overflow it has been completely removed from the c-library beginning with C11. See Why gets() is so dangerous it should never be used! (using scanf() with the "%s" or "%[..]" conversion specifiers without the optional field-width modifier are just a bad)
fgets() is what you are looking for. To read your text file, stopping when '.' appears alone as the first character in a line with nothing following (aside from the '\n' included in the buffer by fgets()), you simply read each line into a sufficiently sized buffer (character array) and check the first character in the line to see if it is a '.' and check the second character to see if it is '\n', and if so, exit your read-loop.
For example:
#include <stdio.h>
#include <string.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
int main (void) {
char line[MAXC]; /* buffer to hold line */
while (fgets (line, MAXC, stdin)) { /* read each line */
/* if 1st char '.' and either EOF or next is '\n', done */
if (*line == '.' && (!line[1] || line[1] == '\n'))
break;
line[strcspn (line, "\n")] = 0; /* trim \n from end of line */
puts (line); /* output line */
}
}
(note: above strcspn (line, "\n") returns the number of characters in line up to the '\n' allowing you to overwrite the '\n' with the nul-termianting character to remove it)
Generally checking that the second character in the line beginning '.' is a newline would be sufficient, but there are a number of editors that do not write POSIX compliant files (meaning no '\n' after the final line). If you didn't check against EOF, then for files with non-POSIX file endings, you would output the last '.' if it appeared on the final line.
Example Use/Output
With your example input in dat/stop_on_dot.txt redirected to the program on stdin as input, you would receive the following:
$ ./bin/stop_on_dot < dat/stop_on_dot.txt
This is a sample text.
The file will be terminated by a single dot: .
The program continues processing the lines because the dot (.)
did not appear at the beginning.
. even though this line starts with a dot, it is not a single dot.
The program stops processing lines right here.
Look things over and let me know if you have any questions.
Never use gets, there is no check for boundary there.
As for your concern using just getchar() is enough by checking the input is space character( , \t,\n)
I have just written a small program to take input till the space.
we can write it more robustly, let me know if this solves your problem.
#include <stdio.h>
int main()
{
char ch;
while(ch = getchar())
{
if(ch != ' ' && ch != '\t' && ch != '\n')
putchar(ch);
else
break;
}
return 0;
}
Related
I'm trying to read a file line by line and count the characters of each line. Those line might contains space characters and I need also to count them. I'm only allowed to use feof and scanf functions.
Sample Code
...
while(!feof(stdin)){
char inputLineArray[1000];
scanf("%[^\n]s", inputLineArray);
printf(inputLineArray);
}
...
My sample file is a txt file which contains the following content:
hello world
abcdsdsdsdsd
But after it prints:
hello world
My program is stuck into infinite loop which does nothing.
From man 3 scanf:
The scanf() family of functions scans input according to format as described below.
This means that your provided pattern %[^\n]s (don't match newlines) will stop matching after world because there is a newline. You'd need to skip to the next char in the stream.
There are many questions like yours on Stackoverflow, search for scanf infinite loop.
scanf("%[^\n]s", inputLineArray); is incorrect and inappropriate:
the conversion specifier does not have a trailing s, it is just %[^\n] ;
scanf reads the stream and stores any characters before the newline into inputLineArray and leaves the newline pending in the stream ;
scanf should be given the maximum number of characters to store to avoid undefined behavior on long lines: scanf("%999[^\n]", inputLineArray) ;
you should test the return value of scanf() to determine if the conversion was successful. The test while (!feof(stdin)) is pathologically inappropriate: Why is “while ( !feof (file) )” always wrong? ;
you would then see another problem: this conversion fails on empty lines because there are no characters to store into the destination array, and since scanf() leaves the newline pending, the second call fails and all successive ones too.
Note also that it is highly risky to call printf with user supplied data as a format string. The behavior is undefined if the line contains non trivial format specifications.
Here is a better way to read the file line by line:
#include <stdio.h>
#include <string.h>
...
char inputLineArray[1001];
while (fgets(inputLineArray, sizeof inputLineArray, stdin)) {
buf[strcspn(buf, "\n")] = '\0'; // strip the trailing newline if present
printf("%s\n", inputLineArray);
}
...
Note however that input lines with 1000 bytes or more will be broken into multiple output lines.
scanf() is not the right tool for your purpose, indeed it is full of quirks and shortcomings, but if you are required to use scanf(), here is a corrected version:
char inputLineArray[1000];
while (scanf("%c", &inputLineArray[0]) == 1) {
/* one byte was read, check if it is a newline */
if (inputLineArray[0] == '\n') {
/* empty line must be special cased */
inputLineArray[0] = '\0';
} else {
/* set the null terminator in case the next `scanf` fails */
inputLineArray[1] = '\0';
/* attempt to read the rest of the line */
scanf("%998[^\n]", inputLineArray + 1);
/* consume the pending newline, if any */
scanf("%*1[\n]");
}
printf("%s\n", inputLineArray);
}
if (feof(stdin)) {
/* scanf() failed at end of file, OK */
} else {
printf("read error\n");
}
Note that feof() is not used as scanf("%c", ...) will return EOF at end of file, so the while() loop with stop as expected.
feof() is only used to distinguish end of file from read error conditions in stream I/O. Most C programs do not need to distinguish between these as read errors can be handled the same way as truncated input files. This function is almost always used incorrectly. In short, you should never use feof(), nor other error-prone or deprecated functions such as gets() and strncpy(). Be also very careful with sprintf(), strcpy(), strcat()...
I have this program:
#include <stdio.h>
#define SIZE 19
int main(){
char string[SIZE];
while (string[0] != 'A'){
printf("\nEnter a new string.\n");
fgets(string,SIZE,stdin);
int storage = 0;
while (storage != '\n')
{
storage = getchar();
}
}
}
The nested while loop with getchar() exists in case the inputted string exceeds the maximum number of characters string[] can hold. If that is not there, inputting a string with, say, 20 characters, would cause the output to be:
Enter a new string.
12345123451234512345
Enter a new string.
Enter a new string.
The problem is that this requires me to press enter twice in order to enter a new string: once for 'fgets' and one for the nested while loop (this is my understanding of what's going on).
Is there a way to change this so I only have to press 'Enter' once, or possibly a way to change the entire while loop into something more elegant?
If the buffer that receives from fgets contains a newline, you know it read everything that was inputted so you don’t need to do anything else. If not, then you use the extra loop to flush the buffer.
You are thinking correctly, you just need to think through how and when you need to empty the input buffer a bit further.
All line-oriented input functions (fgets and POSIX getline) will read, and include, the trailing '\n' in the buffers they fill (fgets only when sufficient space is provided in the buffer).
When using fgets, you have only two possible returns, (1) a pointer to the buffer filled, or (2) "NULL on error or when end of file occurs while no characters have been read."
In case fgets returns a valid pointer, then it is up to you to determine whether a complete line of input was read, or whether the input exceeds the buffer size, leaving characters in the input buffer unread.
To make that determination, you check whether the last character in the buffer is '\n' and if not, whether the buffer contains SIZE-1 characters indicating that characters remain in the input buffer. You can do that a number of ways, you can use strchr (to get a pointer to the '\n'), strcspn (to get an index to it) or good old strlen (to get the length of the string) and then check the character at len-1.
(a note on preference, you can use whatever method you like, but in either case of strcspn or strlen, save the index or length so it can be used to validate whether the input exceeded the buffer size or whether the user ended input by generating a manual EOF. You save the index or length to prevent having to make duplicate function calls to either)
It is also helpful to create a simple helper-function to clear the input buffer to avoid placing loops everywhere you need the check. A simple function will do the trick, e.g.
/* simple function to empty stdin */
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
of if you prefer the more-compact, but arguably less readable version, a single for loop will do, e.g.
void empty_stdin (void)
{
for (int c = getchar(); c != '\n' && c != EOF; c = getchar()) {}
}
The remainder of your example can be structured to complete each of the tests described above to provide input handling as you have described (although using the 1st character of the buffer being 'A' to control the loop is a bit strange), e.g.
#include <stdio.h>
#include <string.h>
#define STRSIZE 19
/* simple function to empty stdin */
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
int main (void) {
char string[STRSIZE] = ""; /* initialize string all 0 */
while (*string != 'A') { /* up to you, but 'A' is a bit odd */
size_t len = 0; /* variable for strlen return */
printf ("enter a string: "); /* prompt */
if (!fgets (string, STRSIZE, stdin)) { /* validate read */
putchar ('\n'); /* tidy up with POSIX EOF on NULL */
break;
}
len = strlen (string); /* get length of string */
if (len && string[len-1] == '\n') /* test if last char is '\n' */
string[--len] = 0; /* overwrite with nul-character */
else if (len == STRSIZE - 1) /* test input too long */
empty_stdin(); /* empty input buffer */
}
return 0;
}
An arguably more useful approach is to have the loop exit if nothing is input (e.g. when Enter alone is pressed on an empty line). The test would then be while (*string != '\n'). A better approach rather is simply controlling your input loop with while (fgets (string, STRSIZE, stdin)). There, you have validated the read before entering the loop. You can also wrap the whole thing in a for (;;) loop and control the loop exit based on any input condition you choose.
Those are all possibilities to consider. Look things over and let me know if you have further questions.
fgets() does read the newline IF (and only if) the buffer is long enough to reach and contain it, along with a trailing nul terminator.
Your sample input is 20 characters, which will be followed by a newline, and then a nul terminator. That won't go into a buffer of 19 characters.
The simple way is to use fgets() in a loop, until the newline is included in the buffer.
printf("\nEnter a new string.\n");
do
{
fgets(string,SIZE,stdin);
/*
handle the input, noting it may or may not include a trailing '\n'
before the terminating nul
*/
} while (strlen(string) > 0 && string[strlen(string) - 1] != '\n');
This loop will clear input up to and including the first newline, and also allow you to explicit handle (discard if needed) ALL the input received. It is therefore not necessary to use a second loop with getchar().
You haven't checked if fgets() returns NULL, so neither have I. It is advisable to check, as that can indicate errors on input.
My code goes something like this:
char k[1000];
while(1){
scanf("%s",&k);
if(k[0] == '\n'){
exit(0);}
/* Do some processing on k */
memset(k,0,1000);
}
My intention is to process user input per normal and terminate when user inputs empty string or new line. This doesn't seem to work.
Could you guys help on what went wrong?
On related note, I also want to terminate if it is the end of file, how should I do it for EoF?
Thank you in advance for all the help.
First off -- don't use scanf for user input. It is a minefield of subtle issues just waiting to bite new C programmers, instead use a line-oriented input function like fgets or POSIX getline. Both read up to (and including) the trailing '\n' every time (as long as you provide a buffer of sufficient size for fgets -- otherwise it just keep reading blocks of characters of its buffer size until it encounters a '\n' or EOF)
So to read user input until an empty-string or EOF is encountered, you could simply do something like the following:
#include <stdio.h>
#include <string.h>
#define MAXC 1000
int main (void) {
char k[MAXC] = "";
for (;;) { /* loop until empty-string of EOF */
printf ("input: "); /* prompt for input */
if (fgets (k, MAXC, stdin)) { /* read line (MAXC chars max) */
if (*k == '\n') { /* test for empty-string */
fprintf (stderr, "empty-string! bye.\n");
break;
}
size_t l = strlen (k); /* get length of string */
if (l && k[l - 1] == '\n') /* check if last char is '\n' */
k[--l] = 0; /* overwrite with nul-terminator */
printf ("got input: %s\n", k);
}
else { /* got EOF */
fprintf (stderr, "EOF -- bye.\n");
break;
}
}
return 0;
}
Example Use/Output
>bin\fgets_user_input.exe
input: this
got input: this
input: is some
got input: is some
input: input
got input: input
input:
empty-string! bye.
>bin\fgets_user_input.exe
input: this is more
got input: this is more
input: ^Z
EOF -- bye.
>bin\fgets_user_input_cl.exe
input: it works the same
got input: it works the same
input: compiled by gcc
got input: compiled by gcc
input: or by cl.exe (VS)
got input: or by cl.exe (VS)
input:
empty-string! bye.
(note: for Linux Ctrl+d generates the EOF, I just happened to be on windoze above)
Like ever so often, the problem here is inappropriate usage of scanf(). scanf() is not for reading input but for parsing it and the format-string tells it how to parse.
In your case, %s is looking for a sequence of non-whitespace characters (IOW, a word) and it skips any leading whitespace. \n (newline) is just a whitespace character, so it is always skipped -- your scanf() will just wait for more input until it can parse %s.
For more information on scanf() pitfalls, I recommend you my beginners' guide away from scanf(). As a rule of thumb, with interactive input (which is the default), scanf() is almost always wrong.
There's another huge problem with scanf("%s", ...): It will happily overflow any buffer you provide it, as long as the input contains non-whitespace characters, just like gets() which was even removed from C for exactly that reason: Buffer overflows are extremely dangerous! Therefore always use a field-width, in your case scanf("%999s", ...). This parses a maximum of 999 characters, leaving one for the necessary 0 byte terminating a string.
But now for how to do it correctly: There are several functions in C that are indeed for reading input and one of them is for reading a line of input: fgets(). In your code, it would look like this:
char k[1000];
while(fgets(k, 1000, stdin)){
if(k[0] == '\n'){
exit(0);
}
/* Do some processing on k */
memset(k,0,1000);
}
I used your original code here, still some further remarks:
It would be better to define a macro instead of using the magic number 1000, e.g. #define INPUTSIZE 1000 and use this instead, like char k[INPUTSIZE];, fgets(k, INPUTSIZE, stdin) etc.
Clearing the whole array is not needed, so to avoid unnecessary work, replace the memset() with just k[0] = '\0'; or similar. A C string ends at the first 0 byte, so this is enough to make k hold an empty string. If your program does nothing more than shown here, you could even get rid of this completely, as the next fgets() call overwrites the array anyways (or returns NULL on error, which would stop the loop).
Also note that fgets() reads the whole line including the newline character at the end, so keep this in mind when processing the contents of k.
This one is guaranteed to give everything except newlines (and EOFs) for you:
char k[1000];
scanf("%[^\n]", k);
And when it returns, the next character is guaranteed to be either a newline, or non-existent at all (EOF reached). Get it like this:
int next_char = getcgar();
if (next_char == EOF){
your_eof_process();
}
else if (nexr_char == '\n'){
your_newline_process();
}
Personally, I would do it using only getchar():
char k[1000];
int ind, tempc;
for (ind = 0; ind < sizeof k; ind ++){
tempc = getchar();
if (tempc == '\n'){
// Some stuff
}
else if (tempc == EOF){
// Other stuff
}
else {
k[ind] = tempc;
}
}
k[sizeof(k)-1] = '\0';
I have this assignment where I have to read till the "?" char and then check if it is followed by number and newline, or newline and then the number and than again newline.
I checked the first char after the "?"
if (scanf("%c",c)=='\n') ...;
but that only works if the first one is a newline, and when it isn't and i want to read the number instead, it cuts the first digit ... for example, it doesn´t read 133 but only 33
... how do i do this?
I also tried puting the char back, but that wouldn't work
please help :)
One advantage of getline over either fgets (or a distant scanf) is that getline returns the actual number of characters successfully read. This allows a simple check for a newline at the end by using the return to getline. For example:
while (printf ((nchr = getline (&line, &n, stdin)) != -1)
{
if (line[nchr - 1] = '\n') /* check whether the last character is newline */
line[--nchr] = 0; /* replace the newline with null-termination */
/* while decrementing nchr to new length */
Use fgets(3), or better yet, getline(3) (like here) to read the entire line, then parse the line using strtol(3) or sscanf(3) (like here)
Don't forget to carefully read the documentation of every function you are using. Handle the error cases - perhaps using perror then exit to show a meaningful message. Notice that scanf and sscanf return the number of scanned items, and know about %n, and that strtol can set some end pointer.
Remember that on some OSes (e.g. Linux), the terminal is a tty and is often line-buffered by the kernel; so nothing is sent to your program until you press the return key (you could do raw input on a terminal, but that is OS specific; consider also readline on Linux).
this line: if (scanf("%c",c)=='\n') ...; will NEVER work.
scanf returns a value that indicates the number of successful parameter conversions.
suggest:
// note: 'c' must be defined as int, not char
// for several reasons including:
// 1) getchar returns an int
// 2) on some OSs (dos/windows) '\n' is 2 characters long
// 3) if checking for EOF, EOF is defined as an int
if( '\n' == (c = getchar() ) )
{ // then found newline
...
#include <stdio.h>
int main (void){
int num;
scanf("%*[^?]?");//read till the "?"
while(1==scanf("%d", &num)){
printf("%d\n", num);
}
return 0;
}
DEMO
Relevant code snippet:
char input [1024];
printf("Enter text. Press enter on blank line to exit.\n");
scanf("%[^\n]", input);
That will read the whole line up until the user hits [enter], preventing the user from entering a second line (if they wish).
To exit, they hit [enter] and then [enter] again. So I tried all sorts of while loops, for loops, and if statements around the scanf() involving the new line escape sequence but nothing seems to work.
Any ideas?
Try this:
while (1 == scanf("%[^\n]%*c", input)) { /* process input */ }
As was yet pointed out, fgets() is better here than scanf().
You can read an entire line with fgets(input, 1024, stdin);
where stdin is the file associated to the standard input (keyboard).
The function fgets() reads every character from the keyboard up to the first new-line character: '\n' (obtained after pressing ENTER key, of course...).
Important: The character '\n' will be part of the array input.
Now, your next step is to verify if all the characters in the array input,
from the first to the '\n', are blanks.
Besides, note that all the characters after the first '\n' in input are garbage, so you have not to check them.
Your program could be as follows:
char input[1024];
printf("Enter text. Press enter on blank line to exit.\n");
while (1) {
if (fgets(input, 1024, stdin) == NULL)
printf("Input Error...\n");
else {
/* Here we suppose the fgets() has reached a '\n' character... */
for (char* s = input; (*s != '\n') && isspace(*s); s++)
; /* skipping blanks */
if (*s == '\n')
break; /* Blank line */
else
printf("%s\n", input); /* The input was not a blank line */
}
}
That code must be written inside your main() block and,
more importantly, it is necessary to include the header <ctype.h> before all,
because the isspace() function is used.
The code is simple: the while is executed for ever, the user enter a line in each iteration, the if sentences checks if some error has happened.
If everything was fine, then a for(;;) statement is executed, which explores the array input to watch if there are just blanks there... or not.
The for iterations continue up to the first new-line '\n' is found, or well, a non-blank character appears.
When for terminates, it means that the last analyzed character, which is held in *s, is a newline (meaning that all earlier characters were blanks), or not (meaning that at least there is some non-blank character in input[], so input is a normal text).
The "ethernal" while(1) is broken only in case that a blank-line is
read (see the break statement in 11th line).
OP says "To exit, they hit [enter] and then [enter] again"
unsigned ConsecutiveEnterCount = 0;
for (;;) {
char buffer[1024];
if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
break; // handle error or EOF
}
if (buffer[0] == '\n') {
ConsecutiveEnterCount++;
if (ConsecutiveEnterCount >= 2 /* or 1, not clear on OP intent */) {
break;
}
}
else ConsecutiveEnterCount = 0;
// Do stuff with buffer;
}
#include <stdio.h>
int main(){
char arr[40];
int i;
for( i = 0; i < sizeof(arr); i +=2 ){
scanf("%c%c",&arr[i],&arr[i+1]);
if( arr[i] == '\n' && arr[i+1] == '\n' )
break;
}
printf("%s", arr);
return 0;
}
... I tried all sorts of while loops, for loops, and if statements around the scanf() involving the new line escape sequence but nothing seems to work.
It seems you tried everything that you shouldn't have tried, prior to reading! A C programmer is expected to read manuals lest they want to run into undefined behaviour which causes headaches like the one you've experienced. To elaborate, you can't learn C by guessing like you can Java.
Consider this your lesson. Stop guessing and start reading (the fscanf manual)!
According to that manual:
[ Matches a non-empty sequence of bytes from a set of expected bytes (the scanset).
The emphasis is mine. What you seem to be describing is an empty sequence of bytes, which means that the match fails. What does the manual say about matching failures?
Upon successful completion, these functions shall return the number of successfully matched and assigned input items; this number can be zero in the event of an early matching failure. If the input ends before the first conversion (if any) has completed, and without a matching failure having occurred, EOF shall be returned. If an error occurs before the first conversion (if any) has completed, and without a matching failure having occurred, EOF shall be returned...
Again, the emphasis is mine... This is telling you that like most other C-standard functions, you need to check the return value! For example, when you call fopen you then write some idiom along the lines of if (fp == NULL) { /* handle error */ }.
Where's your error handling? Note that the return value isn't merely a binary selection; where n conversions are performed, there are n+2 possible return values in the range of: EOF, 0 .. n. You should understand what each of those means, before you try to use fscanf.