fgets loop ending with EOF skips next fgets - c

I'm trying to get a user input after an undefined amount of another input done. But the problem is that the second fgets after the while loop never gets invoked. I'm ending the loop with EOF, maybe that's the error. But I don't know how else I should end the loop.
Another funny thing is: It's a task from my C coding class and the lecturer has a video of her solution, and if I'm copying her code 1:1, it also does not work. It also skips the second fgets call.
I've already cut down the code to an absolute bare minimum to get the error, but as you can see: a few lines of code and it does not work. I even tried debugging it with GDB, but I can't figure out how to have it behave like it does in the video.
#include <stdio.h>
int main() {
char input[80];
while (fgets(input, 80, stdin) != NULL) {
// nop
}
fgets(input, 80, stdin);
printf("%s\n", input);
return 0;
}

when you press ctrl+d = EOF in mac (on windows its the same i guess) for the first time you had to exit the while loop.
when you press it again the fgets after the loop works and it prints the last line.
sorry for my english :)

for LINUX and UNIX systems it's ctrl +D and ctrl + z for windows. you can test it out using the following code.
#include <stdio.h>
int main() {
char input[80], input1[50];
while (fgets(input, 80, stdin) != NULL) {
// nop
}
fgets(input1, 50, stdin);
printf("input is %s\n", input);
printf("input1 is %s\n", input1);
return 0;
}
Also, mention your system in the post for further clarification

Update: I got the problem! Found out that on every OS that the code worked, libc was in version 2.27. On all other systems libc was in version 2.29. So I compiled the code with the -static option on a libc-2.27 System and copied it to my main system with libc-2.29 and everything worked as inspected!
So now I just have to figure out, how to downgrade my libc to 2.27 on Manjaro.
Edit: Got a mail from the developers. They say the way it behaves on my system is the correct way and linked to commit 2cc7bad0ae. So apparently my lecturer used a bug for her solution.

Related

Using control+D (EOF) but return an unexpected character D [duplicate]

