C program which copies one file contents to another file.

Copying a file in C demonstrates how to combine file I/O functions (fopen, fgetc, fputc, fclose) with command-line arguments to build a practical utility. The program reads filenames from argv, opens both files, copies byte-by-byte, and reports how many bytes were transferred.

The original version used conio.h, process.h, void main(), and stored the return value of fgetc() in a char — a subtle bug: fgetc() returns int so it can represent EOF (−1) distinctly from any valid byte. Storing it in a char can cause EOF to be misidentified on platforms where char is unsigned.

C Program to Copy File Contents

/* Copy file contents from source to destination
 * Usage: ./filecopy source.txt dest.txt
 * Compile: gcc -ansi -Wall -Wextra filecopy.c -o filecopy */
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    FILE *src, *dst;
    int ch;        /* int, not char — fgetc returns int so EOF (-1) works */
    long count = 0;

    if (argc != 3) {
        fprintf(stderr, "Usage: %s source destination\n", argv[0]);
        return 1;
    }

    src = fopen(argv[1], "r");
    if (src == NULL) {
        fprintf(stderr, "Error: cannot open source file '%s'\n", argv[1]);
        return 1;
    }

    dst = fopen(argv[2], "w");
    if (dst == NULL) {
        fprintf(stderr, "Error: cannot open destination file '%s'\n", argv[2]);
        fclose(src);
        return 1;
    }

    while ((ch = fgetc(src)) != EOF) {
        fputc(ch, dst);
        count++;
    }

    fclose(src);
    fclose(dst);

    printf("Copied %ld bytes from '%s' to '%s'.\n", count, argv[1], argv[2]);
    return 0;
}

How to Compile and Run

gcc -ansi -Wall -Wextra filecopy.c -o filecopy
echo "Hello from source" > source.txt
./filecopy source.txt destination.txt

Sample Output

# Success:
./filecopy source.txt destination.txt
Copied 19 bytes from 'source.txt' to 'destination.txt'.

# Wrong number of arguments:
./filecopy
Usage: ./filecopy source destination

# Source file missing:
./filecopy missing.txt out.txt
Error: cannot open source file 'missing.txt'

How the Copy Loop Works

while ((ch = fgetc(src)) != EOF) {
    fputc(ch, dst);
    count++;
}
  1. fgetc(src) reads one byte from the source file and returns it as an int.
  2. The return value is assigned to ch inside the while condition — the assignment happens before the comparison.
  3. If ch == EOF, the loop ends. EOF is a negative constant (typically −1) that signals end of file or read error.
  4. fputc(ch, dst) writes the byte to the destination file.

The outer parentheses around (ch = fgetc(src)) are required — without them, the expression parses as ch = (fgetc(src) != EOF), which stores 0 or 1 instead of the character.

Code Explanation

  • int ch (not char ch)fgetc() is declared as returning int so it can return any valid byte value (0–255) AND the special EOF marker (−1) without collision. If you store the result in a char and char is unsigned on your platform, EOF (−1 wrapped to 255) will be indistinguishable from the byte value 255, causing an infinite loop on binary files containing 0xFF bytes.
  • Open mode "r" and "w" — text mode on the platform. For binary files (images, executables), use "rb" and "wb" to prevent newline translation on Windows.
  • fclose on error path — when the destination cannot be opened, fclose(src) is called before returning. Failing to close a file on error paths leaks the file descriptor — harmless in a short program but important in long-running ones.
  • fprintf to stderr — error messages go to stderr, not stdout. This lets the caller distinguish program output from error messages and allows shell redirection: ./filecopy src dst 2>errors.log.
  • Byte count with long — using long instead of int allows reporting file sizes up to ~2 billion bytes on 32-bit platforms. For large files, long long or size_t would be used.

What This Program Teaches

  • File I/O with fopen/fgetc/fputc/fclose — the foundational file API in C. Every file operation follows the same pattern: open → read/write in a loop → close. Always check the return value of fopen for NULL.
  • The fgetc int vs char distinction — one of the most common C bugs in file-reading code. The C standard explicitly requires fgetc to return int. The idiom int ch; while ((ch = fgetc(fp)) != EOF) is the correct pattern.
  • Command-line argument validation — any utility-style program should validate argc and print a usage message. Using argv[0] in the usage message keeps it correct if the binary is renamed.
  • Resource cleanup on all exit paths — a good habit: every fopen that succeeds must have a matching fclose on every return path, including error paths.

Related Programs

Recommended book:
The C Programming Language — Kernighan & Ritchie (India) |
(US)
 | 
C Programming: A Modern Approach — K.N. King (India) |
(US)

Practice what you learned: C Aptitude Questions — or try our C Programming Quiz App on Android.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>