You don't have to mark my answer as accepted, just want to inspire people to write code so that it is readable and safe. Don't be lazy to write code like this where quality is a factor.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
struct student /* Magic numbers everywhere */
{
char first[30];
char last[30];
char ssn[9];
};
void* handle_nullptr_error (void* ptr, char *action, int code)
{
if(ptr == NULL)
{
fprintf(stderr, "Failed to %s\n", action);
exit(code);
}
printf("Succeeded to %s\n", action);
return ptr;
}
int handle_nonzero_error (int val, char *action, int code)
{
if(val != 0)
{
fprintf(stderr, "Failed to %s\n", action);
exit(code);
}
printf("Succeeded to %s\n", action);
return val;
}
int handle_negval_error (int val, char *action, int code)
{
if(val < 0)
{
fprintf(stderr, "Failed to %s\n", action);
exit(code);
}
printf("Succeeded to %s\n", action);
return val;
}
/** This function is not guaranteed to be portable and work (but it will at least fail properly),
* because not all systems and/or library implementations support `SEEK_END` in files
* opened in text mode, as specified by @mode
* Moreover, in binary mode it will behave in an undefined manner, because different systems
* may store files data completely differently. In most cases it will succeed, just don't
* write code that crashes if not.
*/
long int get_file_charcount (const char *filename, char* mode)
{
FILE* fp = NULL;
long int fpSize = 0L;
/* Alignment for complicated function calls (for e.g where functions are passed as arguments) */
fp = handle_nullptr_error (fopen(filename, mode), "open file.", 1);
(void)handle_nonzero_error (fseek(fp, 0, SEEK_END), "seek end position.", 2);
fpSize = handle_negval_error (ftell(fp), "tell position.", 3);
fclose(fp); /* - May fail, as well */
return fpSize;
}
/** This function depends on POSIX headers and it is unix-conformant, although there are still
* some exceptions.
*
* Note that the value returned is the length of the contents of the symbolic link,
* and does not count any trailing null pads. The value is ought to be system-specific.
*/
_off64_t get_file_size (const char *filename)
{
struct stat st = {0};
(void)handle_negval_error(stat(filename, &st), "get file size.", (-1));
return st.st_size;
}
/** A validation function should first determine whether file's size is
* actually dividable by `sizeof(struct STUDENT_DESCRIPTION);`.
*
* Further more you can use `get_file_size()` as an alternative to
* `get_file_charcount()`. In the latter case, make sure you to specify the
* appropriate mode, "r" for text files and "rb" for binary files.
*/
void make_arrays ()
{
long int size = get_file_charcount("myfile.txt", "r");
long int num_students = size / sizeof(struct STUDENT_DESCRIPTION);
printf("size of file: %ld\n", size);
printf("There are %ld students in the file", num_students);
}
int main (void)
{
make_arrays();
return EXIT_SUCCESS;
}
fopen,fseekfopen. Here every function can return error.fopenreference, especially about the difference between the"r"and"a"options, and what happens if the file doesn't exist. That should help you understand why using the append option make it seem to work.