This question already has answers here:
Simple program adding "D" to output
(3 answers)
Why does C program print 0D instead of 0? (When EOF sent as Ctrl+D) [duplicate]
(1 answer)
Closed 5 years ago.
I was coding a very simple programme to detect word pattern by entering to stdin and return the times found the pattern.
However the code return me the correct number but follow a char D.
#include <stdio.h>
#include "string.h"
#define MAXLINE 1000 /* maximum input line length */
char pattern[] = "ould"; /* pattern to search for */
/* print all lines from standard input that match pattern */
int main()
{
char line[MAXLINE];
int found = 0;
while (fgets(line, MAXLINE, stdin) != NULL)
if (strstr(line, pattern) != NULL) {
printf("%s", line);
found++;
}
printf("%d \n", found);
return 0;
}
Result:
glaroam2-180-76:Lab2 apple$ ./find0
fould
fould
1D
The code is correct (apart from the #include "string.h" which should be
#include <string.h>)1, the problem is that when you press
Ctrl+D on your terminal, your terminal might write
something on the terminal, which you cannot control and this output might be
^D
After fgets returns NULL, you do printf("%d \n", found); which prints the '1'.
But because there was ^D on the terminal, the ^ was replaced by the '1' and
you end up with:
1D
Change your last printf to this:
printf("\n\n%d \n, found);
And you might see only a '1' in the next lines of the output.
This has nothing to do with your C program, it's the behaviour of your terminal.
My terminal for example doesn't print when pressing Ctrl+D,
but when pressing Ctrl+C I get ^C. There's nothing you
can do.
edit
With There's nothing you can do I mean that you cannot control the way the
terminal from you C program without calling external tools like stty. While
this might solve your problem, you are loosing portability.
However, before you start you program, you can configure your terminal using a
program like stty. See Jonathan Leffler's answer for more info on that.
Fotenotes
1As Jonathan Leffler points out in the comments, using quotes instead
of angle brackets for system headers is not an error per se. For example my GCC
compiler searches in the same directory of the compiled file for headers that
were included with quotes. But in general, it's a good practice to include the
header files included provided by your system with angle brackets.
It's a terminal setting: echoctl. It means that when you type Control-D, the terminal echoes ^D, and then the 1 overwrites the ^. Try using:
stty -echoctl
and then rerunning your program.
With that said, I'm surprised that the D isn't wiped out by the blank after the %d in the format string. I suspect your actual code may be missing that. When I tested on my Mac, the program with the space after the %d did not show the D for long enough for me to spot it; when I removed that space, I got the output shown in the question.

pre-fill stdin in C

My program is supposed to let the user edit a line of a file. The user edits the line and sends it back by pressing enter. Therefore I would like to print the current line which is about to be edited, but kind of print it on stdin instead of stdout.
The only problem I don't know how to solve is how I can prefill the stdin. I've already tried this:
char cprefill[] = {"You may edit this line"};
char cbuffer[100];
fprintf(stdin, cprefill);
fgets(cbuffer, 100, stdin);
This seems to be the simplest solution, but is probably too simple to work. The fprintf doesn't print anything to stdin. What is the correct way?
Edit:
This is how it is supposed to look like. Please mind the cursor which can be moved.
The C language has no notion of terminal nor of line edition, so it cannot be done in a portable way. You can either rely on a library like [n]curses to get an almost portable solution, or if you only need that on one single OS use low level OS primitives.
For exemple on Windows, you could feed the input buffer by simulating key strokes into the appropriate window (for example by sending WM_CHAR messages) just before reading, but that would be highly non portable - and in the end is no longer a C but a Windows solution...
First you need the libreadline developer package. (You might also need the libreadline if it's not already available on your system)
On Debian / Ubuntu that's apt install libreadline-dev (plus libreadline6 if you need the binaries also - 6 might be different on your platform)
Then you can add an history to readline, like this
#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>
...
char cprefill[] = {"You may edit this line"};
add_history(cprefill);
char *buf = readline("Line: ");
printf("Edited line is %s\n", buf);
// free the line allocated by readline
free(buf);
User is prompted "Line: ", and has to do UP ARROW to get and edit the history, i.e. the cprefill line.
Note that you have to compile/link with -lreadline
readline prints the prompt given as argument, then waits for user interaction, allowing line edition, and arrows to load lines stored in the history.
The char * returned by readline has then to be freed (since that function allocates a buffer with malloc()).
You could use GNU Readline. It calls the function that rl_startup_hook points to when starting, where we use rl_insert_text to put our text in the line buffer.
#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>
int prefill(void)
{
rl_insert_text("You may edit this line");
return 0;
}
int main(void)
{
char *cbuffer;
puts("Please edit the following line");
rl_startup_hook = prefill;
if ((cbuffer = readline(NULL)) == NULL) /* if the user sends EOF, readline will return NULL */
return 1;
printf("You entered: %s\n", cbuffer);
free(cbuffer);
return 0;
}
For more information, see the GNU Readline manual.

Where is scanf() reading input from, if not from the keyboard?

I'm a novice programmer getting introduced to C and I'm missing something fundamental about the way my scanf() works. I want to read a single int from the keyboard with code like this:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int userBookSelection;
scanf("%i", &userBookSelection);
printf("Printing userBookSelection: %i", userBookSelection);
return EXIT_SUCCESS;
}
When I run the code, the console stays black until I stop debugging. There is never a cursor waiting for keyboard input. When I stop debug I can see this output in the console, same every time:
Printing userBookSelection: 2130567168
I'm debugging in Eclipse with MinGW GCC compiler on Windows. The code syntax seems to be correct -- is it possible there's something wrong in my build path to make this happen? I need to know why scanf() isn't reading for keyboard input.
So I've gotten a line of code from my professor which takes care of this bug -- whether it's a necessary solution particular to Eclipse and/or MinGW I'm not sure. In any case, here's the code with the additional line:
int main(void) {
int userBookSelection;
setvbuf (stdout, NULL, _IONBF, 0);//<---The magic line
scanf("%i", &userBookSelection);
printf("Printing userBookSelection: %i", userBookSelection);
return EXIT_SUCCESS;
}
I'd appreciate any additional wisdom on what's going on, what setvbuf() is doing and how scanf() works more fundamentally.

Why does getchar() not work right?

Today, I wrote a simple piece of code that uses getchar() to count the characters you input. But when I compile it on Cygwin, it does not work. It always prints 0, but I never input anything or I can't input any characters it prints 0.
However, if I compile it with VC++6.0, it works.
#include<stdio.h>
int main(void)
{
long nc;
nc = 0;
while(getchar() != EOF)
++nc;
printf("The total of characters you inputed is %ld.\n", nc);
return 0;
}
This email thread talks about a bug that sounds much like yours, but I can't see that there are any follow-ups to it.
I would be interested to know what happened when you try
while(getc(stdin) != EOF)
and if that doesn't work, try
while(fgetc(stdin) != EOF)
All of them should work, though this page suggests there could be implementation differences between these functions.
Another thing you could try is to print the ASCII value of what you get:
printf("%d\n",(int)getchar());
Also, try piping output from a file instead of typing it in the console. Create a file input.txt, put some characters in it, and do
cat input.txt | ./program
EDIT: You write running cat and piping it works. I would say simply update your Cygwin version. You have encountered a bug. Get the newest versions of Cygwin and the compiler, and you should be good to go. Another option is to use scanf.

I'm hitting a segmentation error when I scanf(%s,lastName); (body code inside)

EDIT: About to try intilizing my chars properly... [didnt work=( ]
EDIT: SOLVED (I can't answer my own question for another 7 hours...)
Thanks for the comment Brian, that's just a constant declared at the top.. (it = 20).
It turns out the error was happening because I forgot to add a next line after I took in the input name.
it's working now =D
:ENDEDIT (lol)
I've code my code below, Basically I put in the first name this is supposed to find
John
Then I put in the last name...
Locke
and as soon as I enter in "Locke" it hits this error, I feel like maybe it's the scanf and I should be using a better alternative ???
int findPatron(struct Library *lib,struct Patron **p)
{
int i;
char firstName[NAME_LENGTH], lastName[NAME_LENGTH];
printf("\nPlease enter the patron's first name: ");
scanf("%s",firstName);
printf("\nPlease enter the patron's last name: "); //this line prints...
scanf("%s",lastName); //SEGMENTATION ERROR happens here I'm pretty sure.
printf("deerrrr"); //this line never prints
for(i = 0; i<lib->totalPatrons;i++)
{
printf("checking %s %s to %s %s",lib->patrons[i].name.first,lib->patrons[i].name.last,firstName,lastName);
if((strcmp(lib->patrons[i].name.first, firstName) == 0) && (strcmp(lib->patrons[i].name.last, lastName) == 0))
{
**p = lib->patrons[i];
return 0;
break;
}
}
return 1; //No Match!
}
You're getting the segmentation fault after your scanf() statements.
If you remove everything after printf("deerrrr"); and add a \n to that output so the buffer is flushed, you'll find that it all works just fine (provided NAME_LENGTH is at least 6 given your example input).
Part of programming is knowing how to isolate and debug your problems.
Your issues are with your loop and lib struct - you're dereferencing something you shouldn't be.
SEGMENTATION ERROR happens here I'm pretty sure
this line never prints
C's printf is buffered, and only gets flushed by an explicit call to fflush or a blocking action (like scanf, which AFAIK flushes stdout as well), so the error could happen in another place. Learn to use debugger, that's the proper way of debugging C programs.

Resources