I see lots of buffer overruns and off-by-one errors
This seems better
Code:
/*
* FREQ.C -- blah blah
*
* given input of "this_is_a_test" freq.c will output to a file
*
* char freq context
* ---- ---- -------
* _ 3 a, i, t
* a 1 _
* e 1 s
* i 2 s
* h 1 i
* s 3 _, t
* t 3 e, h
*
* the "context" column represents characters that appear to the right
* of each character processed.
*
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TABLE_SIZE 256
struct data {
unsigned char achar;
unsigned char context[TABLE_SIZE];
unsigned long int count;
};
struct data symbol[TABLE_SIZE];
void init_symbol_array();
void get_stats(char *);
void print_stats(char *);
int main(int, char *[]);
/*
* Kinda obvious, but zero out array
*/
void
init_symbol_array(void)
{
int i, j;
for (i = 0; i < TABLE_SIZE; i++) {
symbol[i].achar = i;
symbol[i].count = 0;
for (j = 0; j < TABLE_SIZE; j++)
symbol[i].context[j] = 0;
}
}
/*
* Get frequency count of each character
*/
void
get_stats(char *file)
{
int c, i;
unsigned char buf[8192];
FILE *fp;
if((fp = fopen(file, "rb")) == NULL) {
(void)fprintf(stderr, "\nerror: %s: Can't open '%s'\n",
strerror(ENOENT), file);
exit(EXIT_FAILURE);
}
while ((c = fread(buf, 1, sizeof(buf), fp)) > 0) {
for (i = 0; i < c-1; i++) { /* nothing to the right of the last char */
symbol[(int)buf[i]].count++;
symbol[(int)buf[i]].context[(int)buf[i+1]] = (int)buf[i+1];
}
}
fclose(fp);
}
/*
* Print symbol stats to output file
*/
void
print_stats(char *file)
{
FILE *fp;
int i, j;
if((fp = fopen(file, "w")) == NULL) {
(void)fprintf(stderr, "\nerror: %s: Can't write to '%s'\n",
strerror(ENOENT), file); /* use strerror(errno) */
exit(EXIT_FAILURE);
}
fprintf(fp, "char\tfreq\tcontext\n");
fprintf(fp, "----\t----\t-------\n");
for (i = 0; i < TABLE_SIZE; i++) {
if (symbol[i].count > 0) {
fprintf(fp, "%c\t%lu\t", symbol[i].achar, symbol[i].count);
for (j = 0; j < TABLE_SIZE; j++) {
if (symbol[i].context[j] > 0)
fprintf(fp, "%c", symbol[i].context[j]);
}
fprintf(fp,"\n");
}
}
fclose(fp);
}
/*
* This is where it all happens; the main function.
*/
int
main(int argc, char *argv[])
{
if(argv[2] == NULL)
argv[2] = "output.txt";
init_symbol_array();
printf("\nGathering statistics... ");
get_stats(argv[1]);
printf("done\n");
print_stats(argv[2]);
exit(EXIT_SUCCESS);
}