correct use of single/double pointers in C - c

I am doing a university project where i want to read lines from a file and store them in an array of Records, (and later sort them) each record is a struct as follows:
typedef struct Record{
int id;
char* string_field;
int int_field;
double double_field;
} Record;
The size of the array is unknown. Initially im allocating a portion in memory as follows and calling a function to load the Records from file in my Records Array, and then reallocating (in the load_array() function) whenever i need more space:
int main(int argc, char const *argv[]){
if(argc < 2){
printf("Usage: ordered_array_main <file_name>\n");
exit(EXIT_FAILURE);
}
int capacity = 2;
Record* array_of_records = NULL;
array_of_records = (Record*)malloc(capacity * sizeof(Record));
int size = load_array(argv[1], array_of_records, capacity);//size_of_array
printf("%d, %d\n", (*array_of_records).id, (*array_of_records).int_field);
//printing here shows me random garbage values.
free(array_of_records);
return 0;
}
The load_array function is as follows, i will skip the part where i do my fopen() and strtok() stuff since its doesnt matter to the issue. I am reading each line and saving 4 variables (id, int_field, string_field, float_field) which then will be stored in each field of the current Record of my Records array.
The issue is that when i print the values of my record array field in the load_array() function they are the correctly read ones from the file, but when i go to print them in the main() they are garbage values, typical C style.
I noticed by printing the array_of_records pointer value at different locations that it changes where i do the realloc(), but as far as i know i dont think i made any mistakes here, realloc is returning me the new location of memory and im storing it in tmp, and then storing tmp in array_of_records.
int load_array(const char* file_name, Record* array_of_records, int capacity){
int index_of_record = 0;
while(fgets(buffer,buf_size,fp)!=NULL){
int id_field = atoi(field[0]);
char *string_field = malloc((strlen(field[1])+1)* sizeof(char));
strcpy(string_field, field[1]);
int int_field = atoi(field[2]);
double double_field = atof(field[3]);
if(index_of_record>=capacity){
Record* tmp = NULL;
tmp = (Record*)realloc(array_of_records,2*capacity*sizeof(Record));
if(tmp==NULL){
fprintf(stderr, "Memory allocation failure\n");
exit(EXIT_FAILURE);
}
array_of_records = tmp;
capacity = 2*capacity;
}
(array_of_records+index_of_record)->id = id_field;
(array_of_records+index_of_record)->string_field = string_field;
(array_of_records+index_of_record)->int_field = int_field;
(array_of_records+index_of_record)->double_field = double_field;
printf("%d\n", (array_of_records+index_of_record)->int_field);
//printing here shows me the correct values
index_of_record++;
free(string_field);
}
return index_of_record;
}
I cant wrap my head around this issue, it seems that i am passing correctly the pointer of the Record array, and then storing each record moving fowards with index_of_record. I am clueless. Maybe i am supposed to use double pointers?

Related

C Programming: Reading data from a file, dynamically allocating memory, placing contents in struct array

