[quote="krilo"][code:1]
fscanf(fpin, "%c", &c); if (fpin==EOF) return NULL;
[/code:1][/quote]
Ovo nikako ne može biti dobro. Naime, [tt]fpin[/tt] je argument funkcije, a znamo da se u C-u argumenti predaju funkciji [b]po vrijednosti[/b], što znači da poziv [tt]fscanf(fpin, "%c", &c);[/tt] ne može promijeniti vrijednost varijeble [tt]fpin[/tt]. Je li tako?
Ajmo sad malo na priču o tome što tebi ovdje zapravo nije jasno.
Koliko ja vidim, ti se ponašaš kao da je [tt]fpin[/tt] pointer na poziciju u datoteci koju čitaš i onda se čitanjem iz datoteke taj pointer pomiče po datoteci. Nažalost situacija nije tako jednostavna.
Ako malo promisliš, očito je da stvari ni ne mogu biti tako jednostavne. Naime, [tt]fpin[/tt] je tipa [tt]FILE*[/tt], odnosno [tt]fpin[/tt] je pointer na nešto što se zove [tt]FILE[/tt]. (Kasnije ćemo o tome što je to nešto). Pointeri su varijable čiju vrijendost interpretiramo kao adresu neke memorijske lokacije. S druge strane, datoteke ne žive u memoriji nego na hard disku, SSD-u, CD-u, DVD-u, Google Driveu, Dropboxu i tko zna gdje drugo, ali ne u memoriji. Prema tome, pointer [tt]fpin[/tt] koji pokazuje na nešto u memoriji nikako ne može pokazivati na poziciju u datoteci. Je li tako?
E, sad, na što [tt]fpin[/tt] zapravo pokazuje?
Priča je ne baš skroz trivijalna. Naime, programi nikada ne komuniciraju direktno s datotekama, nego to rade posredno, putem operativnog sustava. Svaki program se vrti u okviru nekog operativnog sustava (GNU/Linux, Windows, Mac OS, BSD, Android, iOS i sl.), te kada treba komunicirati s datotekama, onda program zamoli operativni sustav da otvori komunikacijski kanal prema željenoj datoteci.
Kada u C-u napišeš [tt]fopen("test.txt", "r")[/tt], rekla si svom programu da prilikom izvršavanja te linije koda kaže operativnom sustavu, [i]"Hej, OS, molim te da mi omogućiš čitanje iz datoteke [tt]test.txt[/tt]."[/i]. Ako može, OS će onda alocirati "uređaj" preko kojeg tvoj program može komunicirati s traženom datotekom. Taj "uređej za komunikaciju s datotekom" je struktura tipa [tt]FILE[/tt], a povratna vrijednost funkcije [tt]fopen[/tt] je pointer na tu strukturu.
E, dobro. A kako onda znamo kad smo na kraju datoteke?
Za to je dobro baciti oko na dokumentaciju funckije [tt]fscanf[/tt], gdje lijepo piše: [quote="[url=https://www-s.acm.illinois.edu/webmonkeys/book/c_guide/2.12.html#scanf]Documentation of [tt]fscanf[/tt][/url]"]On success the number of input fields converted and stored are returned. If an input failure occurred, then EOF is returned.[/quote]
Dakle, treba provjeravati povratnu vrijednost funcije [tt]fscanf[/tt]. Na primjer ovako: [code:1]if(fscanf(fpin, "%c", &c) != EOF) {
/* nesto smo procitali */
} else {
/* dosli smo do kraja datoteke */
}[/code:1]
Je li sad jasnije? Ako nije, pitaj! :)
Za znatiželjne: [b]kako izgleda struktura [tt]FILE[/tt]?[/b]
[spoiler]
U [tt]stdio.h[/tt] imamo (između ostalog) ove dvije linije: [code:1]#include <libio.h>
typedef struct _IO_FILE FILE;[/code:1]
Struktura [tt]_IO_FILE[/tt] definirana je u [tt]libio.h[/tt] na sljedeći način: [code:1]struct _IO_FILE {
int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags
/* The following pointers correspond to the C++ streambuf protocol. */
/* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
char* _IO_read_ptr; /* Current read pointer */
char* _IO_read_end; /* End of get area. */
char* _IO_read_base; /* Start of putback+get area. */
char* _IO_write_base; /* Start of put area. */
char* _IO_write_ptr; /* Current put pointer. */
char* _IO_write_end; /* End of put area. */
char* _IO_buf_base; /* Start of reserve area. */
char* _IO_buf_end; /* End of reserve area. */
/* The following fields are used to support backing up and undo. */
char *_IO_save_base; /* Pointer to start of non-current get area. */
char *_IO_backup_base; /* Pointer to first valid character of backup area */
char *_IO_save_end; /* Pointer to end of non-current get area. */
struct _IO_marker *_markers;
struct _IO_FILE *_chain;
int _fileno;
#if 0
int _blksize;
#else
int _flags2;
#endif
_IO_off_t _old_offset; /* This used to be _offset but it's too small. */
#define __HAVE_COLUMN /* temporary */
/* 1+column number of pbase(); 0 is unknown. */
unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];
/* char* _save_gptr; char* _save_egptr; */
_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};
struct _IO_FILE_complete
{
struct _IO_FILE _file;
#endif
#if defined _G_IO_IO_FILE_VERSION && _G_IO_IO_FILE_VERSION == 0x20001
_IO_off64_t _offset;
# if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
/* Wide character stream stuff. */
struct _IO_codecvt *_codecvt;
struct _IO_wide_data *_wide_data;
struct _IO_FILE *_freeres_list;
void *_freeres_buf;
size_t _freeres_size;
# else
void *__pad1;
void *__pad2;
void *__pad3;
void *__pad4;
size_t __pad5;
# endif
int _mode;
/* Make sure we don't get into trouble again. */
char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
#endif
};[/code:1]
[/spoiler]
krilo (napisa): | Kod: |
fscanf(fpin, "%c", &c); if (fpin==EOF) return NULL;
|
|
Ovo nikako ne može biti dobro. Naime, fpin je argument funkcije, a znamo da se u C-u argumenti predaju funkciji po vrijednosti, što znači da poziv fscanf(fpin, "%c", &c); ne može promijeniti vrijednost varijeble fpin. Je li tako?
Ajmo sad malo na priču o tome što tebi ovdje zapravo nije jasno.
Koliko ja vidim, ti se ponašaš kao da je fpin pointer na poziciju u datoteci koju čitaš i onda se čitanjem iz datoteke taj pointer pomiče po datoteci. Nažalost situacija nije tako jednostavna.
Ako malo promisliš, očito je da stvari ni ne mogu biti tako jednostavne. Naime, fpin je tipa FILE*, odnosno fpin je pointer na nešto što se zove FILE. (Kasnije ćemo o tome što je to nešto). Pointeri su varijable čiju vrijendost interpretiramo kao adresu neke memorijske lokacije. S druge strane, datoteke ne žive u memoriji nego na hard disku, SSD-u, CD-u, DVD-u, Google Driveu, Dropboxu i tko zna gdje drugo, ali ne u memoriji. Prema tome, pointer fpin koji pokazuje na nešto u memoriji nikako ne može pokazivati na poziciju u datoteci. Je li tako?
E, sad, na što fpin zapravo pokazuje?
Priča je ne baš skroz trivijalna. Naime, programi nikada ne komuniciraju direktno s datotekama, nego to rade posredno, putem operativnog sustava. Svaki program se vrti u okviru nekog operativnog sustava (GNU/Linux, Windows, Mac OS, BSD, Android, iOS i sl.), te kada treba komunicirati s datotekama, onda program zamoli operativni sustav da otvori komunikacijski kanal prema željenoj datoteci.
Kada u C-u napišeš fopen("test.txt", "r"), rekla si svom programu da prilikom izvršavanja te linije koda kaže operativnom sustavu, "Hej, OS, molim te da mi omogućiš čitanje iz datoteke test.txt.". Ako može, OS će onda alocirati "uređaj" preko kojeg tvoj program može komunicirati s traženom datotekom. Taj "uređej za komunikaciju s datotekom" je struktura tipa FILE, a povratna vrijednost funkcije fopen je pointer na tu strukturu.
E, dobro. A kako onda znamo kad smo na kraju datoteke?
Za to je dobro baciti oko na dokumentaciju funckije fscanf, gdje lijepo piše: Documentation of fscanf (napisa): | On success the number of input fields converted and stored are returned. If an input failure occurred, then EOF is returned. |
Dakle, treba provjeravati povratnu vrijednost funcije fscanf. Na primjer ovako: Kod: | if(fscanf(fpin, "%c", &c) != EOF) {
/* nesto smo procitali */
} else {
/* dosli smo do kraja datoteke */
} |
Je li sad jasnije? Ako nije, pitaj!
Za znatiželjne: kako izgleda struktura FILE?
Spoiler [hidden; click to show]: |
U stdio.h imamo (između ostalog) ove dvije linije: Kod: | #include <libio.h>
typedef struct _IO_FILE FILE; |
Struktura _IO_FILE definirana je u libio.h na sljedeći način: Kod: | struct _IO_FILE {
int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags
/* The following pointers correspond to the C++ streambuf protocol. */
/* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
char* _IO_read_ptr; /* Current read pointer */
char* _IO_read_end; /* End of get area. */
char* _IO_read_base; /* Start of putback+get area. */
char* _IO_write_base; /* Start of put area. */
char* _IO_write_ptr; /* Current put pointer. */
char* _IO_write_end; /* End of put area. */
char* _IO_buf_base; /* Start of reserve area. */
char* _IO_buf_end; /* End of reserve area. */
/* The following fields are used to support backing up and undo. */
char *_IO_save_base; /* Pointer to start of non-current get area. */
char *_IO_backup_base; /* Pointer to first valid character of backup area */
char *_IO_save_end; /* Pointer to end of non-current get area. */
struct _IO_marker *_markers;
struct _IO_FILE *_chain;
int _fileno;
#if 0
int _blksize;
#else
int _flags2;
#endif
_IO_off_t _old_offset; /* This used to be _offset but it's too small. */
#define __HAVE_COLUMN /* temporary */
/* 1+column number of pbase(); 0 is unknown. */
unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];
/* char* _save_gptr; char* _save_egptr; */
_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};
struct _IO_FILE_complete
{
struct _IO_FILE _file;
#endif
#if defined _G_IO_IO_FILE_VERSION && _G_IO_IO_FILE_VERSION == 0x20001
_IO_off64_t _offset;
# if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
/* Wide character stream stuff. */
struct _IO_codecvt *_codecvt;
struct _IO_wide_data *_wide_data;
struct _IO_FILE *_freeres_list;
void *_freeres_buf;
size_t _freeres_size;
# else
void *__pad1;
void *__pad2;
void *__pad3;
void *__pad4;
size_t __pad5;
# endif
int _mode;
/* Make sure we don't get into trouble again. */
char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
#endif
}; |
|
_________________ Extraordinary claims require extraordinary evidence. – Carl Sagan
|