I can't figure out why my while loop won't work. The code works fine without it... The purpose of the code is to find a secret message in a bin file. So I got the code to find the letters, but now when I try to get it to loop until the end of the file, it doesn't work. I'm new at this. What am I doing wrong?
main(){
FILE* message;
int i, start;
long int size;
char keep[1];
message = fopen("c:\\myFiles\\Message.dat", "rb");
if(message == NULL){
printf("There was a problem reading the file. \n");
exit(-1);
}
//the first 4 bytes contain an int that tells how many subsequent bytes you can throw away
fread(&start, sizeof(int), 1, message);
printf("%i \n", start); //#of first 4 bytes was 280
fseek(message, start, SEEK_CUR); //skip 280 bytes
keep[0] = fgetc(message); //get next character, keep it
printf("%c", keep[0]); //print character
while( (keep[0] = getc(message)) != EOF) {
fread(&start, sizeof(int), 1, message);
fseek(message, start, SEEK_CUR);
keep[0] = fgetc(message);
printf("%c", keep[0]);
}
fclose(message);
system("pause");
}
EDIT:
After looking at my code in the debugger, it looks like having "getc" in the while loop threw everything off. I fixed it by creating a new char called letter, and then replacing my code with this:
fread(&start, sizeof(int), 1, message);
fseek(message, start, SEEK_CUR);
while( (letter = getc(message)) != EOF) {
printf("%c", letter);
fread(&start, sizeof(int), 1, message);
fseek(message, start, SEEK_CUR);
}
It works like a charm now. Any more suggestions are certainly welcome. Thanks everyone.
The return value from getc() and its relatives is an int, not a char.
If you assign the result of getc() to a char, one of two things happens when it returns EOF:
If plain char is unsigned, then EOF is converted to 0xFF, and 0xFF != EOF, so the loop never terminates.
If plain char is signed, then EOF is equivalent to a valid character (in the 8859-1 code set, that's ÿ, y-umlaut, U+00FF, LATIN SMALL LETTER Y WITH DIAERESIS), and your loop may terminate early.
Given the problem you face, we can tentatively guess you have plain char as an unsigned type.
The reason that getc() et al return an int is that they have to return every possible value that can fit in a char and also a distinct value, EOF. In the C standard, it says:
ISO/IEC 9899:2011 §7.21.7.1 The fgetc() function
int fgetc(FILE *stream);
If the end-of-file indicator for the input stream pointed to by stream is not set and a
next character is present, the fgetc function obtains that character as an unsigned char converted to an int ...
If the end-of-file indicator for the stream is set, or if the stream is at end-of-file, the end-of-
file indicator for the stream is set and the fgetc function returns EOF.
Similar wording applies to the getc() function and the getchar() function: they are defined to behave like the fgetc() function except that if getc() is implemented as a macro, it may take liberties with the file stream argument that are not normally granted to standard macros — specifically, the stream argument expression may be evaluated more than once, so calling getc() with side-effects (getc(fp++)) is very silly (but change to fgetc() and it would be safe, but still eccentric).
In your loop, you could use:
int c;
while ((c = getc(message)) != EOF) {
keep[0] = c;
This preserves the assignment to keep[0]; I'm not sure you truly need it.
You should be checking the other calls to fgets(), getc(), fread() to make sure you are getting what you expect as input. Especially on input, you cannot really afford to skip those checks. Sooner, rather than later, something will go wrong and if you aren't religiously checking the return statuses, your code is likely to crash, or simply 'go wrong'.
There are 256 different char values that might be returned by getc() and stored in a char variable like keep[0] (yes, I'm oversummarising wildly). To detect end-of-file reliably, EOF has to have a value different from all of them. That's why getc() returns int rather than char: because a 257th distinct value for EOF wouldn't fit into a char.
Thus you need to store the value returned by getc() in an int at least until you check it against EOF:
int tmpc;
while( (tmpc = getc(message)) != EOF) {
keep[0] = tmpc;
...
Related
I have this code and I don't understand how it works:
void print(char * fileName)
{
FILE * fp;
int ch;
fp = fopen(fileName, "r");
while (ftell(fp) < 20)
{
ch = fgetc(fp);
putchar(ch);
}
fclose(fp);
}
So how is ftell(fp) works if it is in loop?
Because there is nothing inside the loop that get it up.
how it is progressive?
ftell() gets you the current value of the position indicator of the stream(in your case, it basically returns the character position it is currently pointing to right now).
fgetc() gets the next character (an unsigned char) from the specified stream and advances the position indicator for the stream. This function returns the character read as an unsigned char cast to an int or EOF on end of file or error
Flow of your program
What that means in very simple terms is -
fgetc() is reading one character after character from the file and advancing the pointer to the next character.
ftell() is returning you the current position in in bytes from the
beginning of the file. This means it tells the position of the character it is pointing right now(since 1 char takes 1 byte).
So, your program reads from the file until ftell() returns the
position which is less than 20.This means that it will keep looping until 20 characters have been read from your file.
Hope this clears your doubt !
ftell returns the current value of the file position indicator, and fgetc does advance the file position indicator within the loop.
But this program is wrong. For a stream opened in text mode ("r"), the return value of ftell cannot be used portably for anything else except for seeking to a previous position. From C11 draft n1570 7.21.9.4p2
[...] For a text stream, its file position indicator contains unspecified information, usable by the fseek function for returning the file position indicator for the stream to its position at the time of the ftell call; the difference between two such return values is not necessarily a meaningful measure of the number of characters written or read.
Indeed it doesn't make any sense to use ftell in this program. Either open the file in binary mode, "rb", and then it is guaranteed that
[...] the value is the number of characters from the beginning of the file.
or for counting characters read from text file, use a counter variable:
int c_read = 0;
while (c_read < 20)
{
ch = fgetc(fp);
putchar(ch);
c_read ++;
}
Finally neither your original version or mine does not work correctly if the file has less than 20 characters. In that case EOF is returned from fgetc and putchar would write (unsigned char)EOF to the stream (most likely a byte of value 255!)
Thus the correct code would be
int c_read = 0;
while (c_read < 20)
{
ch = fgetc(fp);
if (ch == EOF) {
// report the error
perror("Failed to read 20 characters");
break;
}
putchar(ch);
c_read ++;
}
I have a file that's been passed as stdin in my program. Every iteration of a very large loop, a method "get_next" calls getchar, and gets the next char in stdin and assigns it to a variable named nchar.
The problem is, I have an instance where I have to look at the char after the current nchar without changing what the next call to get_next does. Meaning, I have to call getchar() without it changing the buffer's state.
Is there a way to do this? Is there a method like "getcharStatic" that returns the next char without changing the buffer, à la peek vs pop for a stack?
Alternatively, is there a way to read the char normally with getchar and then insert the char right where I took it from, thereby artificially conserving the buffer's state?
I tried googling for a while, and I think the problem involves too vague terms and tags. Thanks for any help!
You can use ungetc() to push the character back into stdin. Here's a blurb from the doc:
int ungetc( int ch, FILE *stream );
If ch does not equal EOF, pushes the character ch (reinterpreted as unsigned char) into the input
buffer associated with the stream stream in such a manner that
subsequent read operation from stream will retrieve that character.
You can use ungetc(), maybe like this:
int fpeekc(FILE *fp)
{
int c = getc(fp);
if (c != EOF)
ungetc(c, fp);
return c;
}
Careful reading of the POSIX specification indicates that you could call ungetc() with EOF and the call would be ignored, so it isn't 100% necessary to make the test in the fpeekc() function, but it does make ungetc() fail and return EOF. If you like living — dangerously, or compactly; take your choice — you could use:
int fpeekc(FILE *fp)
{
return ungetc(getc(fp), fp);
}
And if you desired, you could make that an inline function. If you are on POSIX and need to be thread-safe, you can use:
int fpeekc(FILE *fp)
{
flockfile(fp);
int c = getc_unlocked(fp); // Legitimate because of flockfile(); getc(fp) works too
if (c != EOF)
{
// ungetc_unlocked() is not defined by POSIX but is available on
// some but not all POSIX-like systems. See comments below.
ungetc(c, fp);
}
funlockfile(fp);
return c;
}
That prevents another thread from interfering with the stream while you're working on it. See also the discussion with Nominal Animal in the comments below.
And you could use:
static inline int peekc(void) { return fpeekc(stdin); }
if you want to do it for standard input.
I think you want int ungetc(int char, FILE *stream).
You could have a method:
char fgetputbackc(file *f){
int c = fgetc(f);
ungetc(c, f);
return c;
}
I have a program that reads a file into a buffer structure. The problem I'm having is that when I look at the output of the file, there's an extra EOF character at the end. Ill post the related functions:(NOTE: I removed parameter checks and only posted code in the function related to the issue)
b_load
int b_load(FILE * const fi, Buffer * const pBD){
unsigned char character; /*Variable to hold read character from file*/
Buffer * tempBuffer; /*Temparary Bufer * to prevent descruction of main Buffer*/
short num_chars = 0; /*Counter of the amount of characters read into the buffer*/
/*Assigns main Buffer to tempBuffer*/
tempBuffer = pBD;
/*Infinite loop that breaks after EOF is read*/
while(1){
/*calls fgetc() and returns the char into the character variable*/
character = (unsigned char)fgetc(fi);
if(!feof(fi)){
tempBuffer = b_addc(pBD,character);
if(tempBuffer == NULL)
return LOAD_FAIL;
++num_chars;
}else{
break;
}
}
return num_chars;
}
b_print
int b_print(Buffer * const pBD){
int num_chars = 0;
if(pBD->addc_offset == 0)
printf("The buffer is empty\n");
/*Sets getc_offset to 0*/
b_set_getc_offset(pBD, 0);
pBD->eob=0;
/*b_eob returns the structures eob field*/
while (!b_eob(pBD)){
printf("%c",b_getc(pBD));
++num_chars;
}
printf("\n");
return num_chars;
}
b_getc
char b_getc(Buffer * const pBD){
if(pBD->getc_offset == pBD->addc_offset){
pBD->eob = 1;
return R_FAIL_1;
}
pBD->eob = 0;
return pBD->ca_head[(pBD->getc_offset)++];
}
at the end I end up with:
"a catÿ"
(the y is the EOF character)
It prints an EOF character but is never added to the buffer. When the driver code adds an EOF character to the end of the buffer, 2 appear. Any idea what is causing this? I might be using feof() wrong so that may be it, but it is required in the code
There is no "EOF character". EOF is a value returned by getchar() and related functions to indicate that they have no more input to read. It's a macro that expands to a negative integer constant expression, typically (-1).
(For Windows text files, an end-of-file condition may be triggered by a Control-Z character in a file. If you read such a file in text mode, you won't see that character; it will just act like it reached the end of the file at that point.)
Don't use the feof() function to detect that there's no more input to read. Instead, look at the value returned by whatever input function you're using. Different input functions use different ways to indicate that they weren't able to read anything; read the documentation for whichever one you're using. For example, fgets() returns a null pointer, getchar() returns EOF, and scanf() returns the number of items it was able to read.
getchar(), for example, returns either the character it just read (treated as an unsigned char and converted to int) or the value EOF to indicate that it wasn't able to read anything. The negative value of EOF is chosen specifically to avoid colliding with any valid value of type unsigned char. Which means you need to store the value returned by getchar() in an int object; if you store it in a char or unsigned char instead, you can lose information, and an actual character with the value 0xff can be mistaken for EOF.
The feof() function returns the value of the end-of-file indicator for the file you're reading from. That indicator becomes true after you've tried and failed to read from the file. And if you ran out of input because of an error, rather than because of an end-of-file condition, feof() will never become true.
You can use feof() and/or ferror() to determine why there was no more input to be read, but only after you've detected it by other means.
Recommended reading: Section 12 of the comp.lang.c FAQ, which covers stdio. (And the rest of it.)
UPDATE :
I haven't seen enough of your code to understand what you're doing with the Buffer objects. Your input look actually looks (almost) correct, though it's written in a clumsy way.
The usual idiom for reading characters from a file is:
int c; /* `int`, NOT `char` or `unsigned char` */
while ((c = fgetc(fi)) != EOF) {
/* process character in `c` */
}
But your approach, which I might rearrange like this:
while (1) {
c = fgetc(fi);
if (feof(fi) || ferror(fi)) {
/* no more input */
break;
}
/* process character in c */
}
should actually work. Note that I've added a check for ferror(f1). Could it be that you have an error on input (which you're not detecting)? That would cause c to contain EOF, or the value of EOF converted to the type of c. That's doubtful, though, since it would probably give you an infinite loop.
Suggested approach: Using either an interactive debugger or added printf calls, show the value of character every time through the loop. If your input loop is working correctly, then build a stripped-down version of your program with a hard-wired sequence of calls to b_addc(), and see if you can reproduce the problem that way.
There you go ...
int b_load(FILE * const fi, Buffer * const pBD){
int character; /*Variable to hold read character from file*/
Buffer * tempBuffer; /*Temparary Bufer * to prevent descruction of main Buffer*/
short num_chars ; /*Counter of the amount of characters read into the buffer*/
/*Infinite loop that breaks WHEN EOF is read*/
while(num_chars = 0; 1; num_chars++ ) {
character = fgetc(fi);
if (character == EOF || feof(fi)) break; // since you insist on the silly feof() ...
tempBuffer = b_addc(pBD, (unsigned char) character);
if(tempBuffer == NULL) return LOAD_FAIL;
}
}
return num_chars;
}
I'm trying to read a file and replace every char by it's corresponding char up one in ASCII table. It opens the file properly but keep on reading the first character.
int main(int argc, char * argv[])
{
FILE *input;
input = fopen(argv[2], "r+");
if (!input)
{
fprintf(stderr, "Unable to open file %s", argv[2]);
return -1;
}
char ch;
fpos_t * pos;
while( (ch = fgetc(input)) != EOF)
{
printf("%c\n",ch);
fgetpos (input, pos);
fsetpos(input, pos-1);
fputc(ch+1, input);
}
fclose(input);
return 1;
}
the text file is
abc
def
ghi
I'm pretty sure it's due to the fgetpos and fsetpos but if I remove it then it will add the character at the end of the file and the next fgetc will returns EOF and exit.
You have to be careful when dealing with files opened in update mode.
C11 (n1570), § 7.21.5.3 The fopen function
When a file is opened with update mode ('+' as the second or third character in the
above list of mode argument values), both input and output may be performed on the
associated stream.
However, output shall not be directly followed by input without an
intervening call to the fflush function or to a file positioning function (fseek,
fsetpos, or rewind), and input shall not be directly followed by output without an
intervening call to a file positioning function, unless the input operation encounters end-of-file.
So your reading might look something like :
int c;
while ((c = getc(input)) != EOF)
{
fsetpos(/* ... */);
putc(c + 1, input);
fflush(input);
}
By the way, you will have problems with 'z' character.
procedure for performing random access such
positioned the record
reading of the record
positioned the record
update(write) the record
do flush (to finalize the update)
The following code is a rewrite in consideration to it.
#include <stdio.h>
#include <ctype.h>
int main(int argc, char * argv[]){
FILE *input;
input = fopen(argv[1], "rb+");
if (!input){
fprintf(stderr, "Unable to open file %s", argv[1]);
return -1;
}
int ch;
fpos_t pos, pos_end;
fgetpos(input, &pos);
fseek(input, 0L, SEEK_END);
fgetpos(input, &pos_end);
rewind(input);
while(pos != pos_end){
ch=fgetc(input);
if(EOF==ch)break;
printf("%c",ch);
if(!iscntrl(ch) && !iscntrl(ch+1)){
fsetpos(input, &pos);
fputc(ch+1, input);
fflush(input);
}
pos += 1;
fsetpos(input, &pos);
}
fclose(input);
return 1;
}
I really suspect the problem is here:
fpos_t * pos;
You are declaring a pointer to a fpos_t which is fine but then, where are the infomation stored when you'll retrieve the pos?
It should be:
fpos_t pos; // No pointer
...
fgetpos (input, &pos);
fsetpos(input, &pos); // You can only come back where you were!
Reading the (draft) standard, the only requirement for fpos_t is to be able to represent a position and a state for a FILE, it doesn't seem that there is a way to move the position around.
Note that the expression pos+1 move the pointer, does not affect the value it points to!
What you probably want is the old, dear ftell() and fseek() that will allow you to move around. Just remember to open the file with "rb+" and to flush() after your fputc().
When you'll have solved this basic problem you will note there is another problem with your approach: handling newlines! You most probably should restrict the range of characters you will apply your "increment" and stipulate that a follows z and A follows Z.
That said, is it a requirement to do it in-place?
7.21.9.1p2
The fgetpos function stores the current values of the parse state (if
any) and file position indicator for the stream pointed to by stream
in the object pointed to by pos. The values stored contain unspecified
information usable by the fsetpos function for repositioning the
stream to its position at the time of the call to the fgetpos
function.
The words unspecified information don't seem to inspire confidence in that subtraction. Have you considered calling fgetpos prior to reading the character, so that you don't have to do a non-portable subtraction? Additionally, your call to fgetpos should probably pass a pointer to an existing fpos_t (eg. using the &address-of operator). Your code currently passes a pointer to gibberish.
fgetc returns an int, so that it can represent every possible unsigned char value distinct from negative EOF values.
Suppose your char defaults to an unsigned type. (ch = fgetc(input)) converts the (possibly negative, corresponding to errors) return value straight to your unsigned char type. Can (unsigned char) EOF ever compare equal to EOF? When does your loop end?
Suppose your char defaults, instead, to a signed type. (c = fgetc(input)) is likely to turn the higher range of any returned unsigned char values into negative numbers (though, technically, this statement invokes undefined behaviour). Wouldn't your loop end prematurely (eg. before EOF), in some cases?
The answer to both of these questions indicates that you're handing the return value of fgetc incorrectly. Store it in an int!
Perhaps your loop should look something like:
for (;;) {
fpos_t p;
/* TODO: Handle fgetpos failure */
assert(fgetpos(input, &p) == 0);
int c = fgetc(input);
/* TODO: Handle fgetc failure */
assert(c >= 0);
/* TODO: Handle fsetpos failure */
assert(fsetpos(input, &p) == 0);
/* TODO: Handle fputc failure */
assert(fputc(c + 1, input) != EOF);
/* TODO: Handle fflush failure (Thank Kirilenko for this one) */
assert(fflush(input) == 0);
}
Make sure you check return values...
The update mode('+') can be a little bit tricky to handle. Maybe You could just change approach and load the whole file into char array, iterate over it and then eventually write the whole thing to an emptied input file? No stream issues.
I am just trying to read each character of the file and print it out but when the file finishes reading, but I am getting a bunch of ? after it finishes reading. How do I fix it?
#include <stdio.h>
int main(void){
FILE *fr; /* declare the file pointer */
fr = fopen ("some.txt", "r"); /* open the file for reading */
/* elapsed.dta is the name of the file */
/* "rt" means open the file for reading text */
char c;
while((c = getc(fr)) != NULL)
{
printf("%c", c);
}
fclose(fr); /* close the file prior to exiting the routine */
/*of main*/
return 0;
}
In spite of its name, getc returns an int, not a char, so that it can represent all of the possible char values and, in addition, EOF (end of file). If getc returned a char, there would be no way to indicate the end of file without using one of the values that could possibly be in the file.
So, to fix your code, you must first change the declaration char c; to int c; so that it can hold the EOF marker when it is returned. Then, you must also change the while loop condition to check for EOF instead of NULL.
You could also call feof(fr) to test end of file separately from reading the character. If you did that, you could leave c as a char, but you would have to call feof() after you read the character but before you printed it out, and use a break to get out of the loop.
If unsuccessful, fgetc() returns EOF.
int c;
while ((c = getc(fr)) != EOF)
{
printf("%c", c);
}
Change this
char c;
while((c = getc(fr)) != NULL)
{
printf("%c", c);
}
to
char c;
int charAsInt;
while((charAsInt = getc(fr)) != EOF)
{
c = (char) charAsInt;
printf("%c", c);
}
In other words: You need to compare against EOF, not NULL. You also need to use an int variable to receive the return value from fgetc. If you use a char, the comparison with EOF may fail, and you'll be back where you started.
fgetc() returns EOF on end-of-file, not NULL.
Replace "NULL" with "EOF".
Others have already addressed the issue you're having, but rather than using printf("%c", c); it is probably much more efficient to use putchar(c);. There is quite a bit of overhead involved when you ask printf to print just one character.
getc returns an int.
change char c, to int c.
also getc returns EOF,
change your test against NULL to a test against EOF