You are actually on the right path, you just fell off by failing to validate your file was open and in your loop logic at the end. You also have a problem in not validating that you actually got num_of_values
values from your file.
Let's start by eliminating the "Where is the values3.txt
file?" problem. main()
provides the ability for your to pass arguments in, such as a filename, make use of that. The declaration for main
accepting arguments is:
int main (int argc, char *argv[]) /* where argc arguments are passed in argv */
This eliminates the hardcoding of values3.txt
in your program. Just pass the filename as the first argument and
FILE *fp = fopen (argv[1], "r");
Or, take it one better and use a ternary operator to open the file in argv[1]
if it is given, otherwise read from stdin
(by default):
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
Always validate your file is open for reading, and handle the error if it is not, e.g.
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
Another significant issue you had was failure to initialize freq
to zero. When you start freq[current] += 1;
in your code, freq[current]
must have been set to zero beforehand to make that make any sense. A simple initialization is all you need:
freq[range_of_nums] = {0}, /* you must initialize freq */
On to the logic issues. You want to read up to a maximum of num_of_values
integer values into a
, but no more. Reading even 1 more would invoke Undefined Behavior. There is no guarantee that there will always be 8
integers in the file. What if there were 6
? What if there were 26
? You must handle all cases. So instead of using a for (i = 0; i < num_of_values; i++)
loop why not just read all the value and make sure you don't read more than num_of_values
? Something like:
/* read each value up to num_of_values */
while (i < num_of_values && fscanf (fp, "%d", &a[i]) == 1)
i++;
How could you adjust if you only read 6
values? Maybe:
if (i != num_of_values) /* validate 8 values read */
num_of_values = i; /* if not adjust number */
(note: you already know it cannot be more from your test in front of fscanf
)
You don't necessarily want to alter your variable holding the number of elements in your array (that's kinda important to keep around). Why don't we use a new variable to hold N/2
(say num_by_2
. Then you could do:
num_by_2 = num_of_values / 2; /* you need another var */
while still preserving num_of_values
for use later in your code.
Lastly, if I understand correctly, you want to identify all numbers that appear more than N/2
time. You have a logic problem in your loop layout. To find all values that appear greater than N/2
times, the printf
needs to be in that loop, e.g.
for (i = 0; i < range_of_nums; i++)
{
if (freq[i] > num_by_2)
{
found_number = i + 1;
printf ("The number %d occurs more than N/2 %d times \n",
found_number, num_by_2);
}
}
Now you know if found_number
has a value, a value was found. So your last test could simply be:
if (found_number == 0)
printf("No number occurs more than N/2 times\n");
Putting it altogether, you could clean the logic up with something similar to the following:
#include <stdio.h>
#define range_of_nums 3
int main (int argc, char **argv)
{
int i = 0,
num_of_values = 8, /* you have 8 values */
a[num_of_values], /* otherwise your VLA is wrong */
freq[range_of_nums] = {0}, /* you must initialize freq */
num_by_2 = 0,
found_number = 0;
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
/* read each value up to num_of_values */
while (i < num_of_values && fscanf (fp, "%d", &a[i]) == 1)
i++;
if (fp != stdin) fclose (fp); /* close file if not stdin */
if (i != num_of_values) /* validate 8 values read */
num_of_values = i; /* if not adjust number */
for (i = 0; i < num_of_values; i++) /* set frequency array vals */
freq[a[i] - 1] += 1;
num_by_2 = num_of_values / 2; /* you need another var */
for (i = 0; i < range_of_nums; i++)
{
if (freq[i] > num_by_2)
{
found_number = i + 1;
printf ("The number %d occurs more than N/2 %d times \n",
found_number, num_by_2);
}
}
if (found_number == 0)
printf("No number occurs more than N/2 times\n");
return 0;
}
Example Use/Output
$ echo "2 3 2 2 2 3 2 1" | ./bin/numby2freq
The number 2 occurs more than N/2 4 times
Look things over and let me know if you have further questions.