Introduction
Excluding databases and files (a topic we'll cover today) there isn't really a good way to store data collected from a program--usually, this data is deleted after the program terminates.
Luckily, C gives us a way to read and write data to files through file pointers. This persistent data does not disappear once the program is finished.
If you're designing a game, you can keep track of a user's high score persistently in a file called scores.txt, for example.
This article will take a closer look at file pointers, and how you can manipulate and store data solely through C.
Understanding FILE and FILE*
In C, FILE is a data structure and FILE* is simply a pointer to that structure.
The only thing particularly special about file pointers is that they are parameters to nearly all functions that deal with manipulating files.
So where do file pointers come from?
The fopen( ) function helps us get these pointers:
fopen( <filename>, <mode> );
opens a file depending on the mode chosen
mode determines what can be done with the file
returns a file pointer
make sure the return value is not NULL
dereferencing a NULL pointer can lead to memory vulnerabilities or a Segmentation Fault
For instance:
#include <stdio.h>
int main(void)
{
// opens file in write mode
// pointer to file stored in flptr
FILE* flptr = fopen("scores.txt", "w");
// exits program if the file pointer was NULL
if (flptr == NULL)
fclose(flptr);
return 1;
}
*If you're interested, here are the different modes that can be passed to fopen( ):
"r" for read -- prepares file to be read (not modified)
"w" for write -- prepares file to be "cleared" and written over (deletes previous information)
"a" for append -- prepares file to have additional information added (appends to previous information)
The Other Functions...
All of these functions take a file pointer as a parameter!
fclose( <file pointer> ) | closes file pointed to, no operations can be performed on the file once closed |
fgetc( <file pointer> ) | reads + returns next character from file pointed to + requires "r" |
fputc( <char>, <file pointer> ) | writes / appends specified character to pointed-to file + requires "w" or "a" |
fread( <buffer>, <size of type (bytes)>, <qty>, <file pointer> ) | reads <qty> units of <size of type> from pointed-to file and stores them in buffer (a pointer) + requires "r" |
fwrite( <buffer>, <size of type (bytes)>, <qty>, <file pointer> ) | same as fread( ) but puts data from buffer to pointed-to file + requires "w" |
Duplicating Linux Commands and Function Applications
If you've worked with VSCode before, you might be familiar with Linux Commands that are like shortcuts for manipulating files.
We can "duplicate" some of these terminal commands using the functions we've learned about.
cat
FILE* ptr = fopen("file.txt", "r");
// prints out each character in a file until it reaches EOF (End of File)
char ch;
while ((ch = fgetc(ptr)) != EOF)
printf("%c\n", ch);
cp
FILE* ptr = fopen("file.txt", "r");
FILE* ptr2 = fopen("file2.txt", "w");
// copies / writes each character in file.txt to file2.txt
char ch;
while((ch = fgetc(ptr)) != EOF)
fputc(ch, ptr2);
Here is an example of using fread( ) and fwrite( ):
Final Thoughts
Hopefully this article has given you a bit of insight into data manipulation with files and file pointers. Thanks for reading!
Comments