Creating and Running .c and .h Files
This page explains how to save C code as a text file, compile it, and run it. The file itself is simply a plain text file saved with a .c extension. Header files that collect function declarations use the .h extension.
How to write a .c file
Write your C code in a text editor and save the file with a .c extension. Save the file using the UTF-8 character encoding.
sample_greet.c
#include <stdio.h>
int main(void) {
char name[] = "Kiryu Kazuma";
int age = 37;
printf("Hello, %s!\n", name);
printf("Age: %d\n", age);
if (age >= 20) {
printf("Adult.\n");
} else {
printf("Minor.\n");
}
return 0;
}
The first line, #include <stdio.h>, includes the standard I/O library. It is required in order to use printf. Execution begins from the main function, which is the entry point of the program.
How to write comments
You can write comments (notes) in a .c file. Comments are ignored by the compiler, so they are useful for leaving descriptions or notes about the code.
| Syntax | Description |
|---|---|
| // comment | A single-line comment. Write it with one space after //. Available since C99. Everything from // to the end of the line is a comment. |
| /* comment */ | A multi-line comment. Everything from /* to */ is a comment. Available since C89. |
#include <stdio.h>
/*
The following is the main function.
This is the entry point of the program.
*/
int main(void) {
// Sets the username.
char name[] = "Majima Goro";
// Displays a greeting message.
printf("Hello, %s!\n", name);
return 0;
}
In modern C development, single-line comments (//) are widely used. Use /* */ when compatibility with older environments is required.
How to write a header file (.h)
A header file is a file that collects function declarations and constant definitions, and uses the .h extension. You load it from a .c file using #include. A header file is also just a plain text file.
It is common practice to include something called an include guard in a header file. In short, an include guard ensures that #include-ing the same file multiple times does not cause a compilation error. Based on experience, the include guard area can be quite confusing for those unfamiliar with it, and it is likely one of the major reasons people give up learning C, so let's look at it in detail.
First, check the table below for include guard syntax. The example assumes the header file is named greeting.h. The part like GREETING_H is conventionally the filename in uppercase (greeting.h → GREETING_H). As long as the name does not conflict with other header files it can be set freely, but following the convention is recommended. Doing so makes it easy to identify the corresponding file just by looking at GREETING_H.
| Directive | Origin of abbreviation | Meaning |
|---|---|---|
| #ifndef GREETING_H | if not defined | If GREETING_H has not yet been defined, everything from this line to #endif is read. This is essentially a kind of if statement. |
| #define GREETING_H | define | Defines GREETING_H. #define can be placed anywhere, but placing it immediately below #ifndef is the standard pattern when you want to avoid duplicate #include errors. |
| #endif | end if | Closes the #ifndef block. |
Let's first see what happens when we include the same header file twice without an include guard. The files used are greeting.h and main.c.
greeting.h (without include guard)
// Defines a greeting message structure.
typedef struct {
char name[50];
int age;
} Person;
sample_main.c
#include <stdio.h>
#include "greeting.h"
#include "greeting.h" // second inclusion
int main(void) {
Person p = {"Kiryu Kazuma", 25};
printf("%s (%d)\n", p.name, p.age);
return 0;
}
Compiling this results in an error.
gcc main.c -o main
main.c:3:10: error: redefinition of 'Person'
The second #include "greeting.h" causes a duplicate definition of Person, producing the error "already defined." In a small program you are unlikely to accidentally include the same file twice, but in a large program such mistakes become more common. Let's add an include guard to the same header file.
greeting.h (with include guard)
#ifndef GREETING_H
#define GREETING_H
// Defines a greeting message structure.
typedef struct {
char name[50];
int age;
} Person;
#endif
sample_main.c
#include <stdio.h>
#include "greeting.h" // 1st: GREETING_H undefined → loaded → GREETING_H defined
#include "greeting.h" // 2nd: GREETING_H already defined → ignored
int main(void) {
Person p = {"Kiryu Kazuma", 25};
printf("%s (%d)\n", p.name, p.age);
return 0;
}
This time compilation succeeds.
gcc main.c -o main ./main
Kiryu Kazuma (25)
On the second #include "greeting.h", because GREETING_H was already defined in the first inclusion, the #ifndef GREETING_H condition is not met and the entire contents are ignored. This is the effect of the include guard, preventing the duplicate error. As mentioned, the larger the program the more likely such mistakes become, so it is a good idea to always include an include guard unless there is a special reason not to.
Next let's look at a practical example of a header file. First, check the table below for #include syntax. Standard library headers are enclosed in < >, while headers you create yourself are enclosed in " ".
| Syntax | Description |
|---|---|
| #include <stdio.h> | Loads a standard library header. Searches in directories managed by the compiler. |
| #include "calc.h" | Loads a user-created header. Searches from the current directory. |
Let's actually split the code into files. The header file calc.h contains function prototype declarations (declarations saying "these functions exist"), the source file calc.c contains the function bodies (the actual processing), and main.c calls the functions by #include-ing calc.h.
calc.h
#ifndef CALC_H #define CALC_H // Performs addition. int add(int a, int b); // Performs subtraction. int subtract(int a, int b); #endif
sample_calc.c
#include "calc.h"
int add(int a, int b) {
return a + b;
}
int subtract(int a, int b) {
return a - b;
}
sample_main.c
#include <stdio.h>
#include "calc.h"
int main(void) {
printf("3 + 5 = %d\n", add(3, 5));
printf("10 - 4 = %d\n", subtract(10, 4));
return 0;
}
When the code is split across multiple files, all .c files must be specified at compile time. For this sample, the command looks like this:
gcc main.c calc.c -o calc_app
See the table below for the meaning and notes of each part of the compile command.
| Part | Meaning |
|---|---|
| gcc | Launches the C compiler. |
| main.c calc.c | Specifies all .c files to compile. The order is free. .h files are loaded automatically via #include and do not need to be specified. |
| -o calc_app | Specifies the name of the output executable. If omitted, the output is named a.out. |
Then run the generated executable.
./calc_app
3 + 5 = 8 10 - 4 = 6
Common Mistakes
Common Mistake: Forgetting the Include Guard
If a header file without an include guard is included indirectly from multiple .c files, duplicate definition errors for types or functions will occur. Always add an include guard to header files.
player.h (without include guard)
/* NG: no include guard */
typedef struct {
char name[32];
int hp;
} Player;
player_ng.c
#include "player.h"
#include "player.h" /* including twice causes an error */
int main(void) {
Player p = {"Kiryu Kazuma", 100};
return 0;
}
player_ng.c:2: error: redefinition of 'Player'
player_ok.h (with include guard)
/* OK: the include guard prevents duplicate inclusions. */
#ifndef PLAYER_H
#define PLAYER_H
typedef struct {
char name[32];
int hp;
} Player;
#endif /* PLAYER_H */
player_ok.c
#include <stdio.h>
#include "player_ok.h"
#include "player_ok.h" /* including twice is safe */
int main(void) {
Player p = {"Kiryu Kazuma", 100};
printf("%s HP=%d\n", p.name, p.hp);
return 0;
}
gcc player_ok.c -o player_ok ./player_ok Kiryu Kazuma HP=100
Summary
A .c file is simply a plain text file. You can create one by writing C code in a text editor and saving it with a .c extension. No special tools are needed.
C is a compiled language, so two steps are required: compile with gcc filename.c -o output, then run with ./output. Because compilation produces a machine-code executable, execution speed is one of C's key features.
There are two types of comments: single-line comments (//, available since C99) and multi-line comments (/* */). In modern C development, single-line comments are widely used.
By using header files (.h) to collect function declarations, you can split a program across multiple files. Adding an include guard (#ifndef, #define, #endif) to header files prevents compilation errors caused by duplicate inclusions.
On macOS, running xcode-select --install is all you need to make gcc available. For gcc installation instructions, see Setup.
If you find any errors or copyright issues, please contact us.