I have two structs I am aiming to save to a binary file.
typedef struct {
int height;
int width;
int resistance_count;
Resistance** resistances; //contains a list of resistance*.
} Breadboard;
typedef struct {
int start_cell_col;
int end_cell_col;
int cell_row;
float resistance_value;
} Resistance;
I am somewhat unsure how I should be going about saving them. Since I need to keep track of the "resistance_count" variable to know how many resistances I will be saving, I have to save the breadboard first. To do that my attempt has been as follows:
bool save_breadboard(char* filename, Breadboard* bb_pointer) {
errno_t error_code;
FILE* fp_board;
/* Opens board.bin to save the board struct on. */
error_code = fopen_s(&fp_board, filename, "wb");
if (error_code != 0) {
return false;
}
size_t elements_written = fwrite(bb_pointer, sizeof(Breadboard), 1, fp_board);
if (elements_written == 0) {
return false;
}
fclose(fp_board);
return true;
}
With my current attempt I see a problem that I am also saving all the "Resistance**" which is perhaps unnecessary. I don't know if there is a way I could skip saving the resistance pointer pointers. But I don't think it will cause problem when I eventually read from it.
To save resistances I'm running into problems. Here is what I do:
bool save_resistances(char* filename, Breadboard* bb_pointer) {
errno_t error_code;
FILE* fp_resistances;
/* Opens resistances.bin to save the array of resistance pointers on. */
error_code = fopen_s(&fp_resistances, filename, "wb");
if (error_code != 0) {
return false;
}
size_t elements_written = fwrite(bb_pointer->resistances, sizeof(Resistance),
bb_pointer->resistance_count, fp_resistances);
if (elements_written == 0) {
return false;
}
fclose(fp_resistances);
return true;
}
I am pretty sure that I will be saving the resistance pointer this way. I cannot check with binary files, but if I am would dereferencing the resistance pointer help?
size_t elements_written = fwrite(*bb_pointer->resistances, sizeof(Resistance),
^ bb_pointer->resistance_count, fp_resistances);
Any help in helping me understand reading/writing to binary files would be much appreciated.
You are getting close to the solution. Just a couple of things missing...
With my current attempt I see a problem that I am also saving all the "Resistance**" which is perhaps unnecessary. I don't know if there is a way I could skip saving the resistance pointer pointers [...]
Yeah, it is unnecessary. Indeed when reading back you will have to discard it and overwrite it with a valid value. I wouldn't bother finding strange ways of skipping the pointer. I'd suggest writing out a NULL pointer instead to avoid mistakes when re-reading the data by doing something like:
void *tmp = bb_pointer->resistances;
bb_pointer->resistances = NULL;
size_t elements_written = fwrite(bb_pointer, sizeof(Breadboard), 1, fp_board);
bb_pointer->resistances = tmp;
Now, coming to the part where you actually save all your structures, this is wrong:
size_t elements_written = fwrite(bb_pointer->resistances, sizeof(Resistance),
bb_pointer->resistance_count, fp_resistances);
And doing *bb_pointer->resistances is also wrong. You want to save each Resistance struct, but your ->resistances is an array of pointers, so (1) saving the pointers (bb_pointer->resistances) is obviously wrong and (2) trying to save the structs as if they were contiguous in memory (*bb_pointer->resistances) is also wrong. The only thing you can do is loop over the array and dereference every single pointer, saving it separately:
for (int i = 0; i < bb_pointer->resistance_count; i++) {
if (fwrite(bb_pointer->resistances[i], sizeof(Resistance), 1, fp_resistances) != 1) {
// handle error
return false;
}
}
Finally, remember that fwrite returns the number of elements written which should always be equal to the requested number, so in general you need to check for errors with res != count, not with res == 0:
size_t elements_written = fwrite(bb_pointer, sizeof(Breadboard), 1, fp_board);
if (elements_written != 1) {
return false;
}
Related
I'm trying to save a struct into a .dat file and read it back in later.
struct myStruct{
char **one;
mytype **two;
mytype2 *three;
}
With an assigning function:
struct MyStruct get_struct() = {
char **pi = ...;
mytype **pa = ...;
mytype2 **po = ...;
MyStruct n = {pi, pa, po};
return n;
}
I originally tried to save this struct into a .dat file by doing this:
struct MyStruct s = get_struct();
myoutfile = fopen("file.dat", "w");
if (myoutfile == NULL) {
fprintf(stderr, "\nError opend file\n");
exit(1);
}
fwrite(&s, sizeof(struct MyStruct), 1, myoutfile);
fclose(myoutfile);
and read it back in with:
fread(&t, sizeof(struct MyStruct), 1, myinfile)
Now I learned, that this does not work (segmentation error), because I only save the location where the pointer points to, not the actual thing.
Now my question is, how can I do it properly? I have found some solutions for C++ but I need to stay in C.
EDIT:
Later on, I want to call a function which looks like this:
void work_with_struct(MyStruct s){
char ** xone = s.one;
mytype **xtwo = s.two;
mytype2 *xthree = s.three;
}
This post is related to this post, but as I could specify my mistake now, asking in a new post makes more sense to me.
As always in programming, you break up the task to smaller chunks, and break up smaller chunks to yet smaller chunks, until every chunk is easy.
int saveMyStruct (struct myStruct* myStruct, FILE* file) {
// what do I do here?!?!
// well it has three members
// so treat each one in sequence
int result;
result = saveStringArray(myStruct->one, file);
if (result >= 0)
result = saveMyTypeArray (myStruct->two, file);
if (result >= 0)
result = saveMyType (myStruct->three, file);
return result;
}
Note how the status is checked all the time. If you work with files, you need to check the status all the time.
What next? You need to write three functions mentioned above.
saveStringArray(char** stringArray, FILE* file)
{
// first save the length of the array, then save each individual string
int length = getStringArrayLength(stringArray);
int result = fwrite(&length, sizeof(length), 1, file);
if (result != 1)
return -1;
for (i = 0; i < length; ++i)
{
result = saveString(stringArray[i], file);
if (result < 0)
return -1;
}
return i;
}
And so on and so forth. I presume your array of pointers is NULL-terminated; if not, you need to have some other way to know its length.
Note how array length is always saved before array elements. This is because you will need to read your array later, and you will need to know where to stop. It will also be easy to allocate your array when you read it.
In C, I often want to handle data read from a file and data read from an array of strings the same way. Usually reading from a file is for production and from strings is for testing. I wind up writing a lot of code like this:
void handle_line(char *line, Things *things) {
...
}
Things *read_from_chars(char *lines[]) {
Things *things = Things_new();
for (int i = 0; lines[i] != NULL; i++) {
handle_line(lines[i], things);
}
return things;
}
Things *read_from_input(FILE *input) {
char *line = NULL;
size_t linelen = 0;
Things *things = Things_new();
while (getline(&line, &linelen, input) > 0) {
handle_line(line, things);
}
return things;
}
This is a duplication of effort.
Is there a way I can make an array of strings masquerade as a FILE * pointer? Or vice-versa? Or is there a better pattern for dealing with this problem?
For bonus points: the solution should make char * or char ** usable with the standard file functions like fgets and getline.
You could use a discriminated union that contains a FILE* and a pointer to the array, then write a get_next function that does the right thing with it.
typedef struct {
enum { is_file, is_array } type;
union {
FILE *file;
struct {
int index;
int size;
char **lines;
} array;
} data;
} file_or_array;
char *get_next(file_or_array foa) {
if (foa.type == is_file) {
char *line = NULL;
size_t linelen = 0;
getline(&line, &linelen, foa.data.file);
return line;
} else {
if (foa.data.array.index < foa.data.array.size) {
return strdup(foa.data.array.lines[foa.data.array.index++]);
} else {
return NULL;
}
}
}
The call to strdup() is necessary to make this work consistently. Since getline() returns a newly-allocated string, which the caller needs to free, it also does the same thing when returning a string from the array. Then the caller can safely free it in both cases.
There's a nonstandard function fmemopen that lets you open a char[] for reading or writing. It's available in most versions of GNU libc, I think, and most versions of Linux.
(This lets you read from or write to a single string, not the array of strings you asked about.)
One of the most powerful ways to handle this is via streams. I use them to hide file/string/serial ports etc
I have rolled my own stream library which I mainly use on embedded systems
the general idea is :-
typedef struct stream_s stream_t;
struct stream_s
{
BOOL (*write_n)(stream_t* stream, char* s, WORD n);
BOOL (*write_byte)(stream_t* stream, BYTE b);
BOOL (*can_write)(stream_t* stream);
BOOL (*can_read)(stream_t* stream);
BYTE (*read_byte)(stream_t* stream);
void* context;
};
then you make a whole bunch of functions
BOOL stream_create(stream_t* stream);
BOOL stream_write_n(stream_t* stream, char* s, WORD n);
BOOL stream_can_read(stream_t* stream);
BYTE stream_read_byte(stream_t* stream);
etc
that use those base function call backs.
the context in the stream struct you use to point to a struct for serial, string, file, or whatever you want. Then you have things like file_create_stream(stream_t* stream, char* filename) which will populate the callbacks on stream with the file related functions. Then for strings you have something similar but handles strings
There's more than one way to skin this particular cat, but in general the solution to this is hiding the implementation of the public interface behind an indirection which allows you to inject separate 'implementations'.
(This incarnation of your problem is also closely related to somewhat different problem of ensuring ABI compatibility between versions of code.)
To solve this in C you can do it similar to the pimpl with-inheritance in C++ (protected instead of private d-pointer, with overridden protected constructors):
You create an opaque 'reader'/'stream' object (pointer to forward declared struct w/ typedef in C) and suitably named constructor functions to instantiate the opaque object which inject the desired implementation.
Let's sketch out example header files to give you an idea of how the functions fit together. Let's start with the guts, the definition of the d-pointer/p-impl objects (N.B.: I'm omitting some boilerplate like header guards):
reader-private.h:
/* probably should be in its proper C file, but here for clarification */
struct FileReaderPrivateData {
FILE * fp;
};
/* probably should be in its proper C file, but here for clarification */
struct StringReaderPrivateData {
size_t nlines;
size_t cursor;
char ** lines;
};
/* in C we don't have inheritance, but we can 'fix' it using callbacks */
struct ReaderPrivate {
int (* close)(void* pData); /* impl callback */
ssize_t (* readLine)(void* pData, char** into); /* impl callback */
/* impl-specific data object, callbacks can type cast safely */
void * data;
};
/* works like a plain p-impl/d-pointer, delegates to the callbacks */
struct Reader {
struct ReaderPrivate * dPtr;
}
reader.h:
typedef struct Reader* Reader;
/* N.B.: buf would be a pointer to set to a newly allocated line buffer. */
ssize_t readLine(Reader r, char ** buf);
int close(Reader r);
file-reader.h
#include "reader.h"
Reader createFileReader(FILE * fp);
Reader createFileReader(const char* path);
string-reader.h
#include "reader.h"
Reader createStringReader(const char**, size_t nlines);
That's a general pattern for doing pimpl/d-pointer with inheritance in C, so you can abstract the implementation guts behind a public interface which is accessed through opaque pointers. This mechanism is generally useful to guarantee API and ABI compatibility between various implementations of the public interface and to implement a simple inheritance pattern.
Here's an implementation using fcookieopen [IIRC, BSD has something similar]:
// control for string list
struct cookie {
char **cook_list; // list of strings
int cook_maxcount; // maximum number of strings
int cook_curidx; // current index into cook_list
int cook_curoff; // current offset within item
};
int cookie_close(void *vp);
ssize_t cookie_read(void *vp,char *buf,size_t size);
cookie_io_functions_t cook_funcs = {
.read = cookie_open;
.close = cookie_close;
};
// cookie_open -- open stream
FILE *
cookie_open(char **strlist,int count,const char *mode)
// strlist -- list of strings
// count -- number of elements in strlist
// mode -- file open mode
{
cookie *cook;
FILE *stream;
cook = calloc(1,sizeof(cookie));
cook->cook_list = strlist;
cook->cook_maxcount = count;
stream = fopencookie(cook,mode,&cook_funcs);
return stream;
}
// cookie_close -- close stream
int
cookie_close(void *vp)
{
free(vp);
return 0;
}
// cookie_read -- read stream
ssize_t
cookie_read(void *vp,char *buf,size_t size)
{
cookie *cook = vp;
char *base;
ssize_t totcnt;
totcnt = 0;
while (size > 0) {
// bug out if all strings exhausted
if (cook->cook_curidx >= cook->cook_maxcount)
break;
base = cook->cook_list[cook->cook_curidx];
base += cook->cook_curoff;
// if at end of current string, start on the next one
if (*base == 0) {
cook->cook_curidx += 1;
cook->cook_curoff = 0;
continue;
}
// store character and bump buffer and count
*buf++ = *base;
size -= 1;
totcnt += 1;
cook->cook_curoff += 1;
}
return totcnt;
}
If you need this functionality just for debugging, write a fopen_strings(char *list[]) function to:
create a temporary file
open that with fopen with mode "r+"
write all your strings into it
delete the file (the FILE* can still operate on it, until it is closed either explicitly or implicitly at program end. You might need to skip this step on some operating systems that prevent deletion of open files.
rewind the stream
return the stream and let your program use it as it would a regular file.
is there a better pattern for dealing with this problem?
My proposed solution is to do function overloading.
Provide all possible parameters:
Things* readThings(FILE *f, char *l[])
{
char *line = NULL;
size_t linelen = 0;
Things *things = Things_new();
if (f)
{
while(getline(&line, &linelen, input) > 0)
handle_line(line, things);
}
else
{
for(int i = 0; lines[i] != NULL; i++)
handle_line(lines[i], things);
}
return things;
}
Things* readThingsChar(char *l[]){ return readThings(0, l); }
Things* readThingsFile(FILE *f){ return readThings(f, 0); }
How to use
FILE *f;
char *l[100];
..
Things *a = readThings(f,0); // or readThingsFile(f)
Things *b = readThings(0,l); // or readThingsChar(l)
You could embed it in the data:
Things* readThings(char *l[])
{
char *line = NULL;
size_t linelen = 0;
Things *things = Things_new();
FILE *f = NULL;
if (l[0][0]==UNIQUE_IDENTIFIER)
{
f = fopen(l[0]+1);
while(getline(&line, &linelen, input) > 0)
handle_line(line, things);
fclose(f);
}
else
{
for(int i = 0; lines[i] != NULL; i++)
handle_line(lines[i], things);
}
return things;
}
How to use
char *f[1] = { "_file.txt" };
char *l[100] = { "first line", .. "last line" };
f[0][0] = UNIQUE_IDENTIFIER;
Things *a = readThings(f);
Things *b = readThings(l);
I am getting a really strange error in my C program and therefore I need your help guys! So I have a recursive structure called path, where sometimes I store the address of the "parent" path in the structure field mother:
typedef struct path{
struct path* mother;
struct path** children;
int length;
uint8_t* inf;
} path;
So in my example I just generate one path like this:
int child_num=2;
int bytes=10;
path* my_path=malloc(sizeof(path));
if (path==NULL) throw error...
my_path->inf=malloc(sizeof(uint8_t)*bytes);
memset(my_path->inf, 4, bytes);
my_path->children=malloc(sizeof(path*)*child_num);
for(int i=0; i<child_num; i++){
my_path->children[i]->mother=my_path;
my_path->children[i]->inf=malloc(sizeof(uint8_t)*bytes);
memset(my_path->children[i]->inf, 5, bytes);
}
So now since I stored the link to the parent structure, I want to use another helping pointer to get access to its information:
path* my_pointer=my_path->children[0]->mother; //this is just for the example
So i checked the addresses and everything seems to be alright, but if I know use the pointer in another method, pointing to the field "inf", it works if I use the variable "path" so:
method(path->inf, bytes);
it is fine, but as soon as I do:
method(my_pointer->inf, bytes);
the method crashes at the marked line:
void method(uint8_t* element, int bytes) {
if (element==NULL) ... //<=== here it crashes
//do something
}
I really dont get what I am doing wrong, I printed the addresses and everything seems to be good, even if I access a certain byte over the variable "my_pointer", so like
my_pointer->inf[1]
it returns me the corresponding value, but in the separate method it doesnt work.
Like the comments indicate we can't exactly answer your question with the information provided, but we can point you in the right direction.
First, I noticed in your examples that you're using path as a variable name to a typedef'd path structure. You need to either be more verbose with your variable names or actually copy paste some code to make sure that we can look at the actual problem, because it could simply be an issue with naming.
All in all I think it would do you a world of good to employ a bit of code hygiene. Organize some of the functions you use for data structure overhead at file scope:
static int path_alloc(path* p);
static int path_alloc_kids(path* p, int num);
static int path_alloc(path* p) {
if(p == NULL) { return -1; }
p = (path*)malloc(sizeof(path));
if(p == NULL) { return -2; }
return 0;
}
static int path_alloc_kids(path* p, int num) {
if(p == NULL || num <= 0) { return -1; }
if(!path_alloc(p)) { /* Easier to read and understand, no error handling here to muddle things up */
/* You don't actually need a path**, do you? Think of char *argv[] a.k.a. char **argv, is that what you're actually going for? */
p->children = (path*)malloc(sizeof(path) * num);
if(p->children == NULL) { return -2; }
p->length = num;
} else { return -1; } /* Simple */
return 0;
}
This makes it a LOT easier to understand your code, which is the main issue with pointers. Add in some methods to free the allocated children and roots and you're set to use this path structure in a relatively abstracted way. You may want to consider using a path and a path_node in a linked-list fashion, that way you only allocate what you need.
struct spath_node; /* So it knows of itself */
typedef struct spath_node {
struct spath_node *parent;
struct spath_node *next;
uint8_t *data;
int data_size;
} path_node;
Then allocate by passing in a data size and parent, a NULL parent could mean it's a root node.
static int path_alloc_node(path_node *parent, int data_size, uint8_t *data);
This makes for relatively slow insert/traversal, but easier to understand where you went wrong.
EDIT: To be clear, this is how we would add children to the linked-list example:
static int path_alloc_node(path_node *parent, int data_size, uint8_t *data) {
path_node *tmp;
if(parent == NULL || data_size <= 0) { return -1; }
if(parent->next != NULL) { return -3; }
tmp = (path_node*)malloc(sizeof(path_node));
if(tmp == NULL) { return -2; }
else parent->next = tmp;
if(data == NULL) { /* Assume the caller is requesting a new data block of the given size */
data = (uint8_t*)malloc((size_t)data_size);
if(data == NULL) { return -2; }
}
parent->next->data = data;
parent->next->data_size = data_size;
parent->next->next = NULL;
parent->next->parent = parent;
return 0;
}
I'm trying to make a simple database program, but when I get to this line
int idSearch(product* itens, int id) {
int i = 0;
for(i; i < size; i++) {
if(itens[i].id == id) //<=== This line
return i;
}
return ITEM_NOT_FOUND;
}
the program stops responding.
size is set as a global variable in the begining of the program
FILE* flog;
FILE* db;
FILE* sizef;
int size = 100;
this function is called by
void newProduct(product* itens, char name[64], int id, float price) {
int pos = idSearch(itens, 0);
if(idSearch(itens, id) != ITEM_NOT_FOUND) {
printf("Erro, o produto ja existe");
return;
}...
items is defined as
itens = (product*) calloc(sizeof(product), size);
and product is a struct defined as such
typedef struct{
char name[64];
int id;
float price;
int amount;
} product;
Firstly I thought the problem was that I was not using the -> operator, but when I tried the compiler says its not right.
I'm using Code::Blocks with GCC compiler on a Windows 7 x64
**EDIT: the whole code can be found here: http://hastebin.com/atulajubar.tex
Hope to hear answers soon, Thanks in advance
**EDIT: You're calling calloc() wrong. The signature is: void *calloc(size_t nelem, size_t elsize);
You're giving it the size first, then the number of elements. Switch that around and see if your problem is resolved.
Also, when calling (AFTER THE FIX:) itens = (product*) calloc( size, sizeof(product) );,
it's important to check to see that itens is not NULL after doing this. If calloc isn't able to give you back the right amount of memory, it returns a NULL pointer I believe. Check this, because if you're getting NULL back, that's your issue.
One good, easy, portable way of checking that would be:
if(!itens){
fprintf(stderr, "Error! Could not allocate memory!\n");
exit(1);
}
Also, as WhozCraig suggested, please make sure your code contains #include <stdlib.h>, a requirement of calloc() as per its man page.
This is wrong:
if((db = fopen(DB_PATH, RB))==NULL)
{
if((db = fopen(DB_PATH, RWB))==NULL)
{
exit(1);
}
else
{
itens = (product*) calloc(sizeof(product), size);
fwrite(itens, sizeof(product), size, db);
rewind(db);
}
}
fread(itens, sizeof(product), size, db);
If you have a DB_PATH file in the current working directory the first fopen() will succeed and the items allocation will never take place. Only if the file is not found, but is then successfully created will items contain a valid allocation, assuming calloc worked.
That else condition should be removed:
// note calloc parameter order addressed.
itens = calloc(size, sizeof(product));
if (itens == NULL)
{
perror("Failed to allocate items.");
exit(EXIT_FAILURE);
}
if((db = fopen(DB_PATH, RB))==NULL)
{
if((db = fopen(DB_PATH, RWB))==NULL)
exit(EXIT_FAILURE);
fwrite(itens, sizeof(product), size, db);
rewind(db);
}
fread(itens, sizeof(product), size, db);
There is a significant amount of error checking left to handle, but this needs to be addressed regardless.
I am having trouble with a struct array. I need to read in a text file line by line, and compare the values side by side. For example "Mama" would return 2 ma , 1 am because you have ma- am- ma. I have a struct:
typedef struct{
char first, second;
int count;
} pair;
I need to create an array of structs for the entire string, and then compare those structs. We also were introduced to memory allocation so we have to do it for any size file. That is where my trouble is really coming in. How do I reallocate the memory properly for an array of structs? This is my main as of now (doesn't compile, has errors obviously having trouble with this).
int main(int argc, char *argv[]){
//allocate memory for struct
pair *p = (pair*) malloc(sizeof(pair));
//if memory allocated
if(p != NULL){
//Attempt to open io files
for(int i = 1; i<= argc; i++){
FILE * fileIn = fopen(argv[i],"r");
if(fileIn != NULL){
//Read in file to string
char lineString[137];
while(fgets(lineString,137,fileIn) != NULL){
//Need to reallocate here, sizeof returning error on following line
//having trouble seeing how much memory I need
pair *realloc(pair *p, sizeof(pair)+strlen(linestring));
int structPos = 0;
for(i = 0; i<strlen(lineString)-1; i++){
for(int j = 1; j<strlen(lineSTring);j++){
p[structPos]->first = lineString[i];
p[structPos]->last = lineString[j];
structPos++;
}
}
}
}
}
}
else{
printf("pair pointer length is null\n");
}
}
I am happy to change things around obviously if there is a better method for this. I HAVE to use the above struct, have to have an array of structs, and have to work with memory allocation. Those are the only restrictions.
Allocating memory for an array of struct is as simple as allocating for one struct:
pair *array = malloc(sizeof(pair) * count);
Then you can access each item by subscribing "array":
array[0] => first item
array[1] => second item
etc
Regarding the realloc part, instead of:
pair *realloc(pair *p, sizeof(pair)+strlen(linestring));
(which is not syntactically valid, looks like a mix of realloc function prototype and its invocation at the same time), you should use:
p=realloc(p,[new size]);
In fact, you should use a different variable to store the result of realloc, since in case of memory allocation failure, it would return NULL while still leaving the already allocated memory (and then you would have lost its position in memory). But on most Unix systems, when doing casual processing (not some heavy duty task), reaching the point where malloc/realloc returns NULL is somehow a rare case (you must have exhausted all virtual free memory). Still it's better to write:
pair*newp=realloc(p,[new size]);
if(newp != NULL) p=newp;
else { ... last resort error handling, screaming for help ... }
So if I get this right you're counting how many times pairs of characters occur? Why all the mucking about with nested loops and using that pair struct when you can just keep a frequency table in a 64KB array, which is much simpler and orders of magnitude faster.
Here's roughly what I would do (SPOILER ALERT: especially if this is homework, please don't just copy/paste):
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
void count_frequencies(size_t* freq_tbl, FILE* pFile)
{
int first, second;
first = fgetc(pFile);
while( (second = fgetc(pFile)) != EOF)
{
/* Only consider printable characters */
if(isprint(first) && isprint(second))
++freq_tbl[(first << 8) | second];
/* Proceed to next character */
first = second;
}
}
int main(int argc, char*argv[])
{
size_t* freq_tbl = calloc(1 << 16, sizeof(size_t));;
FILE* pFile;
size_t i;
/* Handle some I/O errors */
if(argc < 2)
{
perror ("No file given");
return EXIT_FAILURE;
}
if(! (pFile = fopen(argv[1],"r")))
{
perror ("Error opening file");
return EXIT_FAILURE;
}
if(feof(pFile))
{
perror ("Empty file");
return EXIT_FAILURE;
}
count_frequencies(freq_tbl, pFile);
/* Print frequencies */
for(i = 0; i <= 0xffff; ++i)
if(freq_tbl[i] > 0)
printf("%c%c : %d\n", (char) (i >> 8), (char) (i & 0xff), freq_tbl[i]);
free(freq_tbl);
return EXIT_SUCCESS;
}
Sorry for the bit operations and hex notation. I just happen to like them in such a context of char tables, but they can be replaced with multiplications and additions, etc for clarity.