Trying to stop my program when two lines are empty using fgets() - c

Basically I'm making a short program that reads two lines and, if they are different, it will write both of them. If thery are the same sentences, the program shall write only one sentence. Program should stop when it encounters two empty lines. And that's a problem. I can't figure out how to do it. I've already tried to use strcmp() function but that didn't work either. Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char sent1[6000], sent2[6000];
while(1){
fgets(sent1, sizeof(sent1), stdin);
fgets(sent2, sizeof(sent2), stdin);
if(strcmp(sent1, sent2)!=0)
printf("%s%s", sent1, sent2);
else
printf("%s", sent1);
if((sent1[0] == '/0') && (sent2[0] == '/0'))
break;
}
return 0;
}

fgets reads in a line including the new line character. So if your file contains empty lines, then such a line may have a '\n' at position 0, not a '\0'.
Try:
if( ((sent1[0] == '\0') || (sent1[0] == '\n'))
&& ((sent1[0] == '\0') || (sent1[0] == '\n')) )
Further, note that you should check the return value of fgets, which is NULL if end of file has been reached. In such a case, sent1 or sent2 would not be altered any more, and you might run into an infinite loop.

Your lines are not empty because fgets() would read in the newlines ('\n'). So you'd need to check for the newline charater instead.
if((sent1[0] == '\n') && (sent2[0] == '\n'))
break;
Not so relevant anymore, but your comparison is wrong because the null character is '\0', not '/0'.
As said before, fgets() would read in the newline character if there's space in the buffer. In your case, since you're comparing them, you need to be aware of that. Probably needs to strip out the newline character too. e.g.,
char *p;
if ((p = strchr(sent1, '\n')) != NULL)
*p = '\0';
(same with sent2 as well)
Another case to consider is what if the fgets() calls fail. You need to check their return value for failures. fgets() returns NULL on failure.

Related

c - fgets never return \0 and cause a infinite loop

I tried to make a while loop reading some strings from stdin but it never ends
fgets(string,stringlenght,stdin);
while (string[0] != '\0') {
///some stuff here
fgets(string,stringlenght,stdin);
}
now no matter what I do the loop never end, i tried with ctrl+d and ctrl+z but both never worked.
How can a loop like this come to an end?
fgets never return \0 and cause a infinite loop
fgets() does return 0 (aka NULL) on end-of-file (and nothing read).
OP's code is not testing the return value of fgets(), but a value in a buffer. Instead, test the function return value.
//fgets(string,stringlenght,stdin);
//while (string[0] != '\0') {
while (fgets(string, stringlenght, stdin)) {
Better example
char buf[100];
while (fgets(buf, sizeof buf, stdin)) {
// Lop off \n which may exist near the end of input
buf[strcspn(buf, "\n")] = 0;
...
How can a loop like this come to an end?
For the pedantic: There are ways to make string[0] != '\0' false. One involves reading a null character, (e.g. typing Ctrl Shift # on select keyboards) but that is implementation dependent. Null characters are rare with text input.
Certainly OP is on a wrong approach and testing the fgets() return is the best one.
Spelling: lenght -- > length

Usage of scanf ... getchar

Is the following pattern ok in C to get a string up until a newline?
int n = scanf("%40[^\n]s", title);
getchar();
It seems to work in being a quick way to strip off the trailing newline, but I'm wondering if there are shortcomings I'm not seeing here.
The posted code has multiple problems:
the s in the format string is not what you think it is: the specification is %40[^\n] and the s will try and match an s in the input stream, which may occur after 40 bytes have been stored into title.
scanf() will fail to convert anything of the pending input is a newline, leaving title unchanged and potentially uninitialized
getchar() will not necessarily read the newline: if more than 40 characters are present on the line, it will just read the next character.
If you want to read a line, up to 40 bytes and ignore the rest of the line up to and including the newline, use this:
char title[41];
*title = '\0';
if (scanf("%40[^\n]", title) == EOF) {
// end of file reached before reading anything, handle this case
} else {
scanf("%*[^\n]"); // discard the rest of the line, if any
getchar(); // discard the newline if any (or use scanf("%1*[\n]"))
}
It might be more readable to write:
char title[41];
int c, len = 0;
while ((c = getchar()) != EOF && c != '\n') {
if (len < 40)
title[len++] = c;
}
title[len] = '\0';
if (c == EOF && len == 0) {
// end of file reached before reading a line
} else {
// possibly empty line of length len was read in title
}
You can also use fgets():
char title[41];
if (fgets(title, sizeof title, stdin) {
char *p = strchr(title, '\n');
if (p != NULL) {
// strip the newline
*p = '\0';
} else {
// no newline found: discard reamining characters and the newline if any
int c;
while ((c = getchar()) != EOF && c != '\n')
continue;
}
} else {
// at end of file: nothing was read in the title array
}
Previous note, the s should be removed, it's not part of the specifier and is enough to mess up your read, scanf will try to match an s character against the string you input past the 40 characters, until it finds one the execution will not advance.
To answer your question using a single getchar is not the best approach, you can use this common routine to clear the buffer:
int n = scanf(" %40[^\n]", title);
int c;
while((c = getchar()) != '\n' && c != EOF){}
if(c == EOF){
// in the rare cases this can happen, it may be unrecoverable
// it's best to just abort
return EXIT_FAILURE;
}
//...
Why is this useful? It reads and discards all the characters remaing in the stdin buffer, regardless of what they are.
In a situation when an inputed string has, let's say 45 characters, this approach will clear the stdin buffer whereas a single getchar only clears 1 character.
Note that I added a space before the specifier, this is useful because it discards all white spaces before the first parseable character is found, newlines, spaces, tabs, etc. This is usually the desired behavior, for instance, if you hit Enter, or space Enter it will discard those and keep waiting for the input, but if you want to parse empty lines you should remove it, or alternatively use fgets.
There are a number of problems with your code like n never being used and wrong specifier for scanf.
The better approach is to use fgets. fgets will also read the newline character (if present before the buffer is full) but it's easy to remove.
See Removing trailing newline character from fgets() input

Reading String Until Blank Space

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;
}

How to avoid pressing enter twice when using getchar() to clear input buffer?

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.

Ignoring whitespaces while reading input files in C

I'm trying to write code that registers the first word of every line as a command, but I want to be able to read the word regardless of there being spaces or not in front of it. I'm currently using fgets() and strncmp the first x characters of each line to do this, but it doesn't work for an arbitrary amount of whitespace. I have tried using sscanf() inside the fgets() loop to store the first word of each line to a variable but it seems to be skipping through lines and reading them incorrectly. I would rather not post the code as it is quite lengthy but it is basically this:
while( fgets(Line, BUFFER, input) != NULL )
{
if(strncmp(Line, "Word", 4) != NULL)
//DO SOMETHING
}
There are many strncmps and I would like for each of them to ignore an arbitrary amount of preceding spaces.
You can use isspace to skip over whitespace:
#include <ctype.h>
while( fgets(Line, BUFFER, input) != NULL )
{
char *p = Line;
while (isspace(*p)) // skip whitespace
p++;
if(strncmp(p, "Word", 4) != NULL)
//DO SOMETHING
}

Resources