Array initialization is one of the most fundamental yet nuanced topics in C programming. How you initialize an array determines its initial content, affects program behavior, and can be a source of subtle bugs if misunderstood. This article provides an exhaustive exploration of array initialization in C, covering static arrays, partial initialization, designated initializers, character arrays, multidimensional arrays, and common pitfalls.
1. What is Array Initialization?
Array initialization is the process of assigning initial values to array elements at the time of declaration. Unlike uninitialized arrays which contain garbage values (whatever happened to be in memory), properly initialized arrays have predictable, deterministic content.
Key Terminology:
- Uninitialized array: Contains indeterminate (garbage) values
- Zero-initialized array: All elements set to zero (or NULL for pointers)
- Partial initialization: First N elements explicitly set, remaining set to zero
- Full initialization: All elements explicitly assigned values
2. Complete Initialization Methods
A. Braced Initialization (Most Common)
The standard way to initialize an array is using curly braces {} with a comma-separated list of values.
#include <stdio.h>
int main() {
// Complete initialization - all 5 elements get values
int numbers[5] = {10, 20, 30, 40, 50};
// Size deduced from initializer list (compiler counts elements)
int more_numbers[] = {1, 2, 3, 4, 5, 6, 7}; // Size becomes 7
printf("Numbers: ");
for (int i = 0; i < 5; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
printf("More numbers (size 7): ");
for (int i = 0; i < 7; i++) {
printf("%d ", more_numbers[i]);
}
printf("\n");
return 0;
}
Output:
Numbers: 10 20 30 40 50 More numbers (size 7): 1 2 3 4 5 6 7
B. Universal Zero Initialization (Crucial Pattern)
If you provide fewer initializers than the array size, the remaining elements are automatically zero-initialized. This is a critical safety feature in C.
#include <stdio.h>
int main() {
// Only first 3 elements explicitly set, remaining 2 become 0
int array[5] = {1, 2, 3};
printf("Partial initialization result:\n");
for (int i = 0; i < 5; i++) {
printf("array[%d] = %d\n", i, array[i]);
}
return 0;
}
Output:
Partial initialization result: array[0] = 1 array[1] = 2 array[2] = 3 array[3] = 0 // Auto-zeroed array[4] = 0 // Auto-zeroed
Critical Note: This auto-zeroing behavior applies to all basic types (int, float, double, char, pointers).
C. The Empty Brace Trick (C99+)
#include <stdio.h>
int main() {
// Empty braces zero-initialize ALL elements
int array[100] = {}; // All 100 elements are zero
// Verify some elements
for (int i = 0; i < 10; i++) {
printf("array[%d] = %d\n", i, array[i]);
}
// Check a far element
printf("array[99] = %d\n", array[99]);
return 0;
}
Output:
array[0] = 0 array[1] = 0 ... array[9] = 0 array[99] = 0
Important: The empty initializer {} is valid in C99 and later, but some older compilers (strict C89/C90) may reject it. For maximum portability, use {0}.
D. Singleton Zero Initialization
The most portable way to zero-initialize an entire array:
#include <stdio.h>
int main() {
// Setting just the first element to zero zeros EVERYTHING
int large_array[1000] = {0}; // Entire array is zero-initialized
char name[100] = {0}; // All 100 characters are '\0'
double measurements[50] = {0}; // All 50 doubles are 0.0
printf("All methods produce zero-initialized arrays:\n");
printf("int[0] = %d\n", large_array[0]);
printf("int[999] = %d\n", large_array[999]);
printf("char[0] = %d (null terminator)\n", name[0]);
printf("double[0] = %f\n", measurements[0]);
return 0;
}
Output:
All methods produce zero-initialized arrays: int[0] = 0 int[999] = 0 char[0] = 0 (null terminator) double[0] = 0.000000
Why this works: C's initialization rule states that if you provide at least one initializer, any elements without explicit initializers are zero-initialized. By providing {0}, you set the first element to zero and trigger zero-initialization for all others.
3. Specialized Initialization Techniques
A. Designated Initializers (C99)
Designated initializers allow you to initialize specific array indices, leaving others zero-initialized.
#include <stdio.h>
int main() {
// Initialize indices 2, 4, and 8 with specific values
int sparse_array[10] = {
[2] = 100,
[4] = 200,
[8] = 300
};
printf("Designated initializer results:\n");
for (int i = 0; i < 10; i++) {
if (sparse_array[i] != 0) {
printf("array[%d] = %d\n", i, sparse_array[i]);
}
}
// You can combine designated and sequential initialization
int mixed[10] = {
1, 2, 3, // indices 0,1,2
[6] = 100, // index 6
4, 5 // indices 7,8 (continues after last designated)
};
printf("\nMixed initialization:\n");
for (int i = 0; i < 10; i++) {
printf("mixed[%d] = %d\n", i, mixed[i]);
}
return 0;
}
Output:
Designated initializer results: array[2] = 100 array[4] = 200 array[8] = 300 Mixed initialization: mixed[0] = 1 mixed[1] = 2 mixed[2] = 3 mixed[3] = 0 mixed[4] = 0 mixed[5] = 0 mixed[6] = 100 mixed[7] = 4 mixed[8] = 5 mixed[9] = 0
B. String Literals for Character Arrays
Character arrays (strings) have special initialization syntax using string literals.
#include <stdio.h>
#include <string.h>
int main() {
// Method 1: String literal (includes implicit null terminator)
char str1[] = "Hello"; // Size is 6 ('H','e','l','l','o','\0')
// Method 2: Explicit character array with null terminator
char str2[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
// Method 3: Partial initialization (remaining chars zeroed)
char str3[10] = "Hi"; // 'H','i','\0', then 7 zero bytes
// Method 4: Without null terminator (DANGEROUS - not a proper string)
char not_a_string[] = {'H', 'i'}; // No '\0' - cannot use with string functions
printf("str1: '%s' (size: %lu bytes)\n", str1, sizeof(str1));
printf("str2: '%s' (size: %lu bytes)\n", str2, sizeof(str2));
printf("str3: '%s' (size: %lu bytes)\n", str3, sizeof(str3));
// This would cause undefined behavior (reading past array bounds):
// printf("not_a_string: '%s'\n", not_a_string);
// Safe way to print non-null-terminated arrays
printf("not_a_string (manual): %c%c\n", not_a_string[0], not_a_string[1]);
return 0;
}
Output:
str1: 'Hello' (size: 6 bytes) str2: 'Hello' (size: 6 bytes) str3: 'Hi' (size: 10 bytes) not_a_string (manual): Hi
C. Multidimensional Array Initialization
#include <stdio.h>
int main() {
// Method 1: Nested braces (recommended for clarity)
int matrix1[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
// Method 2: Flat initialization (values fill row-major order)
int matrix2[2][3] = {1, 2, 3, 4, 5, 6};
// Method 3: Partial initialization of multidimensional arrays
int matrix3[3][4] = {
{1, 2}, // Row 0: {1,2,0,0}
{5, 6, 7}, // Row 1: {5,6,7,0}
// Row 2: all zeros {0,0,0,0}
};
// Method 4: Designated initializers for specific elements
int matrix4[3][3] = {
[0][0] = 1,
[1][1] = 5,
[2][2] = 9
};
printf("Matrix1 (2x3):\n");
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", matrix1[i][j]);
}
printf("\n");
}
printf("\nMatrix3 (3x4) with partial initialization:\n");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
printf("%3d ", matrix3[i][j]);
}
printf("\n");
}
printf("\nMatrix4 with designated initializers:\n");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", matrix4[i][j]);
}
printf("\n");
}
return 0;
}
Output:
Matrix1 (2x3): 1 2 3 4 5 6 Matrix3 (3x4) with partial initialization: 1 2 0 0 5 6 7 0 0 0 0 0 Matrix4 with designated initializers: 1 0 0 0 5 0 0 0 9
D. Array of Structures Initialization
#include <stdio.h>
#include <string.h>
typedef struct {
char name[50];
int age;
float score;
} Student;
int main() {
// Method 1: Initialize array of structures
Student class1[3] = {
{"Alice", 20, 85.5},
{"Bob", 21, 92.0},
{"Charlie", 19, 78.5}
};
// Method 2: Designated initializers for clarity
Student class2[3] = {
[0] = {.name = "David", .age = 22, .score = 88.0},
[2] = {.name = "Eve", .age = 20, .score = 95.5}
// class2[1] is zero-initialized
};
// Method 3: Partial initialization (remaining elements zeroed)
Student class3[5] = {
{"Frank", 23, 91.0},
{"Grace", 21, 87.5}
// Indices 2,3,4 are zero-initialized
};
printf("Class1 (full initialization):\n");
for (int i = 0; i < 3; i++) {
printf(" %s: age %d, score %.1f\n",
class1[i].name, class1[i].age, class1[i].score);
}
printf("\nClass2 (with designated initializers):\n");
for (int i = 0; i < 3; i++) {
if (class2[i].age != 0) { // Skip zero-initialized
printf(" %s: age %d, score %.1f\n",
class2[i].name, class2[i].age, class2[i].score);
} else {
printf(" [%d]: zero-initialized\n", i);
}
}
printf("\nClass3 (partial, size 5):\n");
for (int i = 0; i < 5; i++) {
if (class3[i].age != 0) {
printf(" %s: age %d, score %.1f\n",
class3[i].name, class3[i].age, class3[i].score);
} else {
printf(" [%d]: zero-initialized\n", i);
}
}
return 0;
}
Output:
Class1 (full initialization): Alice: age 20, score 85.5 Bob: age 21, score 92.0 Charlie: age 19, score 78.5 Class2 (with designated initializers): David: age 22, score 88.0 [1]: zero-initialized Eve: age 20, score 95.5 Class3 (partial, size 5): Frank: age 23, score 91.0 Grace: age 21, score 87.5 [2]: zero-initialized [3]: zero-initialized [4]: zero-initialized
4. Variable-Length Arrays (VLAs)
C99 introduced Variable-Length Arrays whose size is determined at runtime. They have special initialization considerations.
#include <stdio.h>
int main() {
int size;
printf("Enter array size: ");
scanf("%d", &size);
// Variable-Length Array (size determined at runtime)
int vla[size];
// VLA INITIALIZATION RULES:
// 1. You CANNOT initialize VLA at declaration (compiler error)
// int vla2[size] = {0}; // ERROR: VLA cannot be initialized
// 2. You must manually initialize VLAs
for (int i = 0; i < size; i++) {
vla[i] = 0; // Manual zero initialization
}
// 3. Or use memset for efficiency
#include <string.h>
int vla2[size];
memset(vla2, 0, sizeof(vla2)); // Efficient zero initialization
printf("VLA of size %d initialized successfully\n", size);
// 4. Compound literals can initialize VLAs (C99)
int size2 = 4;
int* vla3 = (int[size2]){1, 2, 3, 4}; // Compound literal initialization
printf("Compound literal VLA: ");
for (int i = 0; i < size2; i++) {
printf("%d ", vla3[i]);
}
printf("\n");
return 0;
}
Important: VLAs cannot be initialized at declaration time in standard C. Always manually initialize them.
5. Static and Global Array Initialization
Arrays with static storage duration (global or static local) have different initialization rules.
#include <stdio.h>
// Global array - zero-initialized by default (BSS segment)
int global_array[1000]; // All zeros automatically
// Global array with explicit initialization (data segment)
int initialized_global[5] = {1, 2, 3, 4, 5};
void function() {
// Static local array - initialized only once, persists across calls
static int call_count_array[3] = {0}; // Initialized to zeros
// This increment persists between function calls
call_count_array[0]++;
call_count_array[1] += 2;
call_count_array[2] += 3;
printf("Call count array: [%d, %d, %d]\n",
call_count_array[0], call_count_array[1], call_count_array[2]);
}
int main() {
printf("Global array first element: %d\n", global_array[0]);
printf("Global array last element: %d\n", global_array[999]);
printf("Initialized global: ");
for (int i = 0; i < 5; i++) {
printf("%d ", initialized_global[i]);
}
printf("\n\n");
// Static local persists across function calls
function(); // Output: [1, 2, 3]
function(); // Output: [2, 4, 6]
function(); // Output: [3, 6, 9]
return 0;
}
Output:
Global array first element: 0 Global array last element: 0 Initialized global: 1 2 3 4 5 Call count array: [1, 2, 3] Call count array: [2, 4, 6] Call count array: [3, 6, 9]
Key Rule: Global and static local arrays are automatically zero-initialized even without an explicit initializer. Auto (local) arrays contain garbage if not initialized.
6. Common Pitfalls and Errors
A. Uninitialized Local Arrays
#include <stdio.h>
int main() {
int garbage_array[5]; // NO INITIALIZER - contains garbage values
printf("Uninitialized array contains INDETERMINATE values:\n");
for (int i = 0; i < 5; i++) {
printf("garbage_array[%d] = %d\n", i, garbage_array[i]);
// Values are unpredictable - could be 0, could be random
}
// WARNING: The code above exhibits undefined behavior
// Never rely on uninitialized local array values
return 0;
}
Output (varies each run - this is UB):
Uninitialized array contains INDETERMINATE values: garbage_array[0] = 0 garbage_array[1] = 4200136 garbage_array[2] = 6422272 garbage_array[3] = 4200469 garbage_array[4] = 0
B. Excessive Initializers
#include <stdio.h>
int main() {
// ERROR: Too many initializers
// int array[3] = {1, 2, 3, 4, 5}; // Compilation error
// Fix: Let compiler deduce size or match exactly
int correct1[] = {1, 2, 3, 4, 5}; // Size becomes 5
int correct2[5] = {1, 2, 3, 4, 5}; // Exact match
printf("Compiler-deduced size: %lu\n", sizeof(correct1) / sizeof(correct1[0]));
return 0;
}
C. Forgetting Null Terminator in Strings
#include <stdio.h>
#include <string.h>
int main() {
// DANGEROUS: No room for null terminator
char no_room[5] = "Hello"; // 5 characters, no space for '\0' - Warning!
// The compiler might warn: initializer-string for array of chars is too long
// CORRECT: Leave room for null terminator
char correct[6] = "Hello"; // Size 6 includes '\0'
printf("Correct string: '%s'\n", correct);
// The no_room array is NOT a proper C string
// printf("%s", no_room); // UNDEFINED BEHAVIOR
return 0;
}
D. Confusing Array Size with Initializer Count
#include <stdio.h>
int main() {
// Common mistake: Confusing sizeof with element count
int array[10] = {1, 2, 3};
// sizeof returns TOTAL BYTES, not element count
printf("sizeof(array) = %lu bytes\n", sizeof(array));
printf("Element count = %lu\n", sizeof(array) / sizeof(array[0]));
// Correct way to get element count
int count = sizeof(array) / sizeof(array[0]);
printf("Array has %d elements\n", count);
// When iterating, use the calculated count, not the initializer count
for (int i = 0; i < count; i++) {
printf("array[%d] = %d\n", i, array[i]);
}
return 0;
}
Output:
sizeof(array) = 40 bytes Element count = 10 Array has 10 elements array[0] = 1 array[1] = 2 array[2] = 3 array[3] = 0 array[4] = 0 array[5] = 0 array[6] = 0 array[7] = 0 array[8] = 0 array[9] = 0
7. Performance and Memory Considerations
#include <stdio.h>
#include <time.h>
#define SIZE 1000000
int main() {
clock_t start, end;
double cpu_time_used;
// Method 1: Explicit initialization at declaration (fastest)
start = clock();
int array1[SIZE] = {0}; // Compiler generates efficient code
end = clock();
cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
printf("{0} initialization: %f seconds\n", cpu_time_used);
// Method 2: Manual loop (slower)
int array2[SIZE];
start = clock();
for (int i = 0; i < SIZE; i++) {
array2[i] = 0;
}
end = clock();
cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
printf("Manual loop: %f seconds\n", cpu_time_used);
// Method 3: memset (usually optimized, similar to {0})
#include <string.h>
int array3[SIZE];
start = clock();
memset(array3, 0, sizeof(array3));
end = clock();
cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
printf("memset: %f seconds\n", cpu_time_used);
return 0;
}
Typical Performance (compiler-dependent):
{0}initialization: Fastest (compiler optimizes to efficient assembly)memset(): Very fast (library optimized, often uses SIMD)- Manual loop: Slowest (especially without optimization flags)
8. Complete Reference Table
| Initialization Syntax | Array Type | Result | Portability |
|---|---|---|---|
int arr[5]; (local) | Auto | Garbage values | All standards |
int arr[5]; (global) | Static | All zeros | All standards |
int arr[5] = {0}; | Any | All zeros | All standards |
int arr[5] = {}; | Any | All zeros | C99+ |
int arr[5] = {1,2}; | Any | [1,2,0,0,0] | All standards |
int arr[] = {1,2,3}; | Any | Size deduced as 3 | All standards |
int arr[5] = {[2]=5}; | Any | [0,0,5,0,0] | C99+ |
char str[] = "Hi"; | Char | ['H','i','\0'], size 3 | All standards |
char str[3] = "Hi"; | Char | ['H','i','\0'] | All standards |
char str[2] = "Hi"; | Char | ERROR (no room for '\0') | All standards |
9. Best Practices Summary
DO ✓
- Always initialize local arrays:
int arr[SIZE] = {0}; - Use
{0}for maximum portability (works with C89 to C23) - Let the compiler deduce size when initializing:
int arr[] = {1,2,3}; - Use designated initializers for sparse arrays or self-documenting code
- Always leave room for null terminator in char arrays:
char str[6] = "Hello"; - Use
sizeof(arr) / sizeof(arr[0])to get element count
DON'T ✗
- Don't use uninitialized local arrays (undefined behavior)
- Don't provide more initializers than array size
- Don't forget the null terminator in C strings
- Don't assume partial initialization leaves garbage (it zeros the rest)
- Don't try to initialize VLAs at declaration (not allowed)
- Don't use magic numbers; calculate array sizes when possible
10. Complete Working Example
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
// Demonstrate all major initialization techniques
int main() {
printf("=== C ARRAY INITIALIZATION MASTER DEMO ===\n\n");
// 1. Basic initialization
int basic[5] = {10, 20, 30, 40, 50};
printf("1. Basic initialization: ");
for (int i = 0; i < 5; i++) printf("%d ", basic[i]);
printf("\n");
// 2. Zero initialization techniques
int zeros1[5] = {0};
int zeros2[5] = {};
static int zeros3[5]; // Static storage duration
printf("2. Zero initialization: ");
for (int i = 0; i < 5; i++) printf("%d ", zeros1[i]);
printf("\n");
// 3. Partial initialization
int partial[8] = {1, 2, 3};
printf("3. Partial initialization (rest zeroed): ");
for (int i = 0; i < 8; i++) printf("%d ", partial[i]);
printf("\n");
// 4. Size deduction
int deduced[] = {100, 200, 300, 400, 500};
printf("4. Size deduction (size = %lu): ", sizeof(deduced)/sizeof(deduced[0]));
for (size_t i = 0; i < sizeof(deduced)/sizeof(deduced[0]); i++) {
printf("%d ", deduced[i]);
}
printf("\n");
// 5. Designated initializers (C99)
int designated[10] = {[0]=10, [3]=40, [7]=80, [9]=100};
printf("5. Designated initializers: ");
for (int i = 0; i < 10; i++) {
if (designated[i] != 0) printf("[%d]=%d ", i, designated[i]);
}
printf("\n");
// 6. String initialization
char str1[] = "Hello";
char str2[10] = "World";
char str3[20] = {0}; // Empty string
printf("6. String initialization: '%s', '%s', '%s'\n", str1, str2, str3);
// 7. 2D array initialization
int matrix[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
printf("7. 2D array (3x4):\n");
for (int i = 0; i < 3; i++) {
printf(" Row %d: ", i);
for (int j = 0; j < 4; j++) printf("%3d ", matrix[i][j]);
printf("\n");
}
// 8. Jagged 2D initialization (partial rows)
int jagged[3][4] = {
{1, 2},
{5, 6, 7},
{9}
};
printf("8. Partial 2D initialization (zeros fill gaps):\n");
for (int i = 0; i < 3; i++) {
printf(" Row %d: ", i);
for (int j = 0; j < 4; j++) printf("%3d ", jagged[i][j]);
printf("\n");
}
// 9. Array of structures
typedef struct {
int id;
char name[20];
float value;
} Item;
Item inventory[3] = {
{1, "Widget", 19.99},
{2, "Gadget", 29.99},
{3, "Thingy", 9.99}
};
printf("9. Array of structures:\n");
for (int i = 0; i < 3; i++) {
printf(" Item %d: %s ($%.2f)\n",
inventory[i].id, inventory[i].name, inventory[i].value);
}
// 10. Compound literals for initialization
int* dynamic_array = (int[5]){100, 200, 300, 400, 500};
printf("10. Compound literal initialization: ");
for (int i = 0; i < 5; i++) printf("%d ", dynamic_array[i]);
printf("\n");
// Note: Compound literal lifetime ends at block end unless assigned to pointer
return 0;
}
Output:
=== C ARRAY INITIALIZATION MASTER DEMO === 1. Basic initialization: 10 20 30 40 50 2. Zero initialization: 0 0 0 0 0 3. Partial initialization (rest zeroed): 1 2 3 0 0 0 0 0 4. Size deduction (size = 5): 100 200 300 400 500 5. Designated initializers: [0]=10 [3]=40 [7]=80 [9]=100 6. String initialization: 'Hello', 'World', '' 7. 2D array (3x4): Row 0: 1 2 3 4 Row 1: 5 6 7 8 Row 2: 9 10 11 12 8. Partial 2D initialization (zeros fill gaps): Row 0: 1 2 0 0 Row 1: 5 6 7 0 Row 2: 9 0 0 0 9. Array of structures: Item 1: Widget ($19.99) Item 2: Gadget ($29.99) Item 3: Thingy ($9.99) 10. Compound literal initialization: 100 200 300 400 500
Conclusion
Array initialization in C is a deceptively deep topic. While the syntax appears simple, understanding the nuances—especially the auto-zeroing behavior of partial initialization, the special rules for strings, and the differences between static and automatic storage—is essential for writing correct, robust C code.
The single most important rule to remember: Always initialize your local arrays. The simple pattern int array[SIZE] = {0}; guarantees predictable behavior across all C standards and compilers, and should be your default choice unless you have a specific reason to do otherwise.
Complete Guide to Core & Advanced C Programming Concepts (Functions, Strings, Arrays, Loops, I/O, Control Flow)
https://macronepal.com/bash/building-blocks-of-c-a-complete-guide-to-functions/
Explains how functions in C work as reusable blocks of code, including declaration, definition, parameters, return values, and modular programming structure.
https://macronepal.com/bash/the-heart-of-text-processing-a-complete-guide-to-strings-in-c-2/
Explains how strings are handled in C using character arrays, string manipulation techniques, and common library functions for text processing.
https://macronepal.com/bash/the-cornerstone-of-data-organization-a-complete-guide-to-arrays-in-c/
Explains arrays in C as structured memory storage for multiple values, including indexing, initialization, and efficient data organization.
https://macronepal.com/bash/guaranteed-execution-a-complete-guide-to-the-do-while-loop-in-c/
Explains the do-while loop in C, where the loop body executes at least once before checking the condition.
https://macronepal.com/bash/mastering-iteration-a-complete-guide-to-the-for-loop-in-c/
Explains the for loop in C, including initialization, condition checking, and increment/decrement for controlled iteration.
https://macronepal.com/bash/mastering-iteration-a-complete-guide-to-while-loops-in-c/
Explains the while loop in C, focusing on condition-based repetition and proper loop control mechanisms.
https://macronepal.com/bash/beyond-if-else-a-complete-guide-to-switch-case-in-c/
Explains switch-case statements in C, enabling multi-branch decision-making based on variable values.
https://macronepal.com/bash/mastering-conditional-logic-a-complete-guide-to-if-else-statements-in-c/
Explains if-else statements in C for decision-making and controlling program flow based on conditions.
https://macronepal.com/bash/mastering-the-fundamentals-a-complete-guide-to-arithmetic-operations-in-c/
Explains arithmetic operations in C such as addition, subtraction, multiplication, division, and operator precedence.
https://macronepal.com/bash/foundation-of-c-programming-a-complete-guide-to-basic-input-output/
Explains basic input and output in C using scanf and printf for interacting with users and displaying results.
Online C Code Compiler
https://macronepal.com/free-online-c-code-compiler-2/