fgets() input overflow to stderr - c

I have two inputs using fgets() function. Obviously, I declare size of input hoping it will truncate the input. It does truncate the input, but the remaining characters overflow into the following fgets(). I thought flushing the stdin would be the fix, but it doesn't seem to be working. Any help? Example below.
char a[3];
char b[3];
fgets(a, sizeof(a), stdin);
fflush(stdin);
fgets(b, sizeof(b), stdin);
fprintf(stderr, "%s%s", a, b);
an input of "help" followed by "ok" would produce the following:
hel
pok

strchr could be used to look for a newline. If found, set the newline to zero to terminate the string. Call fgets to fill the remainder of the array. The loops continue until both arrays are filled.
The array with size [4] can store three characters and a terminating zero.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ( void) {
char a[4];
char b[4];
char *newline = NULL;
size_t len = 0;
fgets(a, sizeof(a), stdin);
while ( ( newline = strchr ( a, '\n'))) {//find a newline
*newline = 0;//set terminating zero
len = strlen ( a);
if ( len < sizeof a - 1) {//space available in array
fgets ( newline, sizeof a - len, stdin);//more input into array
}
else {
break;
}
}
fgets(b, sizeof(b), stdin);
while ( ( newline = strchr ( b, '\n'))) {//find a newline
*newline = 0;//set terminating zero
len = strlen ( b);
if ( len < sizeof b - 1) {//space available in array
fgets ( newline, sizeof b - len, stdin);//more input into array
}
else {
break;
}
}
fprintf(stderr, "%s%s\n", a, b);
return 0;
}
getchar could be used to clear the input stream if the first array does not contain a newline.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ( void) {
char a[4];
char b[4];
fgets(a, sizeof(a), stdin);
if ( ! strchr ( a, '\n')) {//no newline
while ( '\n' != getchar ( )) {//clear the input stream
if ( EOF == getchar ( )) {
fprintf ( stderr, "problem EOF\n");
return 1;
}
}
}
fgets(b, sizeof(b), stdin);
fprintf(stderr, "%s%s\n", a, b);
return 0;
}

how to flush stdin
Do NOT use: fflush( stdin )
The function: fflush() is ONLY for output streams and the C programming language specifically states that calling fflush() with an input stream results in undefined behavior. (regardless of what visual studio might allow)
Suggest:
int ch;
while( (ch = getchar() ) != EOF && ch != '\n' ){;}
regarding the function: fgets()
That function always appends a NUL byte to the input and always stops 1 short of the length it is given, so there will be room for the NUL byte
regarding:
char a[3];
char b[3];
fgets(a, sizeof(a), stdin);
fflush(stdin);
fgets(b, sizeof(b), stdin);
fprintf(stderr, "%s%s", a, b)
replace:
fflush(stdin);
with:
int ch;
while( ( ch = getchar() ) != EOF && ch != '\n' ){;}

Related

How to read only first n characters from each line in c language?

Suppose, I have a file with the following contents
abcdefghijkl
mnopqrstuvwx
yz1234567890
and I only want to read the first 5 characters from each line so the it can be like the following:
abcde
mnopq
yz123
I tried the following solution,
char line[5];
for (int i = 0; i < 5; i++){
char c = getchar();
line[i] = c;
printf("%c", line[i]);
}
but it does not work. How can I solve this?
Here is a demonstrative program. For simplicity instead of an external file there is used the standard input stream stdin.
#include <stdio.h>
#include <string.h>
int main(void)
{
char line[6];
while ( fgets( line, sizeof( line ), stdin ) != NULL )
{
char *p = strchr( line, '\n' );
if ( !p ) fscanf( stdin, "%*[^\n]\n" );
else *p = '\0';
puts( line );
}
return 0;
}
If to enter
abcdefghijkl
xyz
mnopqrstuvwx
yz1234567890
then the output will be
abcde
xyz
mnopq
yz123
The code you posted will read 5 bytes from stdin and print them. This code should work.
The problem with your code is probably that you are not discarding the remaining characters on the line before reading the next line with the same loop. Since you did not post the code which is calling the loop, I have no way of knowing.
Simple function https://godbolt.org/z/2UP4JW
#include <stdio.h>
#include <stdint.h>
char *read5chars(char *buff, FILE *fp)
{
int ch;
char *ret;
ret = fgets(buff, 6, fp);
do
{
ch = fgetc(fp);
}while(ch != '\n' && ch != EOF);
return ret;
}
int main()
{
char line[6];
while(read5chars(line, stdin))
printf("%s\n", line);
}

