This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Using fseek with a file pointer that points to stdin
i have a program that use fseek to clear my input buffer, it works well in Windows, buf fails in Linux. Please help me .
#include <stdio.h>
#define NO_USE_FSEEK 0
int main(int argc, char *argv[])
{
char ch = 'a';
int i = 1;
long int fpos = -1;
while(1)
{
printf("loop : %d\n", i);
fseek(stdin, 0L, SEEK_END); /*works in Windows with MinGW, fails in Linux*/
fpos = ftell(stdin);
if (-1 == fpos)
{
perror("ftell failure:"); /*perror tells it is Illegal Seek*/
printf("\n");
}
else
{
printf("positon indicator:%ld\n", fpos);
}
scanf("%c", &ch);
printf("%d : %c\n", (int)ch, ch);
i++;
}
return 0;
}
Thanks in advance!
This is not the accepted way to "clear your input buffer" on either Windows or Linux.
On windows, using the MSVCRT version of the standard C functions, there is an extension allowing fflush(stdin) for this purpose. Note that on other systems this is undefined behavior.
Linux has a function called fpurge with the same purpose.
However, I have to ask, why do you want to clear your input buffer? If it's the usual complaint people have with scanf not reading to the end of the line, it would be better to write code to actually read and discard the rest of the line (loop with getc until reading a '\n', for example, as in pmg's answer). Clearing the input buffer will tend to skip a large amount of data when used on a redirected file or pipe rather than the normal console/tty input.
i guess fseek will not work with stdin. Because the size of stdin is not known.
Test the return value from fseek() (in fact, test the return value from all <stdio.h> input functions).
if (fseek(stdin, 0, SEEK_END) < 0) { perror("fseek"); exit(EXIT_FAILURE); }
Use the idiom
while ((ch = getchar()) != '\n' && ch != EOF) /* void */;
/* if (ch == EOF)
** call feof(stdin) or ferror(stdin) if needed; */
to ignore all characters in the input buffer up to the next ENTER (or end of file or input error).
Related
I am trying to write a simple C program that loads a text-file, prints the first line to screen, waits for the user to press enter and then prints the next line, and so on.
As only argument it accepts a text-file that is loaded as a stream "database". I use the getline()-function for this, according to this example. It compiles fine, successfully loads the text-file, but the program never enters the while-loop and then exits.
#include <stdio.h>
#include <stdlib.h>
FILE *database = NULL; // input file
int main(int argc, char *argv[])
{
/* assuming the user obeyed syntax and gave input-file as first argument*/
char *input = argv[1];
/* Initializing input/database file */
database = fopen(input, "r");
if(database == NULL)
{
fprintf(stderr, "Something went wrong with reading the database/input file. Does it exist?\n");
exit(EXIT_FAILURE);
}
printf("INFO: database file %s loaded.\n", input);
/* Crucial part printing line after line */
char *line = NULL;
size_t len = 0;
ssize_t read;
while((read = getline(&line, &len, database)) != -1)
{
printf("INFO: Retrieved line of length %zu :\n", read);
printf("%s \n", line);
char confirm; // wait for user keystroke to proceed
scanf("%c", &confirm);
// no need to do anything with "confirm"
}
/* tidy up */
free(line);
fclose(database);
exit(EXIT_SUCCESS);
}
I tried it with fgets() -- I can also post that code --, but same thing there: it never enters the while-loop.
It might be something very obvious; I am new to programming.
I use the gcc-compiler on Kali Linux.
Change your scanf with fgetline using stdin as your file parameter.
You should step through this in a debugger, to make sure your claim that it never enters the while loop is correct.
If it truly never enters the while loop, it is necessarily because getline() has returned -1. Either the file is truly empty, or you have an error reading the file.
man getline says:
On success, getline() and getdelim() return the number of
characters
read, including the delimiter character, but not including the termiā
nating null byte ('\0'). This value can be used to handle embedded
null bytes in the line read.
Both functions return -1 on failure to read a line (including end-of-
file condition). In the event of an error, errno is set to indicate
the cause.
Therefore, you should enhance your code to check for stream errors and deal with errno -- you should do this even when your code works, because EOF is not the only reason for the function
to return -1.
int len = getline(&line, &len, database);
if(len == -1 && ferror(database)) {
perror("Error reading database");
}
You can write more detailed code to deal with errno in more explicit ways.
Unfortunately handling this thoroughly can make your code a bit more verbose -- welcome to C!
I want to know how to check if my input buffer (perhaps its called stdin) is empty or not.
I dont want the program to stop if the buffer is empty, and I dont want the input to necessarily end with \n, therefore just using scanf is not enough.
I tried searching on google and on this website but no answer was enough.
I tried using feof(stdin) like this:
int main()
{
char c,x;
int num;
scanf("%c",&c);
scanf("%c",&x);
num=feof(stdin);
printf("%d",num);
}
but all it did was printing 0 no matter the input. adding fflush(stdin) after the second scanf gave the same result.
other answers suggested using select and poll but I couldnt find any explanations for those functions.
Some other forum told me to use getchar() but I think they misunderstood my question.
if you suggest I use select/poll, could you please add an explanation about how to use those?
Here is the code for solving this:
fseek (stdin, 0, SEEK_END);
num = ftell (stdin);
fseek will put the pointer at the end of the stdin input buffer. ftell will return the size of file.
If you don't want to block on an empty stdin you should be able to fcntl it to O_NONBLOCK and treat it like any other non-blocking I/O. At that point a call to something like fgetc should return immediately, either with a value or EAGAIN if the stream is empty.
int ch = getc(stdin);
if (ch == EOF)
puts("stdin is empty");
else
ungetc(ch, stdin);
Try this, ungetc(ch, stdin); is added to eliminate the side effect.
You can use select() to handle the blocking issue and the man page select(2) has a decent example that polls stdin. That still doesn't address the problem of needing a line-delimiter ('\n'). This is actually due to the way the terminal handles input.
On Linux you can use termios,
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
// immediate mode getchar().
static int getch_lower_(int block)
{
struct termios tc = {};
int status;
char rdbuf;
// retrieve initial settings.
if (tcgetattr(STDIN_FILENO, &tc) < 0)
perror("tcgetattr()");
// non-canonical mode; no echo.
tc.c_lflag &= ~(ICANON | ECHO);
tc.c_cc[VMIN] = block ? 1 : 0; // bytes until read unblocks.
tc.c_cc[VTIME] = 0; // timeout.
if (tcsetattr(STDIN_FILENO, TCSANOW, &tc) < 0)
perror("tcsetattr()");
// read char.
if ((status = read(STDIN_FILENO, &rdbuf, 1)) < 0)
perror("read()");
// restore initial settings.
tc.c_lflag |= (ICANON | ECHO);
if (tcsetattr(STDIN_FILENO, TCSADRAIN, &tc) < 0)
perror("tcsetattr()");
return (status > 0) ? rdbuf : EOF;
}
int getch(void)
{
return getch_lower_(1);
}
// return EOF if no input available.
int getch_noblock(void)
{
return getch_lower_(0);
}
I have following C program.
#include <stdio.h>
int main()
{
FILE *fp;
long n;
char c;
fp=fopen("RANDOM","W");
while((c=getchar()) != EOF)
{
putc(c,fp);
}
printf("No. of character entered = %1d\n",ftell(fp));
fclose(fp);
n=0L;
while(feof(fp) == 0)
{
fseek(fp, n, 0);
printf("Position of %c is %1d\n", getc(fp), ftell(fp));
n=n+5L;
}
printf("\n");
fseek(fp,-1L,2);
do
{
putchar(getc(fp));
}
while(!fseek(fp,-2L,1));
fclose(fp);
return 0;
}
This code is not showing any error. But when I run the code after giving input ABCD...Z, it says segment fault, core dumped. Where is the problem??
Confident the seg fault is from calling feof() after the fclose(). fp is closed at the point and should not be passed as an augment to another IO function.
Number of issues
1) Do not use uppercase "W", but lowercase "w". Else undefined behavior (UB).
2) Use of fopen("RANDOM","w") truncates a file to zero length and writing, but not update. Suggest use fopen("RANDOM","r+") "open text file for update (reading and writing)" or fopen("RANDOM","w+") which open for reading and writing and "truncate to zero length or create text file for update" #BLUEPIXY
3) char c; ... while((c=getchar()) != EOF) is wrong as the end-of-file condition will get flagged on some legitimate char. Instead use int c.
4) No need for fclose(fp); after printf("No. of....
5) while(feof(fp) == 0) begin an infinite loop. If anything use if (feof(fp) == 0). Although for learner's purposes, the test can be dropped.
5R) May this is OK. Recommend checking result of fseek(fp, n, 0);
6) printf("Position of %c is %1d\n", getc(fp), ftell(fp)); should use "%ld" and not "%d".
7) Do not use fseek(fp, n, 0); and fseek(fp,-1L,2); but something like fseek(fp, -1L, SEEK_SET); or SEEK_CUR SEEK_END.
8) Without using the standard macros as mentioned above, unclear what the code's goal is for fseek(fp,-1L,2);
9) Suggest testing the result of fseek(fp,-1L,2);.
10) printf("Position of %c is %1d\n", getc(fp), ftell(fp)); is a problem. (identified by #BLUEPIXY). The order that getc(fp) and ftell(fp) is called is left to the compiler to choose. Better to be explicit like printf("Position of %c is ", getc(fp)); printf("%ld\n", ftell(fp));.
If code is to truncate an existing file before writing, opening with "w" is good. Rather than the remove the middle fclose(), consider freopen(..., "r").
To begin with, add fp=fopen("RANDOM","R") after the first fclose(fp).
You can't read from a file after closing it (neither can you read from it when it's opened only for writing).
I'm working on a small C program for a college assignment and I've noticed a weird bug in my code. I use an iMac with the short keyboard generally, but its battery was flat so i plugged in a standard USB keyboard with number pad.
The weird thing is that if I hit [Enter] on my number pad, it seems to do what the regular [Enter} key does, but the \n I am trying to detect in the stdin function I made to read the keyboard input, doesn't work when I use the number pad's [Enter] key.
Wtf?
Here is my function that reads the user input:
/* This is my implementation of a stdin "scanner" function which reads
* on a per character basis until the the termination signals are found
* and indescriminately discarding all characters in the input in excess
* of the supplied (limit) parameter. Eliminates the problem of 'left-over'
* characters 'polluting' future stdin reads.
*/
int readStdin(int limit, char *buffer)
{
char c;
int i = 0;
int read = FALSE;
while ((c = myfgetc(stdin)) != '\n' && c != '\0') {
/* if the input string buffer has already reached it maximum
limit, then abandon any other excess characters. */
if (i <= limit) {
*(buffer + i) = c;
i++;
read = TRUE;
}
}
/* clear the remaining elements of the input buffer with a null character. */
for (i = i; i < strlen(buffer); i++) {
*(buffer + i) = '\0';
}
return read;
}
/* This function used to wrap the standard fgetc so that I can inject programmable
* values into the stream to test my readStdin functions.
*/
int myfgetc (FILE *fin) {
if (fakeStdIn == NULL || *fakeStdIn == '\0')
return fgetc (fin);
return *fakeStdIn++;
}
NB: The myfgetc and the subsequent *fakeStdIn are part of a way that I can unit test my code and 'inject' items into the stdin stream programatically as someone suggested on this question: How do I write a testing function for another function that uses stdin input?.
What output do you get for this tiny test?
#include <stdio.h>
int main(int argc, char* argv[]) {
int c;
while((c=getchar()) != EOF) {
printf("%d\n", c);
}
return 0;
}
Could well be that on Mac, you are getting \r\n, not just \n.
So it turns out that it's a Mac OSX thing. I've spoken to other Mac users and they have the same problem. Never found a fix because one may simply not exist. The problem doesn't occur on Solaris machines and since that's the OS which the code will be run on, I guess it doesn't really matter.
I am going to answer this myself with the answer that its just one of those OSX "quirks" and be done with it.
While doing filing im stuck here.The condition of the while loop is not working.The compiler says cannot convert int to FILE*.
while(pFile!=EOF);
Should i typecase the pFile to int?I tried that but it did not worked.Thanks in advance.
The complete code is:
int main()
{
char ch;
char name[20];
FILE *pFile;
int score;
pFile=fopen("database.txt","r");
if(pFile!=NULL)
{
while(pFile!=EOF);
{
fscanf(pFile,"%c",ch);
}
}
else
printf("Cant open the file.......");
fclose(pFile);
return 0;
}
First, you do not want to use while (!feof(pFile)) -- ever! Doing so will almost inevitably lead to an error where the last data you read from the file appears to be read twice. It's possible to make it work correctly, but only by adding another check in the middle of the loop to exit when EOF is reached -- in which case, the loop condition itself will never be used (i.e., the other check is the one that will actually do the job of exiting the loop).
What you normally do want to do is check for EOF as you read the data. Different functions indicate EOF in different ways. fgets signals failure (including EOF) by returning NULL. Most others (getc, fgetc, etc.) do return EOF, so you typically end up with something like this:
int ch; // Note, this should be int, NOT char
while (EOF != (ch=getc(pFile)))
process(ch);
or:
char buffer[MAX_LINE_SIZE];
while (fgets(buffer, sizeof(buffer), pFile))
process(buffer);
With scanf, checking for success is a little more complex -- it returns the number of successful conversions, so you want to make sure that matches what you expected. For example:
while (1 == fscanf(fPfile, "%d", &input_number))
process(input_number);
In this case I've used 1 because I specified 1 conversion in the format string. It's also possible, however, for conversion to fail for reasons other than EOF, so if this failes, you'll frequently want to check feof(pFile). If it returns false, do something like reading the remainder of the line, showing it to the user in a warning message, and then continuing to read the rest of the file.
It depends what pFile and EOF are defined as, but I will asssume that pFile is a *FILE, and EOF is from stdio.h. Then I guess you should do something like:
#include <stdlib.h>
#include <stdio.h>
#define FILENAME "file.txt"
int main(void) {
FILE *pFile;
int ch;
pFile = fopen(FILENAME,"r");
if (pFile) {
while ((ch = getc(pFile)) != EOF) {
printf("Read one character: %c\n", ch);
}
close(pFile);
return EXIT_SUCCESS;
} else {
printf("Unable to open file: '%s'\n", FILENAME);
return EXIT_FAILURE;
}
}
which yields
$ echo "abc" > file.txt
$ /tmp/fileread
Read one character: a
Read one character: b
Read one character: c
Read one character:
# last character being a linefeed
Assuming pFile is your file handle, this doesn't change as you read from the file. EOF is returned by e.g. fgetc(). See e.g. http://www.drpaulcarter.com/cs/common-c-errors.php#4.2 for common ways to solve this.
here is correct way:
c = getc(pFile);
while (c != EOF) {
/* Echo the file to stdout */
putchar(c);
c = getc(pFile);
}
if (feof(pFile))
puts("End of file was reached.");
else if (ferror(pFile))
puts("There was an error reading from the stream.");
else
/*NOTREACHED*/
puts("getc() failed in a non-conforming way.");
fclose(pFile);
pFile is a pointer to a file. EOF is usually defined as -1, a signed integer.
What you should do is fopen, make sure pFile != NULL, then call some function on the file handle until that function returns EOF. A pointer will (or rather, should) never be EOF. But a function acting on that pointer may return EOF.
I'm guessing you want to keep looping while you haven't hit end-of-file. In that case, you are looking for this:
while (!feof(pFile))
{
...
}
That said, this is still not quite correct. feof will only return true once it tries to read beyond the end of the file. This means feof can return false and yet there is no more data to read. You should really try your operation and only check for end of file if it fails:
char buffer[SIZE];
while (fgets(buffer, sizeof(buffer), pFile))
{
...
}
if (!feof(pFile))
{
// fgets failed for some reason *other* then end-of-file
}