This is my very first post on stackoverflow. I am a CS student learning C, and I am having some issues with the problem I'm working on. Additionally, I should mention that I know very little, so if anything I put here comes off as foolish or ignorant, it is absolutely not my intention
I am aware that there are other posts similar to this one, however so far I feel that I have tried making a lot of amendments that all end with the same result.
I am given a text file in which each line contains studentName(tab)gpa. The total size of the file is unknown, this I must use dynamic memory allocation.
Example of text file format
Jordan 4.0
Bhupesh 2.51
General steps for program
Many details will be left out to save myself from embarrassment, however I will give a high-level overview of the process I am struggling with:
1.) Create dynamic memory array to hold struct for each line
2.) Start looping through file
3.) check the current size of the array to see if reallocation is necessary
4.) Create dynamic array to hold name
5.) Place name and gpa into struct
6.) rinse & repeat
Finally, one last thing. The error occurs when my initial allocated memory limit is reached and the program attempts to reallocate more memory from the heap.
Screenshot of error being thrown in clion debugger
My code is shown below:
#define EXIT_CODE_FAIL 1
#define ROW_COUNT 10
#define BUFFER_SIZE 255
#define VALID_ARG_COUNT 2
struct Student {
float gpa;
char * name;
};
// read the file, pack contents into struct array
struct Student * readFileContents(char *filename, int *rowCounter) {
// setup for loop
int maxDataSize = ROW_COUNT;
float currentStudentGpa = 0;
char studentNameBuffer[BUFFER_SIZE];
// initial structArray pre-loop
struct Student * structArray = calloc(maxDataSize, sizeof(*structArray));
FILE *pFile = fopen(filename, "r");
validateOpenFile(pFile);
// loop through, get contents, of eaach line, place them in struct
while (fscanf(pFile, "%s\t%f", studentNameBuffer, &currentStudentGpa) > 0) {
structArray = checkArraySizeIncrease(*rowCounter, &maxDataSize, &structArray);
structArray->name = trimStringFromBuffer(studentNameBuffer);
structArray->gpa = currentStudentGpa;
(*rowCounter)++, structArray++;
}
fclose(pFile);
return structArray;
}
// resize array if needed
struct Student * checkArraySizeIncrease(int rowCount, int * maxDataSize, struct Student ** structArray) {
if (rowCount == *maxDataSize) {
*maxDataSize += ROW_COUNT;
**// line below is where the error occurs**
struct Student * newStructArray = realloc(*structArray, *maxDataSize * sizeof(*newStructArray));
validateMalloc(newStructArray);
return newStructArray;
}
return *structArray;
}
// resize string from initial data buffer
char *trimStringFromBuffer(char *dataBuffer) {
char *string = (char *) calloc(strlen(dataBuffer), sizeof(char));
validateMalloc(string);
strcpy(string, dataBuffer);
return string;
}
Once again, I apologize if similar questions have been asked, but please know I have tried most of the recommendations that I have found on stack overflow with no success (of which I'm well aware is the result of my poor programming skill level in C).
I will now promptly prepare myself for my obligatory "first post on stackoverflow" roasting. Cheers!
You are reusing structArray as both the base of the array and a pointer to the current element. This won't work. We need two variables.
There are a number of "loose" variables related to the dynamic array. It's cleaner to define a struct (e.g. dynarr_t below) to contain them and pass just the struct pointer around.
When you're duplicating the string, you must allocate strlen + 1 [not just strlen]. But, the entire function does what strdup already does.
I tried to save as much as possible, but I've had to refactor the code a fair bit to incorporate all the necessary changes.
By passing sizeof(*structArray) to the arrnew function, this allows the struct to be used for arbitrary size array elements.
Anyway, here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define sysfault(_fmt...) \
do { \
printf(_fmt); \
exit(1); \
} while (0)
#define EXIT_CODE_FAIL 1
#define ROW_COUNT 10
#define BUFFER_SIZE 255
#define VALID_ARG_COUNT 2
struct Student {
float gpa;
char *name;
};
// general dynamic array control
typedef struct {
void *base; // base address
size_t size; // bytes in array element
size_t count; // current number of used entries
size_t max; // maximum number of entries
size_t grow; // number of entries to grow
} dynarr_t;
// arrfind -- return pointer to array element
void *
arrfind(dynarr_t *arr,size_t idx)
{
void *ptr;
ptr = arr->base;
idx *= arr->size;
ptr += idx;
return ptr;
}
// arrnew -- create new array control
dynarr_t *
arrnew(size_t siz,size_t grow)
// siz -- sizeof of array element
// grow -- number of elements to grow
{
dynarr_t *arr;
arr = calloc(1,sizeof(*arr));
if (arr == NULL)
sysfault("arrnew: calloc fail -- %s\n",strerror(errno));
arr->size = siz;
arr->grow = grow;
return arr;
}
// arrgrow -- grow array [if necessary]
// RETURNS: pointer to element to fill
void *
arrgrow(dynarr_t *arr)
{
void *ptr;
// grow array if necessary
// NOTE: use of a separate "max" from "count" reduces the number of realloc
// calls
if (arr->count >= arr->max) {
arr->max += arr->grow;
arr->base = realloc(arr->base,arr->size * arr->max);
if (arr->base == NULL)
sysfault("arrgrow: realloc failure -- %s\n",strerror(errno));
}
// point to current element
ptr = arrfind(arr,arr->count);
// advance count of elements
++arr->count;
return ptr;
}
// arrtrim -- trim array to actual number of elements used
void
arrtrim(dynarr_t *arr)
{
arr->base = realloc(arr->base,arr->size * arr->count);
if (arr->base == NULL)
sysfault("arrtrim: realloc failure -- %s\n",strerror(errno));
arr->max = arr->count;
}
void
validateMalloc(void *ptr)
{
if (ptr == NULL) {
perror("validateMalloc");
exit(1);
}
}
void
validateOpenFile(FILE *ptr)
{
if (ptr == NULL) {
perror("validateOpenFile");
exit(1);
}
}
// resize string from initial data buffer
char *
trimStringFromBuffer(char *dataBuffer)
{
#if 0
#if 0
char *string = calloc(1,strlen(dataBuffer));
#else
char *string = calloc(1,strlen(dataBuffer) + 1);
#endif
validateMalloc(string);
strcpy(string, dataBuffer);
#else
char *string = strdup(dataBuffer);
validateMalloc(string);
#endif
return string;
}
// read the file, pack contents into struct array
dynarr_t *
readFileContents(char *filename)
{
dynarr_t *arr;
// setup for loop
float currentStudentGpa = 0;
char studentNameBuffer[BUFFER_SIZE];
struct Student *structArray;
arr = arrnew(sizeof(*structArray),10);
FILE *pFile = fopen(filename, "r");
validateOpenFile(pFile);
// loop through, get contents, of eaach line, place them in struct
while (fscanf(pFile, "%s\t%f", studentNameBuffer, &currentStudentGpa) > 0) {
structArray = arrgrow(arr);
structArray->name = trimStringFromBuffer(studentNameBuffer);
structArray->gpa = currentStudentGpa;
}
fclose(pFile);
arrtrim(arr);
return arr;
}
I think your issue is with the calculation of the size of the realloc. Rather than using sizeof(*newStructArray), shouldn't you really be using the size of your pointer type? I would have written this as realloc(*structArray, *maxDataSize * sizeof(struct Student *))
There's a lot of other stuff in here I would never do - passing all those variables in to checkArraySizeIncrease as pointers is generally a bad idea because it can mask the fact that things are getting changed, for instance.
There is an issue in allocation of the buffer for string
char *string = (char *) calloc(strlen(dataBuffer), sizeof(char));
it should be:
char *string = (char *) calloc(1 + strlen(dataBuffer), sizeof(char));
as C-strings require extra 0-byte at the end.
Without it, the following operation:
strcpy(string, dataBuffer);
may damage data after the buffer, likely messing malloc() metadata.

c Struct Array, Storing string and its occurrence and writing it to a file

so I'm having a little problem with my struct array not doing what its supposed to. I get no compiler warnings or errors when building the program.
int Array_Size=0;;
int Array_Index=0;
FILE *Writer;
struct WordElement
{
int Count;
char Word[50];
};
struct WordElement *StructPointer; //just a pointer to a structure
int Create_Array(int Size){
StructPointer = (struct WordElement *) malloc(Size * sizeof(StructPointer));
Array_Size = Size;
return 0;
}
int Add_To_Array(char Word[50]){
int Word_Found=0;
for(int i=0; i <= Array_Size && Word_Found!=1; i++)
{
if(strcmp(StructPointer[i].Word, Word)) // This should only run if the word exists in struct array
{
StructPointer[i].Count++;
Word_Found=1;
}
}
if(Word_Found==0) // if the above if statement doesnt evualate, this should run
{
strcpy(StructPointer[Array_Index].Word, Word); //copying the word passed by the main function to the struct array at a specific index
printf("WORD: %s\n", StructPointer[Array_Index].Word); // printing it just to make sure it got copied correctly
Array_Index++;
}
return 0;
}
int Print_All(char File_Name[50])
{
Writer = fopen(File_Name, "w");
printf("Printing starts now: \n");
for(int i=0; i < Array_Size; i++)
{
fprintf(Writer, "%s\t\t%d\n",StructPointer[i].Word, StructPointer[i].Count);
}
free(StructPointer);
return 0;
}
These functions get called from a different file, The Add_To_Array is called when the program reads a new word form the text file. That function is supposed to check if the word already exists in the struct array and if it does, it should just increment the counter. If it doesn't, then it adds it.
The Print_All function is called after all the words have been stored in the struct array. Its supposed to loop through them and print each word and their occurrence. In the text file, there are 2 of every words but my program outputs:
this 13762753
document -1772785369
contains 1129268256
two 6619253
of 5701679
every 5570645
word 3342389
doccontains 5374021
I don't know what to make of this as im really new to C programming... It's probably worth mentioning the if(Word_Foun==0) doesn't execute
StructPointer = malloc(Size * sizeof(*StructPointer));
This will be the correct allocation. Otherwise you will have erroneous behavior in your code. Also check the return value of malloc.
StructPointer = malloc(Size * sizeof(*StructPointer));
if(NULL == StructPointer){
perror("malloc failure");
exit(EXIT_FAILURE);
}
You are allocating for struct WordElement not a for a pointer to it. You already have a pointer to struct WordElement all that you needed was memory for a struct WordElement.
Also in the loop you are accessing array index out of bound
for(int i=0; i <= Array_Size && Word_Found!=1; i++)
^^^
It will be i < Array_Size.
In case match occurs you want to set the variable Word_found to 1.
if(strcmp(StructPointer[i].Word, Word) == 0){
/* it macthed */
}
Also Writer = fopen(File_Name, "w"); you should check the return value of fopen.
if(Writer == NULL){
fprintf(stderr,"Error in file opening");
exit(EXIT_FAILURE);
}
Also when you are increasing the Array_index place a check whether it might access the array index out of bound.
The more global variable you use for achieving a small task would make it more difficult to track down a bug. It is always problematic because the places from which data might change is scattered - making it difficult to manage.

Modify and print typedef'd array in C

I am learning to work with structures and this doubt come to me when doing one exercise with C.
I have this code:
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#define MAX_STRING 256
#define MAX_CHILD 2000
#define MAX_GIFTS 20
#define MAX_LINE 1024
typedef char String[MAX_STRING];
typedef char Line[MAX_LINE];
typedef struct {
String child_name;
int grade; //integer between 0 and 5
String gift_name;
int price; //price of the gift
} Data;
typedef struct {
String name;
int price;
bool received; //true if the child will get this gift
} Gift;
typedef Gift Gifts[MAX_CHILD];
typedef struct{
String name;
int grade;
Gifts asked; //gifts the child asked for
int n_asked;
} Child;
typedef Child Children[MAX_CHILD];
Data make_data (String line){
Data d;
sscanf(line,"%s %d %s %d", d.child_name, &d.grade, d.gift_name, &d.price);
return d;
}
Child make_child(Data d) {
Child c;
strcpy(c.name, d.child_name);
c.grade = d.grade;
c.n_asked = 0;
return c;
}
Gift make_gift(Data d){
Gift g;
strcpy(g.name, d.gift_name);
g.price = d.price;
g.received = false;
return g;
}
int process(char file_name[]){
Line line;
FILE *f = fopen(file_name, "r");
while(fgets(line, MAX_LINE, f) != NULL){
make_data(line);
}
int fclose (FILE *f);
}
int main(){
process("data.txt");
return 0;
}
So this program receives a file text of this format:
John 4 Bike 200
Alice 3 Computer 800
Alice 3 Candy 10
Mike 5 Skate 100
and constructs the data in the function process.
The problem is, I want to store all the children in the array Children[ ] and to print it( print all the array or just something similar to Children[0], Children[1],etc). I have tried some ways but no success...as the array is of type Children and not char*. Even when I just do Children cs; I get segmentation fault. Is there a way I can accomplish this?
And my second question is, initially I had #define MAX_CHILD 20000 and when I tried to compile I got an error saying "size of array ‘Children’ is too large". Why does this happen? I see it doesn't happen to Gifts, but happens to Children because the struct Child has a Gifts type as on the members, which means it requires more space.
Any help appreciated.
the use of the typedef's (and so on)
instead of just writing the code out where it is needed
is unneeded (and distracting) and mis-leading and
makes the code much more difficult to follow.
This function:
Data make_data (String line)
{
Data d;
sscanf(line,"%s %d %s %d", d.child_name, &d.grade, d.gift_name, &d.price);
return d;
}
has several problems:
1) the parameter list will cause the compiler to 'set aside' enough room
for the String struct,
invoke a memcpy() to copy the String struct
to that 'set aside' memory from the callers' memory
Then copy the 'set aside' memory to the called functions' stack
That 'set aside' memory will never be used for anything else
The stack will be cluttered with the contents of the String struct
until the function returns
such activity is a real 'bear' to debug
2) the returned value from sscanf() needs to be checked
to assure that all 4 conversion operations were successful
3) the function return is a instance of the Data struct.
This will cause the compiler to 'set aside' enough room
for the Data struct.
that 'set aside' memory will never be used for anything else
invoke a memcpy() to copy the Data struct from the stack
to the 'set aside' memory
then perform the return from the function
then the compiler will cause the caller to
invoke memcpy() to copy the Data struct
from the 'set aside' memory to the caller's Data struct area.
such activity is a real 'bear' to debug.
The function should be written more like this:
int make_data (String *pLine, Data* pData)
{
int returnValue = 1; // initialize to indicate function successful
if( 4 != sscanf(pLine," %s %d %s %d",
pData->child_name,
&pData->grade,
pData->gift_name,
&pData->price) )
{ // then sscanf failed
perror( "sscanf failed for Line" );
returnValue = 0; // indicate to caller that function failed
} // end if
return( returnValue );
} // end function: make_data
and the caller(s) of this function should be adjusted accordingly
the make_gift() function has the same passed parameter
and returned parameter problems.
The problem is, I want to store all the children in the array
Children[ ] and to print it( print all the array or just something
similar to Children[0], Children[1],etc).
to store:
static Children cs;
size_t nc = 0; // number of children
while (fgets(line, MAX_LINE, f))
{
#include <search.h>
Data d = make_data(line);
Child c = make_child(d);
Child *cp = lsearch(&c, cs, &nc, sizeof c, (int (*)())strcmp);
cp->asked[cp->n_asked++] = make_gift(d);
}
to print:
int i, j;
for (i = 0; i < nc; ++i)
{
printf("%s (grade %d) asked for %d:\n",
cs[i].name, cs[i].grade, cs[i].n_asked);
for (j = 0; j < cs[i].n_asked; ++j)
printf("\t%s\t%d\n", cs[i].asked[j].name, cs[i].asked[j].price);
}
(We cannot simply print an aggregate type object - we have to print the individual elements.)