How to split string input?

This is part of my main function, the problem is: if my input for translation is given more than one word the program doesn't work properly, any idea about how can I fix that?
int main() {
struct node *temp;
char str[1000];
char word[MAXP];
char translation[MAXT];
char option[15];
while (1) {
str[0] = '\0';
word[0] = '\0';
translation[0] = '\0';
scanf("%[^\n]%*c", str);
sscanf(str, "%s %s %s", option, word, translation);
}
...
You can use fgets to read each input. Then sscanf to scan for the first two sub-strings. Using the %n specifier, the number of characters scanned can be captured to allow you to use strcpy from that index.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char end = '\0';
char str[1000];
char word[1000];
char translation[1000];
char option[15];
int used = 0;
int scanned = 0;
while(1){
str[0]='\0';
word[0]='\0';
translation[0]='\0';
fgets ( str, sizeof ( str), stdin);
str[strcspn ( str, "\n")] = '\0';//remove newline
scanned = sscanf(str, "%14s%999s%c%n", option, word, &end, &used);
if ( scanned >= 1) {//one sub string scanned
printf ( "%s\n", option);
}
if ( scanned >= 2) {//two sub strings scanned
printf ( "%s\n", word);
}
if ( scanned == 3) {//two sub strins and a character scanned
strcpy ( translation, &str[used]);
printf ( "%s\n", translation);
}
}
return 0;
}

Read size-limited input line ignoring the tail part

Is there a library function to read a line of input from stdin with the following requirements?
I have a limited static buffer of specific size (size may be a known constant).
No dynamic allocation allowed. So the library functions like getline() cannot be used.
For lines whose length is beyond the buffer size, the unread tail part of the line is to be ignored.
My solution to read a line is using fgets and a loop to read and ignore the tail part. The code is as below
char buffer[80], tail_buffer[80];
char * line, * tail;
line = tail = fgets(buffer, 80, stdin);
/* Read the tail part to ignore it */
while (tail != NULL && tail[strlen(tail)-1] != '\n')
{
tail = fgets(tail_buffer, 80, stdin);
}
/* Use 'line' as needed */
An alternative solution using scanf to read until the newline is found, and the getchar to read the newline.
char buffer[80];
if ( fgets( buffer, sizeof buffer, stdin ) != NULL )
{
if ( strchr( buffer, '\n' ) == NULL ) // if the buffer does not contain the newline
{
scanf( "%*[^\n]" ); // read up to the newline
getchar(); // read the newline
}
}
After looking into the documentation of scanf, I found a solution myself.
char buffer[80];
scanf(" %79[^\n]%*[^\n]", buffer);
EDIT: With the comments from #chux that this has some limitations in parsing the blank lines and initial spaces, and with the solution from #user3386109, I enhance this as below to scan all the lines till EOF.
char buffer[80] = "";
while (scanf("%79[^\n]%*[^\n]", buffer) != EOF)
{
/* Process the line in buffer */
if (feof(stdin)) break;
getchar(); /* Remove end of line */
buffer[0] = 0;
}
fgets() has corner cases that preclude using it at a complete solution to OP's goal.
Simply loop using fgetc().
// Return count of `char` read - not including potential \n.
int read_line(char *dest, int size) {
int i = 0;
if (size > 0) {
size--;
int ch;
while ((ch = fgetc(stdin)) != '\n' && ch != EOF) {
if (i < size) {
dest[i++] = ch;
}
}
dest[i] = '\0';
if (ch == EOF && i == 0) return EOF;
}
return i;
}
A forced use of fgets() looks like
bool was_there_extra(char *buf, size_t size) {
char *lf = strchr(buf, '\n');
if (lf) {
*lf = '\0'; // optional: lop off potential trailing \n
return false;
}
int ch;
bool extra = false;
while ((ch = fgetc(stdin)) != '\n' && ch != EOF) {
extra = true;
}
return extra;
}
while (fgets(buf, sizeof buf, stdin)) {
if (was_there_extra(buf, sizeof buf)) ...
else ...
}
This approach does get fooled if code reads a '\0'.

