-
Opening files.
I've got the following code:
Code:
#include <stdio.h>
FILE * fptr;
int main()
{
char fileLine[81];
fptr = fopen("C:\\aap.txt", "r");
if (fptr != 0)
{
while (!feof(fptr))
{
fgets(fileLine, 81, fptr);
if (!feof(fptr))
{puts(fileLine);}
}
}
else
{printf("\nError opening file.\n");}
fclose(fptr);
getchar();
getchar();
return 0;
}
Let's start with the first bit.
I'm not sure about
Code:
while (!feof(fptr))
{
fgets(fileLine, 81, fptr);
if (!feof(fptr))
{puts(fileLine);}
What does while (!feof(fptr)) do exactly? I can see that it checks whether the end of the file as been reached.
Would (feof(fptr)) return 1 if the end of the file had been reached and 0 if the end of the file hadn't been reached?
If so how can it do that, (I thought) means, store the adress of FILE in fptr. It doesn't say much about the lengt of the file does it? (or does it store the end adress of the file too, so that it knows how long it is, as this is a special FILE-pointer?)
Thank You.
-
-
Indeed, it returns 0 if end of file is not reached and 1 otherwise.
How can it do that? It's true that you receive a FILE* pointer, but have you thought about what it points to?
-
>I can see that it checks whether the end of the file as been reached.
It does indeed.
>Would (feof(fptr)) return 1 if the end of the file had been
>reached and 0 if the end of the file hadn't been reached?
Close, it returns a non-zero value if the end of file has been reached. Or rather, true if the end of file has been reached and false otherwise, as C treats a non-zero value as true and a zero value as false.
> FILE * fptr;
>(I thought) means, store the adress of FILE in fptr.
FILE is an opaque type. Typically it's a structure that contains all kinds of information about a file so that the standard I/O functions can properly work with it and still tell you how things went. For example, here's one implementation for FILE:
Code:
struct _buffer {
HANDLE _fd; /* Character source for the buffer */
struct _deque _buf; /* Queue of buffered characters */
struct _deque _unget; /* Stack of pushed back characters */
char _peek; /* Unread but not yet buffered character */
unsigned long _flag; /* State of the buffer */
char *_tmp; /* The name of the file (if it's temporary) */
};
typedef struct _buffer FILE;
And feof might be implemented as such:
Code:
int feof ( FILE *stream )
{
return stream->_flag & _OPEN && stream->_flag & _EOF;
}
At the risk of confusing you with too much detail, the input functions will work with a buffer of characters. That buffer is filled up using system functions. For example, the rest of the library that works with the above FILE structure eventually gets down to this function for input:
Code:
/*
Return the 0 on success, non-zero on error or EOF
*/
int _intern_fill ( FILE *in )
{
const HANDLE fd = in->_fd;
const size_t size = in->_buf._size;
size_t read_size = size;
char *temp = NULL;
if ( ( temp = malloc ( read_size ) ) != NULL ) {
char *pread = temp;
size_t nread = 0;
/* "Read" any peeked characters first */
if ( in->_flag & _PEEK ) {
in->_flag &= ~_PEEK;
*temp = in->_peek;
pread = temp + 1;
--read_size;
}
/* Load the raw stream characters into our temporary buffer */
if ( ReadFile ( fd, pread, read_size, (LPDWORD)&nread, NULL ) != 0 ) {
if ( pread != temp ) {
/* We "read" a peeked character, so bump the nread count */
++nread;
}
if ( nread != 0 ) {
/* Prep the buffer for streaming */
char *buf = in->_buf._base;
size_t i = 0;
if ( in->_flag & _TEXT )
nread = _compact_newlines ( in, temp, nread );
/* Set up a new owned buffer if necessary */
if ( buf == NULL && in->_flag & _OWNED )
buf = malloc ( size );
if ( buf != NULL ) {
/* Reset the buffer for fresh loading */
_deque_init ( in->_buf, buf, size );
/* Load characters into the buffer */
while ( i < nread && i < size )
_deque_pushf ( in->_buf, temp[i++] );
}
else {
/* Allocation failed or a non-owned buffer was NULL */
in->_flag |= _ERR;
}
}
else {
/* The stream is good, but we hit end-of-file immediately */
in->_flag |= _EOF;
}
}
else
in->_flag |= _ERR;
}
else
in->_flag |= _ERR;
/* Don't forget to clean up the mess */
free ( temp );
return in->_flag & ( _ERR | _EOF );
}
Notice how it sets the flag field for errors and end-of-file. It's this flag that tells feof (and ferror) whether the stream is in an invalid state or not. The actual machinery is somewhat complicated by the buffering mechanism, but it all boils down to this: FILE is an opaque type that holds enough information necessary to work with streams. When you perform I/O on a stream, the C runtime makes calls to the system to do the actual work. The system functions give the C runtime enough information to pass back to you through the standard C interface, which completes the abstraction.
-
I thank you all for your explanations. Prelude, I think you must be really intelligent, but I'm sorry to say that your knowlege of C is a bit bigger than mine, and therefore I don't understand very much of your post. Thanks for your reply, it will probably be useful to somebody else.
Elysia, yes I have thought about that. I think it would be the location on the harddisk. Is this true?
-
As I mentioned, it's FILE struct pointer. It points to a struct of information somewhere in memory.
That's where it gets the information from.
-
>I don't understand very much of your post
That's okay, I didn't expect you to. If you understood everything in my post you wouldn't have asked your question in the first place. ;) I covered the extra detail because even though you may not understand it now, it'll be there for you in the future.
-
Okay. I think I have a slight understanding of its working now. I was actually going to ask how
Code:
fgets(fileLine, 81, fptr);
works too, but I think I'm just going to accept its working for now without knowing why or how.
-
Fgets reads the information from the pointer to the FILE struct you passed and can thus read information from the file opened and store it in your buffer.
-
>I was actually going to ask how fgets(fileLine, 81, fptr); works too
Okay, now I'm just being evil. You can ignore me, but this is how fgets and gets work:
Code:
char *gets ( char *s )
{
return _getline ( s, 0x80000000, stdin, 0 );
}
char *fgets ( char *s, int n, FILE *in )
{
return _getline ( s, n, in, 1 );
}
static char *_getline ( char *s, int n, FILE *in, int store_nl )
{
char *p = s;
int ch;
while ( --n > 0 ) {
ch = fgetc ( in );
if ( ch == EOF )
break;
else if ( ch == '\n' ) {
if ( store_nl )
*p++ = '\n';
break;
}
else
*p++ = (char)ch;
}
if ( p != s && !ferror ( in ) ) {
*p = '\0';
return s;
}
else
return NULL;
}