I want to read a PNG image file with C without any library. From PNG (Portable Network Graphics) Specification Version 1.0 any PNG file has a signature that distinguishes it from other image formats. The signature is the first 8 bytes of the image.
Some sources like the above RFC mentioned the signature as:
137 80 78 71 13 10 26 10 (decimal)
Or like Not able to read IHDR chunk of a PNG file mentioned the signature as:
89 50 4E 47 0D 0A 1A 0A (ASCii)
So, I write a simple code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE (8)
int main(int argc, char **argv){
if(argc != 2) {
printf("Usage: %s <png file>\n", argv[0]);
return 1;
}
char *buf = (char *)malloc(MAX_SIZE);
if(!buf) {
fprintf(stderr, "Couldn't allocate memory\n");
return 1;
}
FILE *f = fopen(argv[1], "r");
if(!f) {
perror("fopen");
printf("Invalid file\n");
free(buf);
return 1;
}
int size = fread(buf, 1, MAX_SIZE, f);
printf(%c\n", buf[1]);
printf(%c\n", buf[2]);
printf(%c\n", buf[3]);
printf(%c\n", buf[4]);
printf(%c\n", buf[5]);
printf(%c\n", buf[6]);
printf(%c\n", buf[7]);
printf(%c\n", buf[8]);
fclose(f);
free(buf);
system("pause");
return 0;
}
When I print the bytes by printf, the output is not like the above.
This is what it shows:
ëPNG→►v#,
Can someone describe what happened and what can I do to modify it?
You need to print each value with the correct format specifier. Here we want numerical representations, not character ones.
From the documentation on printf:
%c writes a single character
%d converts a signed integer into decimal representation
%x converts an unsigned integer into hexadecimal representation
%02X prints a hexadecimal with a minimum width of two characters, padding with leading zeroes, using ABCDEF (instead of abcdef).
See also implicit conversions.
An example:
#include <stdio.h>
#define SIZE 8
int main(int argc, char **argv) {
unsigned char magic[SIZE];
FILE *file = fopen(argv[1], "rb");
if (!file || fread(magic, 1, SIZE, file) != SIZE) {
fprintf(stderr, "Failure to read file magic.\n");
return 1;
}
/* Decimal */
for (size_t i = 0; i < SIZE; i++)
printf("%d ", magic[i]);
printf("\n");
/* Hexadecimal */
for (size_t i = 0; i < SIZE; i++)
printf("%02X ", magic[i]);
printf("\n");
fclose(file);
}
Output:
137 80 78 71 13 10 26 10
89 50 4E 47 0D 0A 1A 0A
Related
I know there are too many questions about this algorithm but I couldn't really find a good answer for compressing the bytes. I am kind of a newbie in C. I have the following code:
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
//compress function here...
int main(int argc, char **argv) {
if(argc != 2){
fprintf(stderr, "Wrong argument number\n");
exit(1);
}
FILE *source = fopen(argv[1], "rb");
if(source == NULL){
fprintf(stderr, "Cannot open the file to be read\n");
exit(1);
}
FILE *destination;
char name = printf("%s.rle", argv[1]);
while((destination = fopen(&name, "wb")) == NULL){
fprintf(stderr, "Can't create the file to be written\n");
exit(1);
}
compress_file(source, destination);
int error;
error = fclose(source);
if(error != 0){
fprintf(stderr, "Error: fclose failed for source file\n");
}
error = fclose(destination);
if(error != 0){
fprintf(stderr, "Error: fclose failed for destination file\n");
}
}
If this is test.c and the executable is test. I need to make this work on terminal/command prompt as "./test file.txt". My file.txt includes something like (bytes):
20 21 20 20 8F 8F 21 21 64 60 70 20 21 90 90
and the desired output is:
01 20 01 21 02 20 02 8F 02 21 01 64 01 60 01 70 01 20 01 21 02 90
My code create a file and that file includes:
0b00 0000 0106 0000 0000 0000 0000 0000
0000 0000 0a
instead what I want. What do I miss?
Also I want my file to be named as file.txt.rle but it has no name.
EDIT:
char name[30];
sprintf(name, "%s.rle", argv[1]);
solved the problem for naming.
Also I want my file to be named as file.txt.rle but it has no name.
Well, this code
char name = printf("%s.rle", argv[1]);
while((destination = fopen(&name, "wb")) == NULL){
doesn't give you a string like "file.txt.rle". Instead try something like:
size_t len = strlen(argv[1]) + 4 + 1;
char name[len];
sprintf(name, "%s.rle", argv[1]);
while((destination = fopen(name, "wb")) == NULL){
instead what I want. What do I miss?
Well, you miss that you need to put data into str
This code
char str[BUF_SIZE];
fwrite(str, sizeof(str), 1, destination);
just writes an uninitialized variable to the file.
I'll not give you a complete solution but here is something that you can start with and then figure the rest out yourself.
void compress_file(FILE *source, FILE *destination){
char str[BUF_SIZE];
int index = 0;
int repeat_count = 0;
int previous_character = EOF;
int current_character;
while((current_character = fgetc(source)) != EOF){
if(current_character != previous_character) {
if (previous_character != EOF) {
// Save the values to str
str[index++] = repeat_count;
str[index++] = previous_character;
}
previous_character = current_character;
repeat_count = 1;
}
else{
repeat_count++;
}
}
if (repeat_count != 0)
{
str[index++] = repeat_count;
str[index++] = previous_character;
}
fwrite(str, index, 1, destination);
}
EXAMPLE 1:
Let's say a file.txt is:
ABBCCC
On linux it can be displayed hexadecimal like this:
# hexdump -C file.txt
00000000 41 42 42 43 43 43 |ABBCCC|
After running the program, you have:
hexdump -C file.txt.rle
00000000 01 41 02 42 03 43 |.A.B.C|
EXAMPLE 2:
Let's say that file.txt is like
# hexdump -C file.txt
00000000 20 21 20 20 8f 8f 21 21 64 60 70 20 21 90 90 | ! ..!!d`p !..|
the result will be
# hexdump -C file.txt.rle
00000000 01 20 01 21 02 20 02 8f 02 21 01 64 01 60 01 70 |. .!. ...!.d.`.p|
00000010 01 20 01 21 02 90 |. .!..|
As pointed in comments, you have two problems:
Usage of printf instead of sprintf,
Writting to file what you've counted.
Name Creation
char name = printf("%s.rle", argv[1]);
destination = fopen(&name, "wb");
The first line will store the number of characters in argv[1] plus 4 into name. Since, from man printf:
Upon successful return, these functions return the number of characters printed (excluding the null byte used to end output to strings).
The second line is more problematic : you ask fopen to open a file giving it a pointer to char instead of a read string.
One correct way to do what you want is:
/* reserve memory to store file name
NOTE: 256 here might not large enough*/
char name[256];
/* fill name array with original name + '.rle'
The return of sprintf is tested to assert that its size was enough */
if (snprintf(name, sizeof name, "%s.rle", argv[1]) >= sizeof name)
{
fprintf(stderr, "name variable is not big enough to store destination filename");
}
Writting to file
The code
char str[BUF_SIZE];
fwrite(str, sizeof(str), 1, destination);
reserve a big array, and writes it to file, without initializing it. To do what you want, you can have this approach:
make a function that will only write two characters in file: the number of character found and the character itself
call this function each time needed (at character changing, but not when one of character is EOF...)
Let's look at :
void write_char_to_file(FILE *f, int count, char car)
{
/* char array to be stored in file */
char str[2];
/* number of repeating characters */
str[0] = count;
/* the character */
str[1] = car;
/* write it to file */
fwrite(str, sizeof str, 1, f);
}
This function has two potential problems:
It doesn't handle char overflow (what if count is over 256?),
It doesn't test the return of fwrite.
Then, when this function should be called, when the current character changes:
EOF A A B C C EOF
In this example, we have 4 characters changes, but we want only 3 writting in the file, so:
Character changing when previous is EOF must be ignored (else we would write something like 0 (char)EOF at file starting),
One writting must be added after while loop since, when the last reading gives EOF, we still have 2 C to write to file.
Let's look at the code:
while((current_character = fgetc(source)) != EOF) {
if(current_character != previous_character) {
/* ignore initial change */
if (previous_character != EOF) {
write_char_to_file(destination, repeat_count, previous_character);
}
previous_character = current_character;
repeat_count = 1;
} else {
repeat_count++;
}
}
/* write last change */
write_char_to_file(destination, repeat_count, previous_character);
This code have a problem too: what if the input file is empty? (first read gives EOF)
The complete code:
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#define BUF_SIZE 5096
void write_char_to_file(FILE *f, int count, char car)
{
/* char array to be stored in file */
char str[2];
/* number of repeating characters */
str[0] = count;
/* the character */
str[1] = car;
/* write it to file */
fwrite(str, sizeof str, 1, f);
}
void compress_file(FILE *source, FILE *destination)
{
int repeat_count = 0;
int previous_character = EOF;
int current_character;
while((current_character = fgetc(source)) != EOF) {
if(current_character != previous_character) {
if (previous_character != EOF) {
write_char_to_file(destination, repeat_count, previous_character);
}
previous_character = current_character;
repeat_count = 1;
} else {
repeat_count++;
}
}
write_char_to_file(destination, repeat_count, previous_character);
}
int main(int argc, char **argv) {
if(argc != 2) {
fprintf(stderr, "Wrong argument number\n");
exit(1);
}
FILE *source = fopen(argv[1], "rb");
if(source == NULL) {
fprintf(stderr, "Cannot open the file to be read\n");
exit(1);
}
FILE *destination;
/* reserve memory to store file name
NOTE: 256 here might not large enough*/
char name[256];
/* fill name array with original name + '.rle'
The return of sprintf is tested to assert that its size was enough */
if (snprintf(name, sizeof name, "%s.rle", argv[1]) >= sizeof name)
{
fprintf(stderr, "name variable is not big enough to store destination filename");
}
/* while is not needed here, if do the job */
if((destination = fopen(name, "wb")) == NULL) {
fprintf(stderr, "Can't create the file to be written\n");
exit(1);
}
compress_file(source, destination);
int error;
error = fclose(source);
if(error != 0) {
fprintf(stderr, "Error: fclose failed for source file\n");
}
error = fclose(destination);
if(error != 0) {
fprintf(stderr, "Error: fclose failed for destination file\n");
}
/* main must return a integer */
return 0;
}
Iam having a problem with my school project. When i try to read in C program some hex data from a binary file i get some data filled with F's like this
00 64 61 56 03 00 00 00 09 00 00 00 73 00 00 00
6A 69 75 FFFFFFE8 FFFFFFD1 5B FFFFFF8C FFFFFF93 73 FFFFFFAF 19 FFFFFF87 FFFFFFC1 4D FFFFFFFD FFFFFF93
FFFFFFDF FFFFFFBE FFFFFFA0 09 FFFFFFBE FFFFFFD4 FFFFFFEB FFFFFFDE FFFFFFD3 FFFFFFF9 FFFFFFBD FFFFFFE6 FFFFFFFA FFFFFFAA 7E 29
FFFFFFD3 FFFFFFE2 13 FFFFFFA5 3F FFFFFFA0 3A FFFFFFB2 50 53 3B 12 FFFFFFA1 39 FFFFFFA6 FFFFFF82
FFFFFFF7
While the original file in hexdump looks like this:
0000000 6400 5661 0003 0000 0009 0000 0073 0000
0000010 696a e875 5bd1 938c af73 8719 4dc1 93fd
0000020 bedf 09a0 d4be deeb f9d3 e6bd aafa 297e
0000030 e2d3 a513 a03f b23a 5350 123b 39a1 82a6
0000040 00f7
Iam not quiet sure, why is this happening.
I tested it using this code:
int main()
{
char ch, file_name[25];
FILE *fp;
printf("Enter the name of file you wish to see\n");
fgets(file_name, sizeof(file_name), stdin);
file_name[strlen(file_name)-1] = 0x00;
fp = fopen(file_name,"rb"); // read binary mode
if( fp == NULL ) //error checking
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
printf("The contents of %s file are :\n", file_name);
int i;
while( ( ch = fgetc(fp) ) != EOF )
{
printf("%02X ",ch);
if( !(++i % 16) ) putc('\n', stdout);
}
fclose(fp);
putc('\n', stdout);
return 0;
}
You just tripped on the sign extension done by the processor when expanding a signed integer value to a larger integer type:
The type char is only one byte wide, while the printf() function expects int arguments (four bytes on your system). Since char is signed on your system, the other 24 bits are filled with copies of the sign bit, producing the FFFFFF pattern that you see in your output. Note that your output is correct, except for the FFFFFF-prefixes to all bytes that start with a hex digit greater or equal to 8.
You can avoid this by simply declaring ch as unsigned char. That will be zero extended to an int, and your output will be correct.
If you make ch an unsigned character you won't see the sign extension (the FFs).
It may not be a good idea to open a file as a binary file, and trying reading it by fgetc(), which deals with text files. Instead, you can use fread() to read binary files.
Here is my solution:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
int main()
{
char file_name[25];
puts("Enter the name of file you wish to see");
fgets(file_name, sizeof (file_name), stdin);
file_name[strlen(file_name) - 1] = '\0';
FILE *fp;
fp = fopen(file_name, "rb"); // read binary mode
if(!fp) //error checking
{
perror("fopen()");
exit(EXIT_FAILURE);
}
fseek (fp, 0, SEEK_END); // non-portable
long fSize = ftell(fp);
rewind(fp);
printf("The contents of %s file are :\n", file_name);
uint8_t *ch = malloc(fSize); // assuming CHAR_BIT == 8
fread(ch, 1, fSize, fp);
int i;
for(i = 0; i < fSize; i++)
{
printf("%.2x ", ch[i]);
if(!((i + 1) % 16))
putchar('\n');
}
fclose(fp);
putchar('\n');
return EXIT_SUCCESS;
}
This code has been tested on my machine, and its output is identical to that of hex dump. Feel free to ask me about the details.
make ch an unsigned char as it is treating the binary value as signed and the MSB as sign bit.
I am trying to read a file parsed from a command line argument 16 bytes at a time. I am storing the bytes in an unsigned char array. I am then trying to print the elements in their HEX format and then, if they are printable characters, I am printing them and if not I am printing a dot "." I also would like to print the offset of the byte from the beggining of the file on each new line but I want to get the rest working before I start working on that. The problem I am having is the file I am reading from is not printing so I don't think I am doing it right. I started out using fread() but I think I may be needing to use fseek() but I am unsure. If anyone could point me in the right direction or tell me if I'm doing anything wrong I'd appreciate it.
Code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *fp;
int i, j;
unsigned char buffer[17];
fp = fopen(argv[1], "r");
while(!feof(fp))
{
while(fread(buffer, 16, 1, fp) !=0)
{
for(i=0; i < 16; i++)
{
printf("%X ", buffer[i]);
}
for(j = 0; j < 16; j++)
{
if(isprint(buffer[j]))
printf("%s", buffer[j]);
else
printf("." );
}
printf("\n");
}
}
fclose(fp);
return 0;
}
Expected output:
0001: 40 4F 28 37 0B B8 FF 9D 81 5E 2E 73 B5 CC 6A 70 #O(7.....^.s..jp
0010: 0F 30 9C 6E 7E F7 53 E0 C1 5E 9A 38 C5 02 F2 33 .0.n .S..^.8...3
EDIT: Fixed problem with suggestions. Was opening file in text mode instead of binary. Changed read mode to "rb" and code is working correctly now.
You need to open the file in binary mode, using fseek/ftell on a file in text mode gives erratic values.
So open the file with
fp = fopen(argv[1], "rb");
also good practice is to always check if a function succeeded by checking the return value, in this case if (fp != NULL) ...
Instead of reading 16 byte chunks read 1 byte 16 times, otherwise if the file length is not evenly dividable by 16 you miss the last bytes
if ( fp != NULL )
{
int read = 0;
while((read = fread(buffer, 1, 16, fp)) > 0)
{
for(i=0; i < read; i++)
{
...
}
fclose(fp);
}
IOW no need to for the outer while (feof(fp)) ...
in
printf("%s", buffer[j]);
you are not using the correct format specifier, buffer[j] is a character, not a string so write
printf("%c", buffer[j]);
EDIT: if you are not in some embedded environment with minimal stack reading 16 bytes at a time is not so effective, you can just as might read 2k or some bigger size to read faster.
I'm trying to create a hexdump like xxd but there are some differences that I'm trying to resolve. Currently the program processes 10 characters per line as seen on the utmost right column vs 16 in xxd. It also only shows 1 octet per column instead of pairs of 2 octet's.
xxd
0000000: 2369 6e63 6c75 6465 203c 7374 6469 6f2e #include <stdio.
my output
0: 23 69 6E 63 6C 75 64 65 20 3C #include <
EDIT:
To add some clarification, I am trying to achieve two things.
1) I would like this program to output exactly like xxd. For this it needs to output 32 Hex numbers (8x columns of 4).
2) I would also like the program to list the hex numbers in row's columns of 4 like in xxd.
I've tried to edit the "10" in the source below to something like "12" but it creates errors in the output, it seems to be a magic number.
source:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#define BYTE_OFFSET_INIT 8
#define CHAR_OFFSET_INT 39
#define LINE_LENGTH 50
static void print_e(int e, char *program, char *file)
{
fprintf(stderr, "%s: %s: %s\n", program, file, strerror(e));
}
static void print_line(char *line)
{
int i;
/* sprintf leaves terminators mid-line, so clear them out so we can print the full line */
for (i = BYTE_OFFSET_INIT; i < CHAR_OFFSET_INT; i++)
if (line[i] == '\0')
line[i] = ' ';
printf("%s\n", line);
}
int main(int argc, char *argv[])
{
char line[LINE_LENGTH + 1];
int ch;
int character = 0;
int line_offset = 0;
int byte_offset = BYTE_OFFSET_INIT, char_offset = CHAR_OFFSET_INT;
if (argc != 2) {
fprintf(stderr, "Usage: %s [file]\n", argv[0]);
exit(EXIT_FAILURE);
}
FILE *fp = fopen(argv[1], "rb");
if (!fp) {
print_e(errno, argv[0], argv[1]);
exit(EXIT_FAILURE);
}
printf("Offset Bytes Characters\n");
printf("------ ----------------------------- ----------\n");
while ((ch = fgetc(fp)) != EOF) {
if (character == 0) {
sprintf(line, "%6d ", line_offset);
line_offset += 10;
}
sprintf(line + byte_offset, "%02X ", ch);
sprintf(line + char_offset, "%c", isprint(ch) ? ch : '.');
character++;
char_offset++;
byte_offset += 3;
if (character == 10) {
print_line(line);
character = 0;
char_offset = CHAR_OFFSET_INT;
byte_offset = BYTE_OFFSET_INIT;
}
}
if (ferror(fp)) {
print_e(errno, argv[0], argv[1]);
exit(EXIT_FAILURE);
}
if (character > 0)
print_line(line);
if (fclose(fp) == EOF) {
print_e(errno, argv[0], argv[1]);
exit(EXIT_FAILURE);
}
return 0;
}
While it's possible to scan one byte at a time and write it into the output string at the correct position, it is by no means necessary. It is way easier to read DISPLAY_LENGTH bytes at once and loop over the thus read number of bytes twice; first outputting the hex representation, then again for the ASCII characters. The only (minor) caveat is what to do at the end of the file; but since fread returns the number of characters, you can just keep on counting and output spaces for as long as necessary to fill the hex line.
This leads to the following program. DISPLAY_LENGTH is the total number of bytes to display per line, GROUP_BYTES is the number of single bytes in each hexadecimal group (setting it to 1 will display a 'regular' spaced hex output, 2 will group as in your xxd example, and higher values should also work).
I had some fun figuring out the magic formulae to correctly center the text Bytes and calculating how many dashes to display for the separator. The rest is very straightforward.
I don't know what xxd output looks like, apart from your one-line example, so I use stat to read out the length of the file in advance (with an added opportunity to display an error for "not a file" -- try for example with a folder) and display the correct number of dashes and spaces to line up the line counter. I set this value to a minimum of 6 so there is always room for the text Offset.
If your compiler is not a modern one, it may complain about the %zu format string. If so, use %lu; you may also need to change all occurrences of size_t to unsigned long.
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#define DISPLAY_LENGTH 21
#define GROUP_BYTES 2
static void print_e(int e, char *program, char *file)
{
fprintf(stderr, "%s: %s: %s\n", program, file, strerror(e));
}
int main(int argc, char *argv[])
{
size_t i;
struct stat fs;
int n_digit;
unsigned char read_buf[DISPLAY_LENGTH];
size_t bytes_read, cpos = 0;
if (argc != 2)
{
fprintf(stderr, "Usage: %s [file]\n", argv[0]);
exit(EXIT_FAILURE);
}
FILE *fp = fopen(argv[1], "rb");
if (!fp)
{
print_e (errno, argv[0], argv[1]);
exit(EXIT_FAILURE);
}
if (stat(argv[1], &fs) == -1)
{
print_e (errno, argv[0], argv[1]);
exit(EXIT_FAILURE);
}
if ((fs.st_mode & S_IFMT) != S_IFREG) /* regular file */
{
fprintf(stderr, "Not a regular file: %s\n", argv[1]);
exit(EXIT_FAILURE);
}
n_digit = 0;
while (fs.st_size > 0)
{
fs.st_size /= 10;
n_digit++;
}
if (n_digit < 6)
n_digit = 6;
printf("%*s ", n_digit, "Offset");
printf("%*s%-*s", ((2*DISPLAY_LENGTH+(DISPLAY_LENGTH+GROUP_BYTES-1)/GROUP_BYTES)+2)/2, "Bytes", ((2*DISPLAY_LENGTH+(DISPLAY_LENGTH+GROUP_BYTES-1)/GROUP_BYTES)+2-5)/2, "");
printf (" Characters\n");
for (i=0; i<n_digit; i++)
printf ("-");
printf(" ");
for (i=1; i<2*DISPLAY_LENGTH+(DISPLAY_LENGTH+GROUP_BYTES-1)/GROUP_BYTES; i++)
printf ("-");
printf (" ");
for (i=0; i<DISPLAY_LENGTH; i++)
printf ("-");
printf ("\n");
while ( (bytes_read = fread (read_buf, 1, DISPLAY_LENGTH, fp)))
{
printf ("%*zu ", n_digit, cpos);
for (i=0; i<bytes_read; i++)
{
if (!(i % GROUP_BYTES))
printf (" ");
printf ("%02X", read_buf[i]);
}
while (i < DISPLAY_LENGTH)
{
if (!(i % GROUP_BYTES))
printf (" ");
printf (" ");
i++;
}
printf (" ");
for (i=0; i<bytes_read; i++)
printf ("%c", isprint(read_buf[i]) ? read_buf[i] : '.');
printf ("\n");
cpos += bytes_read;
}
if (ferror(fp))
{
print_e (errno, argv[0], argv[1]);
exit(EXIT_FAILURE);
}
if (fclose(fp))
{
print_e (errno, argv[0], argv[1]);
exit(EXIT_FAILURE);
}
return 0;
}
Sample output, displaying its own compiled executable with a display length of 21 and grouped per 2 bytes:
Offset Bytes Characters
------ ---------------------------------------------------- ---------------------
0 CFFA EDFE 0700 0001 0300 0080 0200 0000 0D00 0000 70 ....................p
21 0600 0085 0020 0000 0000 0019 0000 0048 0000 005F 5F ..... .........H...__
42 5041 4745 5A45 524F 0000 0000 0000 0000 0000 0000 00 PAGEZERO.............
... (673 very similar lines omitted) ...
14196 7075 7473 005F 7374 6174 2449 4E4F 4445 3634 005F 73 puts._stat$INODE64._s
14217 7472 6572 726F 7200 6479 6C64 5F73 7475 625F 6269 6E trerror.dyld_stub_bin
14238 6465 7200 0000 der...
I was writting a program that can read a set of numbers file called dog.txt;
and also writes to two file separating odd and even. i was able to compile my program however, the output expected is not the same which was supposed to be even numbers in one file called EVEN, odd numbers in file odd.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int i;
int even,odd;
int num;
if (argc != 4) {
printf("Usage: executable in_file output_file\n");
exit(0);
}
FILE *dog = fopen(argv[1], "r");
FILE *feven= fopen(argv[2], "w");
FILE *fodd= fopen (argv[3], "w");
while (fscanf(dog, "%d", &num) != EOF)
{
if (0==i%2){
i++;
printf("even= %d\n", num);
}
else if(i!=0){
i++;
printf("odd= %d\n", num);
}
}
fclose(feven);
fclose(fodd);
fclose(dog);
return 0;
}
output:
even= 1
odd= 2
even= 34
odd= 44
even= 66
odd= 78
even= 94
odd= 21
even= 23
odd= 54
even= 44
odd= 65
even= 78
odd= 68
even= 92
You're checking i % 2, not num % 2. I'm not even sure what i does in this example—perhaps you're planning on using it later.
while (fscanf(dog, "%d", &num) != EOF) {
if (num % 2 == 0) {
printf("even = %d\n", num);
}
else if(num != 0) {
printf("odd = %d\n", num);
}
}
I imagine the code to write these numbers to the files will come later, once you've fixed this bug.
The code contains no instructions to write into the output files. It only writes to stdout.
In addition to the printf/fprintf problem, in any decent modern compiler, that code should be generating a warning that you're not assigning any initial value to i.
The printf function writes to the screen (more correctly, it writes to "standard output", but that is usually the screen). You want to write to a file. You have opened files called feven and fodd. To write to them, you would use the fprintf call, which works like printf except it takes an extra (left-most) argument, which is the FILE* that you want to write to, e.g.
FILE *fmyfile = fopen("myfile.txt", "w");
fprintf(fmyfile, "The magic number is %d!", 3);
Also, your results are incorrect, but that's an unrelated problem.