← 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);

Build System: Makefiles (Instead of IDE Build Buttons)

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)