← Back to home
C vs Java Cheat Sheet
Side-by-side reference for the concepts you already know in Java and how they translate to C.
Compilation and Execution
| Java |
C |
javac Hello.java |
gcc -Wall -Wextra -std=c17 -o hello hello.c |
java Hello |
./hello |
| Compiles to bytecode, runs on JVM |
Compiles to native machine code |
One class per .java file (convention) |
Functions across .c files, declared in .h headers |
import java.util.Scanner; |
#include <stdio.h> (preprocessor copies the header in) |
C compilation is a multi-step pipeline: preprocessor → compiler → assembler → linker. gcc runs all four. Use -Wall -Wextra always — the compiler catches mistakes the language won't stop you from making.
Program Structure
| Java |
C |
public class Hello { ... } |
No classes — just functions in files |
public static void main(String[] args) |
int main(int argc, char *argv[]) |
| Methods belong to classes |
Functions are standalone (no this) |
System.out.println("hi"); |
printf("hi\n"); |
return; from void method |
return 0; from main (0 = success) |
| Packages organize code |
Header files (.h) declare interfaces |
Types and Variables
| Java |
C |
boolean |
int (0 = false, nonzero = true) — or #include <stdbool.h> for bool |
String (object) |
char[] or char * (null-terminated array) |
int is always 32 bits |
int is “at least 16 bits” (usually 32) |
byte, short, int, long |
char, short, int, long (sizes vary by platform) |
final int X = 5; |
const int X = 5; or #define X 5 |
var x = 5; (type inference) |
No type inference — always declare types explicitly |
| Default initialization (0, null, false) |
Local variables are uninitialized (garbage values!) |
C has no String type. Strings are just arrays of char ending with '\0'. This is the single biggest source of bugs for Java programmers learning C.
Console I/O
| Java |
C |
System.out.println("x = " + x); |
printf("x = %d\n", x); |
System.out.printf("%d", x); |
printf("%d", x); (same format specifiers) |
Scanner sc = new Scanner(System.in); |
No Scanner — use scanf, fgets, or getline |
int n = sc.nextInt(); |
scanf("%d", &n); (note the & — address of n) |
String s = sc.nextLine(); |
fgets(s, sizeof(s), stdin); |
| Exceptions on bad input |
scanf returns the count of items read — check it |
| Format |
Type |
Example |
%d |
int |
printf("%d", 42); |
%f |
double |
printf("%.2f", 3.14); |
%c |
char |
printf("%c", 'A'); |
%s |
char * (string) |
printf("%s", name); |
%p |
pointer (address) |
printf("%p", (void *)ptr); |
%ld |
long |
printf("%ld", big); |
Control Flow
| Java |
C |
if, else if, else |
Identical syntax |
switch (String, int, enum) |
switch on integers/chars only |
for, while, do-while |
Identical syntax |
for (int x : arr) (for-each) |
No for-each — use index: for (int i = 0; i < n; i++) |
break, continue |
Identical |
Functions
| Java |
C |
| Methods belong to a class |
Functions are standalone |
| Overloading (same name, different params) |
No overloading — every function name is unique |
void swap(int a, int b) — doesn’t work |
void swap(int *a, int *b) — pass addresses |
| Pass by value (always, for primitives) |
Pass by value (always) — use pointers to simulate pass-by-reference |
| Return object to return multiple values |
Return via pointer parameters or return a struct |
| Declaration order doesn’t matter |
Must declare before use (prototype or define above call) |
/* Function prototype — goes at top of file or in .h */
void swap(int *a, int *b);
/* Definition */
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
/* Call site */
swap(&x, &y); /* pass addresses */
Arrays
| Java |
C |
int[] arr = new int[10]; |
int arr[10]; (stack) or int *arr = calloc(10, sizeof(int)); (heap) |
arr.length |
No .length — track size yourself in a separate variable |
| Bounds checking (ArrayIndexOutOfBoundsException) |
No bounds checking — out-of-bounds = undefined behavior |
Arrays.sort(arr); |
qsort(arr, n, sizeof(int), compare_func); |
2D: int[][] grid = new int[3][4]; |
int grid[3][4]; (stack) — rows are contiguous in memory |
| Garbage collected |
Stack arrays die with the function; heap arrays need free() |
Strings
| Java |
C |
String s = "hello"; |
char s[] = "hello"; or char *s = "hello"; (read-only) |
s.length() |
strlen(s) (walks the string counting chars — O(n)) |
s1.equals(s2) |
strcmp(s1, s2) == 0 |
s1 + s2 (concatenation) |
strcat(dest, src) — dest must have enough space |
s.charAt(i) |
s[i] |
s.substring(2, 5) |
No built-in — use pointer arithmetic or strncpy |
| Strings are immutable |
char[] strings are mutable; char * literals are not |
| Null is a reference thing |
Strings end with '\0' (null terminator) — forget it and everything breaks |
char name[50];
strcpy(name, "Alice"); /* copy string into buffer */
strcat(name, " Smith"); /* append — name must have room */
printf("Length: %zu\n", strlen(name)); /* 11 */
if (strcmp(name, "Alice Smith") == 0) {
printf("Match!\n");
}
Memory: The Big Difference
| Java |
C |
new allocates on the heap |
calloc / malloc allocate on the heap |
| Garbage collector frees memory |
You free memory with free() |
| No pointer arithmetic |
Pointer arithmetic is a core tool |
NullPointerException |
Segmentation fault (crash) or silent corruption |
| No memory leaks (usually) |
Memory leaks if you forget free() |
| No dangling references |
Use-after-free = undefined behavior |
/* Allocate array of 10 ints, zero-initialized */
int *arr = calloc(10, sizeof(int));
if (arr == NULL) {
fprintf(stderr, "Out of memory\n");
return 1;
}
/* Use it */
arr[0] = 42;
/* Done — give the memory back */
free(arr);
arr = NULL; /* prevent use-after-free */
Use calloc over malloc — it zero-initializes memory, which catches bugs that garbage values hide. Use Valgrind to check for leaks: valgrind --leak-check=full ./program
Pointers (No Java Equivalent)
Pointers are addresses. Java hides them behind references; C gives them to you directly.
int x = 42;
int *p = &x; /* p holds x's address */
*p = 99; /* follow the pointer, write 99 → x is now 99 */
int **pp = &p; /* pointer to pointer */
**pp = 7; /* follow two levels → x is now 7 */
| Operation |
Syntax |
Meaning |
| Declare pointer |
int *p; |
p can hold the address of an int |
| Address-of |
&x |
Get x’s memory address |
| Dereference |
*p |
Follow pointer to the value |
| Pointer arithmetic |
p + 3 |
Address 3 ints past p |
| Array indexing |
p[3] |
Same as *(p + 3) |
Structs (Instead of Classes)
| Java |
C |
class Student { ... } |
typedef struct { ... } Student; |
| Fields + methods |
Fields only — no methods |
student.getName() |
student.name (direct access) |
this.name |
No this — pass struct as parameter |
| Inheritance, interfaces |
No inheritance — composition only |
new Student() |
Stack: Student s = {0}; / Heap: Student *s = calloc(1, sizeof(Student)); |
student.name (reference) |
ptr->name (shorthand for (*ptr).name) |
typedef struct {
char name[50];
int age;
double gpa;
} Student;
/* Stack allocation */
Student s = {"Alice", 20, 3.8};
printf("%s is %d\n", s.name, s.age);
/* Heap allocation */
Student *p = calloc(1, sizeof(Student));
strcpy(p->name, "Bob");
p->age = 21;
free(p);
File I/O
| Java |
C |
new FileReader("data.txt") |
fopen("data.txt", "r") |
try-with-resources auto-closes |
You must call fclose(fp) |
BufferedReader.readLine() |
fgets(line, sizeof(line), fp) |
PrintWriter.println() |
fprintf(fp, "...\n"); |
| Exceptions on error |
Returns NULL on failure — always check |
FILE *fp = fopen("data.txt", "r");
if (fp == NULL) {
perror("fopen"); /* prints: "fopen: No such file or directory" */
return 1;
}
char line[256];
while (fgets(line, sizeof(line), fp) != NULL) {
printf("%s", line);
}
fclose(fp);
Error Handling
| Java |
C |
try / catch / finally |
No exceptions — check return values |
throw new Exception("...") |
Return error codes or set errno |
| Stack unwinding |
Manual cleanup (often goto cleanup) |
NullPointerException |
Segfault or silent corruption |
/* C pattern: check every call, clean up on failure */
FILE *fp = fopen(filename, "r");
if (fp == NULL) {
perror("fopen");
return -1;
}
char *buf = calloc(1024, sizeof(char));
if (buf == NULL) {
fclose(fp); /* clean up what we already opened */
return -1;
}
/* ... use fp and buf ... */
free(buf);
fclose(fp);
CC = gcc
CFLAGS = -Wall -Wextra -std=c17
program: main.o utils.o
$(CC) $(CFLAGS) -o program main.o utils.o
main.o: main.c utils.h
$(CC) $(CFLAGS) -c main.c
utils.o: utils.c utils.h
$(CC) $(CFLAGS) -c utils.c
clean:
rm -f *.o program
| Java (Gradle/Maven) |
C (Make) |
gradle build |
make |
gradle clean |
make clean |
| Dependency resolution automatic |
You list dependencies in Makefile rules |
Compiles all .java at once |
Compiles each .c separately, then links |
Quick Translation Guide
| Task |
Java |
C |
| Print with newline |
System.out.println(x) |
printf("%d\n", x) |
| Read an int |
sc.nextInt() |
scanf("%d", &x) |
| Allocate array |
new int[n] |
calloc(n, sizeof(int)) |
| Free memory |
(garbage collected) |
free(ptr) |
| String compare |
s1.equals(s2) |
strcmp(s1, s2) == 0 |
| String copy |
s1 = s2 |
strcpy(s1, s2) |
| String length |
s.length() |
strlen(s) |
| Array length |
arr.length |
Track it yourself |
| Sort |
Arrays.sort(arr) |
qsort(arr, n, sizeof(int), cmp) |
| Null check |
if (obj == null) |
if (ptr == NULL) |
| Struct/class field |
obj.field |
s.field or ptr->field |
| Boolean |
boolean |
int (or bool with stdbool.h) |