Adding a struct to an array using a pointer

I am fairly new to the C language and allocating memory/using pointers in general. Anyway, I was experimenting with reading a file, putting those values in a struct, etc. I know exactly what I want to do and of course the program runs but the output is incorrect and some kind of jumbled numbers and letters.
There is a text file with new information for each line. Each line represents one object.
This is how a line in the file might look:
meat sirloin 6.55 8 8.50 4
Overall I want to be able to store all of my PRODUCT objects in an array (so I have an array of structs). So I attempted to allocate memory with a pointer, use a line count, and then send the pointer to a function called read. In read I add each struct to the array via a pointer. The program doesn't crash, the output is just not correct and I have no clue why not. It's prob something with pointers. If anyone could help me I would really appreciate it. Any help at all would be great.
//prototype
void read(pointerToArr);
typedef struct
{
char supType[15];
char prodName[15];
double wholePrice;
int quantWhole;
double retPrice;
int retProdQuantity;
}PRODUCT;
FILE *fr;
int lineCount = 0;
int main()
{
PRODUCT *ptr;
int i;
char check[50];
fr = fopen("ttt.txt", "r");
while(fgets(check, sizeof(check), fr)!= NULL)
{
if(check[0] != '\n')
{
lineCount++;
}
}
// allocate memory for array based on line count.
PRODUCT prodContainter[lineCount];
ptr = (PRODUCT*)malloc(sizeof(PRODUCT)*lineCount);
ptr = prodContainter;
read(ptr);
//print after adding to array via pointer from other
//function. this was a test.
for(i = 0; i < lineCount; i++)
{
printf("%s ", prodContainter[i].supType);
printf("%s ", prodContainter[i].prodName);
printf("%f ", prodContainter[i].wholePrice);
printf("%d ", prodContainter[i].quantWhole);
printf("%f ", prodContainter[i].retPrice);
printf("%d\n\n", prodContainter[i].retProdQuantity);
}
return 0;
}
void read(PRODUCT *pointerToArr)
{
// objective in this method is to read in data from the file, create an object for every line and
// then use the pointer array to add those objects to prodConstainer up above.
char supplyName[15];
char productName[15];
double wholeP = 0;
int quantityWhole = 0;
double retailPrice = 0;
int retailProductQuant = 0;
while(fscanf(fr, "%s %s %lf %d %lf %d", supplyName, productName, &wholeP, &quantityWhole, &retailPrice, &retailProductQuant) == 6)
{
PRODUCT record;
int i;
strcpy(record.supType, supplyName);
strcpy(record.prodName, productName);
record.wholePrice = wholeP;
record.quantWhole = quantityWhole;
record.retPrice = retailPrice;
record.retProdQuantity = retailProductQuant;
for(i = 0; i < lineCount; i++)
{
pointerToArr[i] = record;
}
}
fclose(fr);
}
You never rewind the file, so all the reading after you count the number of lines fails.
What you're printing is just what happens to be in memory.
There are many ways to fix this, of course.
Rewind the file, using rewind()
Close the file and let your read() function (whose name collides with a POSIX standard function, btw) re-open the file. This would also involve removing the scary global variable fr.
Re-structure so you never count the number of lines, by just reading and letting the ptr array grow as necessary (see realloc()).
Also, you should really avoid casting the return value of malloc() in C. This:
ptr = (PRODUCT*)malloc(sizeof(PRODUCT)*lineCount);
is better written as:
ptr = malloc(lineCount * sizeof *ptr);
This does away with the cast, and also uses sizeof on a value of the type pointed at to automatically compute the proper number of bytes to allocate.

Reallocating memory for a struct array in C

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.

Resources