is there an any way to discard '\n'?

I am trying to to record response by the user(using getchar()). I am having issues with '\n' sticking in buffer. If I use fgets(char* buf, .. , ..), '\n' again goes into buf and you have to include '\n' at the end of the test string. when using string.h functions (like strcmp()). Is there any clean way of writing code for such purposes.
#include<stdio.h>
#include<string.h>
int main()
{
char buf[100];
fgets(buf, 3, stdin);
puts(buf);
int i = strcmp("p\n", buf);
printf("%d", i);
//if (!strcmp("CLock to random\n", buf))
//{
//puts("sucess");
//}
char c;
c = getchar();
putchar(c);
return 0;
}
Now I want to record response(single character 'p'). If I use getchar(), in place of fgets(), program skips second getchar()( c = '\n'). If I use the current code, i have to include \n in strcmp() every time.
If you want to discard the \n:
char buf[0x1000];
fgets(buf, sizeof(buf), stdin);
char *p = strchr(buf, '\n');
if (p) *p = 0;
#include <stdio.h>
#include <string.h>
char* chomp(char* str){
size_t len = strlen(str);
if(len>0 && str[len-1] == '\n')
str[len-1] = '\0';
return str;
}
int main(void){
char buf[128];
fgets(buf, sizeof(buf), stdin);
printf("<%s>\n", buf); //include newline
printf("<%s>\n", chomp(buf));//drop tail newline
printf("<%s>\n", chomp(buf));//NC
return 0;
}

Reading c file line by line using fgetc()

