i want to write a code to count occurrences of a specific hex number in a file. for example in the file there are 0x01 0x02 0x03 0x41 0x42 0x43 0x0D 0x0A 0xFF 0xFE 0xFD 0x01 0x02 0x03 0x80 0x7F 0x0D 0x0A
and if i input : FF
it will output: 1
i already working on the code but it doesn't seems to work
#include <stdio.h>
#include <stdlib.h>
main ()
{
FILE *in, *out;
unsigned char a[1000] = { 0 };
int b;
int count = 0, i = 0;
in = fopen ("a.dat", "rb");
out = fopen ("b.txt", "wb");
while (!feof (in)) {
b = fgetc (in);
a[i] = b;
i ;
}
scanf ("%x", &b);
for (i = 0; i < 1000; i ) {
if (a[i] == b) {
count ;
}
}
fprintf (out, "%d\n", count);
printf ("%d\n", count);
fclose (out);
fclose (in);
return 0;
}
(note: nesting error with '}'
fixed)
CodePudding user response:
You have a large number of small errors. They can be summarized as follows:
while (!feof(in))
reads one-character-too-many. Look at the logic of the loop. After reading the last character, you check!feof(in)
(which hasn't occurred yet) and then callb = fgetc (in);
again (which now returnsEOF
), and then you blindly assigna[i] = b;
. That's Why is while ( !feof (file) ) always wrong? Simply control your read-loop with the return from your read-function.- You use the wrong type with
scanf()
.%x
requires anunsigned int*
value, but you pass typeint*
. This will result in problems with signed and unsigned type mismatch. This is readily apparent when you compile with warnings enabled. - You fail to validate whether your open of
in
andout
succeed. Always validate every file open operation. - You fail the validate the return of
scanf()
. You cannot usescanf()
correctly unless you validate the number returned is equal to the number of valid conversions expected. - Since you write to
b.txt
you should validate thefclose(out)
. Always validate your close-after-write to ensure you catch any write error that occurs after the last value written by your code. - There is no need to loop over all
1000
elements of your array. You know the number of elements filled from the value ofi
. Just loop over the elements filled using a separate loop variable (j
shown below). - Lastly, when you need input from your user, don't leave the user staring at a blinking cursor on the screen wondering whether the program is hung or what is going on, prompt the user for input.
Putting all the pieces together, you could do something similar to the following:
#include <stdio.h>
#include <stdlib.h>
#define MAXC 1000 /* if you need a constant, #define one (or more) */
int main (void)
{
FILE *in, *out;
unsigned char a[MAXC] = { 0 };
int b;
unsigned u; /* unsigned value required for scanf() */
int count = 0, i = 0, j;
in = fopen ("a.dat", "rb");
out = fopen ("b.txt", "wb");
if (!in) { /* always validate every file open */
perror ("fopen-a.dat");
return 1;
}
if (!out) { /* always validate every file open */
perror ("fopen-b.txt");
return 1;
}
/* protect array bound - use read function to control loop */
while (i < MAXC && (b = fgetc (in)) != EOF) {
a[i] = b;
i ;
}
fputs ("enter 8-bit hex value to find: ", stdout);
if (scanf ("%x", &u) != 1) { /* validte every user-input */
fputs ("error: invalid hex input.\n", stderr);
return 1;
}
for (j = 0; j < i; j ) { /* iterate over values read from file */
if (a[j] == u) {
count ;
}
}
fprintf (out, "%d\n", count);
printf ("%d\n", count);
if (fclose (out) == EOF) { /* always validate close-after-write */
perror ("fclose-out");
}
fclose (in);
}
Example Use/Output
Compiling your code with full warnings enabled you can do:
$ gcc -Wall -Wextra -pedantic -Wshadow -std=c11 -O3 -o bin/readwriteucbin readwriteucbin.c
Running your code on the binary input provided you would get, e.g.
$ ./bin/readwriteucbin
enter 8-bit hex value to find: 0xff
1
Or where more than one value is matched, e.g.
$ ./bin/readwriteucbin
enter 8-bit hex value to find: 1
2