This is how I've done it but I'm not sure this is the preferred idiom:
FILE *fp = fopen(argv[0], "r");
// handle fopen() returning NULL
while (!feof(fp)) {
char buffer[80]; // statically allocated, may replace this later with some more sophisticated approach
int num_chars = 0;
for (int ch = fgetc(fp); ch != EOF && ch != '\n'; ch = fgetc()) {
buffer[num_chars++] = ch;
}
// null-terminate the string
buffer[num_chars] = '\0';
printf("%s\n", buffer);
}
Is this okay, any suggestions to improve this?
If you are not going to use fgets() (perhaps because you want to remove the newline, or you want to deal with "\r", "\n" or "\r\n" line endings, or you want to know how many characters were read), you can use this as a skeleton function:
int get_line(FILE *fp, char *buffer, size_t buflen)
{
char *end = buffer + buflen - 1; /* Allow space for null terminator */
char *dst = buffer;
int c;
while ((c = getc(fp)) != EOF && c != '\n' && dst < end)
*dst++ = c;
*dst = '\0';
return((c == EOF && dst == buffer) ? EOF : dst - buffer);
}
It recognizes only newline as the end of line; it drops the newline. It does not overflow the buffer; it does not discard excess characters, so if called upon to read a very long line, it will read the line in chunks; it returns the number of characters read. If you need to distinguish between overflow and a line that happens to be the length of the buffer - 1, then you probably need to preserve the newline - with consequential changes in the code:
int get_line(FILE *fp, char *buffer, size_t buflen)
{
char *end = buffer + buflen - 1; /* Allow space for null terminator */
char *dst = buffer;
int c;
while ((c = getc(fp)) != EOF && dst < end)
{
if ((*dst++ = c) == '\n')
break;
}
*dst = '\0';
return((c == EOF && dst == buffer) ? EOF : dst - buffer);
}
There are endless minor variants on this, such as discarding any excess characters if the line has to be truncated. If you want to handle DOS, (old) Mac or Unix line endings, then borrow a leaf out of the CSV code from "The Practice of Programming" by Kernighan & Pike (an excellent book) and use:
static int endofline(FILE *ifp, int c)
{
int eol = (c == '\r' || c == '\n');
if (c == '\r')
{
c = getc(ifp);
if (c != '\n' && c != EOF)
ungetc(c, ifp);
}
return(eol);
}
Then you can use that in place of the c != '\n' test:
int get_line(FILE *fp, char *buffer, size_t buflen)
{
char *end = buffer + buflen - 1; /* Allow space for null terminator */
char *dst = buffer;
int c;
while ((c = getc(fp)) != EOF && !endofline(fp, c) && dst < end)
*dst++ = c;
*dst = '\0';
return((c == EOF && dst == buffer) ? EOF : dst - buffer);
}
The other alternative way of dealing with the whole process is using fread() and fwrite():
void copy_file(FILE *in, FILE *out)
{
char buffer[4096];
size_t nbytes;
while ((nbytes = fread(buffer, sizeof(char), sizeof(buffer), in)) != 0)
{
if (fwrite(buffer, sizeof(char), nbytes, out) != nbytes)
err_error("Failed to write %zu bytes\n", nbytes);
}
}
In context, you'd open the file and check it for validity, then call:
copy_file(fp, stdout);
You're risking buffer overflow if the user inputs 80 characters or more.
I'm with ThiefMaster: you should use fgets(), instead. Read the input into a buffer that's larger than any legitimate input and then check that the last character is a newline.
Unless you're hoping to get a ultra-high efficient way to set the number of characters read, use fgets().
Replacing your example with a similar but different simple fgets(), you "lose" the num_chars variable.
fgets(buffer, sizeof buffer, stdin);
fputs(buffer, stdout); /* buffer contains a '\n' */
If you need to remove the last '\n'
buffer[0] = 0;
if (!fgets(buffer, sizeof buffer, stdin)) /* error or eof */;
num_chars = strlen(buffer);
if (num_chars && (buffer[num_chars - 1] == '\n')) buffer[--num_chars] = 0;
puts(buffer); /* add a '\n' to output */
If the strings are really humongous (like 42 Mega bytes worth), you may be better off reading character by character and keeping count with num_chars than using fgets first and strlen later.
If you need every char in order to inspect it or modify or whatever else then use fgets.
For everything else, use fgets.
fgets (buffer, BUFFER_SIZE, fp);
Note that fgets will read until a new line or EOF is reached (or the buffer is full of course). New line character "\n" is also appended to the string if read from the file. Null character is also appended.
fgets returns :
On success, the function returns the same str parameter.
If the End-of-File is encountered and no characters have been read, the contents of str remain unchanged and a null pointer is returned.
If an error occurs, a null pointer is returned.
Use either ferror or feof to check whether an error happened or the End-of-File was reached.
No linesize-limit und strictly C89 (your code is only C99) like:
FILE *fp = fopen(argv[0], "r");
size_t len=1;
char c, *buffer=calloc(1,1);
/* handle fopen() returning NULL*/
while( c=fgetc(fp),!feof(fp) )
if( c=='\n' )
{
puts(buffer);
len=1;
*buffer=0;
}
else
strncat(buffer=realloc(buffer,++len),&c,1); /* check for NULL needed */
puts(buffer);
free(buffer);
fclose(fp);
#include<stdio.h>
void main()
{
FILE *fp;
char c;
int ch=0,w=0,l=0;
fp=fopen("c:\read.txt","w");
clrscr();
if(fp==NULL)
{
printf("\n\n\tDOES NOT EXIXST");
getch();
exit(0);
}
while(!feof(fp))
{
c=fgetc(fp);
ch++;
if(c==' ')
{
w++;
}
if(c=='\n')
{
l++;
w++;
}
}
printf("\n\n\tTOTAL CHAR = %d\n\n\tTOTAL WORDS = %d\n\n\tTOTAL LINES = %d",ch,w,l);
}

Resources