Introduction to Constants
Constants in C are fixed values that cannot be changed during program execution. They provide a way to define values that remain the same throughout the program, improving code readability, maintainability, and reducing errors.
Types of Constants in C
Constants in C
├── Literal Constants
│ ├── Integer Constants (10, -5, 0)
│ ├── Floating-point Constants (3.14, 2.5e-3)
│ ├── Character Constants ('A', '\n', '5')
│ └── String Constants ("Hello", "C Programming")
├── Symbolic Constants
│ ├── #define Preprocessor (PI, MAX_SIZE)
│ └── const Keyword (const int MAX = 100)
├── Enumeration Constants (enum)
└── Constant Expressions
Literal Constants
Integer Constants
#include <stdio.h>
int main() {
// Decimal (base 10)
int decimal = 42;
// Octal (base 8) - starts with 0
int octal = 052; // 42 in decimal
// Hexadecimal (base 16) - starts with 0x or 0X
int hex1 = 0x2A; // 42 in decimal
int hex2 = 0X2a; // 42 in decimal
// Binary (C23 standard) - starts with 0b
// int binary = 0b101010; // 42 in decimal (C23)
// Integer suffixes
long longVar = 42L; // long
unsigned int uintVar = 42U; // unsigned int
unsigned long ulVar = 42UL; // unsigned long
long long llVar = 42LL; // long long
printf("Decimal: %d\n", decimal);
printf("Octal (052): %d\n", octal);
printf("Hexadecimal (0x2A): %d\n", hex1);
printf("Long: %ld\n", longVar);
printf("Unsigned: %u\n", uintVar);
printf("Long Long: %lld\n", llVar);
return 0;
}
Output:
Decimal: 42 Octal (052): 42 Hexadecimal (0x2A): 42 Long: 42 Unsigned: 42 Long Long: 42
Floating-Point Constants
#include <stdio.h>
int main() {
// Decimal notation
float f1 = 3.14159;
double d1 = 2.71828;
// Scientific notation
double sci1 = 1.23e-4; // 0.000123
double sci2 = 5.67e+6; // 5670000
double sci3 = 8.9E2; // 890
// Hexadecimal floating-point (C99)
double hex_float = 0x1.2p3; // (1 + 2/16) * 2^3 = 9.0
// Floating-point suffixes
float floatVar = 3.14F; // float
double doubleVar = 3.14; // double (default)
long double ldVar = 3.14L; // long double
printf("Pi: %f\n", f1);
printf("e: %f\n", d1);
printf("1.23e-4: %f\n", sci1);
printf("5.67e+6: %f\n", sci2);
printf("8.9E2: %f\n", sci3);
printf("Hex float 0x1.2p3: %f\n", hex_float);
printf("\nSizes:\n");
printf("float constant size: %zu bytes\n", sizeof(3.14F));
printf("double constant size: %zu bytes\n", sizeof(3.14));
printf("long double constant size: %zu bytes\n", sizeof(3.14L));
return 0;
}
Character Constants
#include <stdio.h>
int main() {
// Regular character
char ch1 = 'A';
char ch2 = '5';
char ch3 = '$';
// Escape sequences
char newline = '\n';
char tab = '\t';
char backspace = '\b';
char carriage = '\r';
char formfeed = '\f';
char backslash = '\\';
char single_quote = '\'';
char double_quote = '\"';
char null_char = '\0';
// Octal and hexadecimal escape sequences
char octal = '\101'; // 'A' in octal
char hex = '\x41'; // 'A' in hexadecimal
printf("Characters: %c %c %c\n", ch1, ch2, ch3);
printf("Octal 101: %c\n", octal);
printf("Hex 41: %c\n", hex);
printf("Escape sequences:\n");
printf("Line 1%sLine 2\n", "\n"); // Newline
printf("Column1\tColumn2\tColumn3\n"); // Tabs
return 0;
}
String Constants
#include <stdio.h>
int main() {
// String literals
char *str1 = "Hello, World!";
char str2[] = "C Programming";
// Multi-line string
char *multi_line = "This is a "
"multi-line "
"string.";
// String with escape sequences
char *path = "C:\\Program Files\\MyApp";
char *message = "He said, \"Hello!\"";
// Wide string (C99)
wchar_t *wide_str = L"Wide string";
printf("str1: %s\n", str1);
printf("str2: %s\n", str2);
printf("multi_line: %s\n", multi_line);
printf("path: %s\n", path);
printf("message: %s\n", message);
printf("\nString literal concatenation:\n");
printf("This " "is " "one " "string.\n");
return 0;
}
Symbolic Constants
Using #define Preprocessor
#include <stdio.h>
// Simple constant definitions
#define PI 3.14159
#define MAX_SIZE 100
#define NAME "C Programming"
// Mathematical constants
#define E 2.71828
#define GOLDEN_RATIO 1.61803
// Configuration constants
#define BUFFER_SIZE 1024
#define TIMEOUT_MS 5000
#define DEBUG_MODE 1
// Bit masks
#define FLAG_READ 0x01
#define FLAG_WRITE 0x02
#define FLAG_EXEC 0x04
// Macro-like constants (can have parameters)
#define SQUARE(x) ((x) * (x))
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MIN(a,b) ((a) < (b) ? (a) : (b))
int main() {
printf("PI: %f\n", PI);
printf("MAX_SIZE: %d\n", MAX_SIZE);
printf("NAME: %s\n", NAME);
printf("E: %f\n", E);
printf("\nBit masks:\n");
printf("FLAG_READ: 0x%02X\n", FLAG_READ);
printf("FLAG_WRITE: 0x%02X\n", FLAG_WRITE);
printf("FLAG_EXEC: 0x%02X\n", FLAG_EXEC);
printf("\nMacros:\n");
printf("SQUARE(5): %d\n", SQUARE(5));
printf("MAX(10, 20): %d\n", MAX(10, 20));
printf("MIN(3.14, 2.72): %f\n", MIN(3.14, 2.72));
#ifdef DEBUG_MODE
printf("\nDebug mode is ON\n");
#endif
return 0;
}
Using const Keyword
#include <stdio.h>
// Global constants
const double PI = 3.141592653589793;
const int MAX_USERS = 1000;
const char* APP_NAME = "MyApplication";
// const with different types
const int array[] = {1, 2, 3, 4, 5};
const float rates[] = {1.2, 2.3, 3.4, 4.5};
// Pointer to const
const int* ptr_to_const; // pointer to constant int
int* const const_ptr = NULL; // constant pointer to int
const int* const const_ptr_to_const = NULL; // constant pointer to constant int
int main() {
// Local constants
const int local_max = 50;
const float tax_rate = 0.15;
printf("PI: %f\n", PI);
printf("MAX_USERS: %d\n", MAX_USERS);
printf("APP_NAME: %s\n", APP_NAME);
printf("local_max: %d\n", local_max);
printf("tax_rate: %.2f\n", tax_rate);
// Using const arrays
printf("\nConst array: ");
for (int i = 0; i < 5; i++) {
printf("%d ", array[i]);
}
printf("\n");
// Cannot modify const variables
// PI = 3.14; // Error!
// local_max = 100; // Error!
// array[0] = 10; // Error!
// Demonstrating pointer to const
int value = 42;
ptr_to_const = &value;
// *ptr_to_const = 100; // Error! Can't modify through pointer
return 0;
}
const vs #define Comparison
#include <stdio.h>
// #define - preprocessor, no type checking, no memory allocation
#define MAX_SIZE 100
#define MULTIPLY(a,b) ((a)*(b))
// const - compiler, type checking, memory allocated
const int max_size = 100;
int main() {
printf("=== #define vs const ===\n\n");
// #define advantages:
// 1. No memory allocation
// 2. Can be used in preprocessor directives
printf("#define MAX_SIZE: %d\n", MAX_SIZE);
printf("#define MULTIPLY(5,3): %d\n", MULTIPLY(5, 3));
// const advantages:
// 1. Type checking
// 2. Scope control
// 3. Can be used with pointers
printf("const max_size: %d\n", max_size);
printf("Size of const variable: %zu bytes\n", sizeof(max_size));
// const with pointer
const int *p = &max_size;
printf("const pointer value: %d\n", *p);
// #define limitations
// #define VALUE 10 + 20
// int result = VALUE * 2; // 10 + 20 * 2 = 50, not 60
return 0;
}
Enumeration Constants
Basic Enum
#include <stdio.h>
// Simple enum
enum Weekday {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
};
// Enum with explicit values
enum Status {
STATUS_OK = 0,
STATUS_ERROR = -1,
STATUS_NOT_FOUND = 404,
STATUS_FORBIDDEN = 403
};
// Enum with bitmask values
enum Permissions {
PERM_NONE = 0,
PERM_READ = 1 << 0, // 1
PERM_WRITE = 1 << 1, // 2
PERM_EXEC = 1 << 2, // 4
PERM_DELETE = 1 << 3, // 8
PERM_ALL = 15
};
int main() {
enum Weekday today = WEDNESDAY;
enum Status status = STATUS_OK;
enum Permissions user_perm = PERM_READ | PERM_WRITE;
printf("Today: %d (", today);
switch (today) {
case MONDAY: printf("Monday"); break;
case TUESDAY: printf("Tuesday"); break;
case WEDNESDAY: printf("Wednesday"); break;
case THURSDAY: printf("Thursday"); break;
case FRIDAY: printf("Friday"); break;
case SATURDAY: printf("Saturday"); break;
case SUNDAY: printf("Sunday"); break;
}
printf(")\n");
printf("Status: %d\n", status);
printf("\nPermissions: %d\n", user_perm);
if (user_perm & PERM_READ) printf(" Can read\n");
if (user_perm & PERM_WRITE) printf(" Can write\n");
if (user_perm & PERM_EXEC) printf(" Can execute\n");
if (user_perm & PERM_DELETE) printf(" Can delete\n");
return 0;
}
Typedef with Enum
#include <stdio.h>
// Using typedef with enum
typedef enum {
COLOR_RED,
COLOR_GREEN,
COLOR_BLUE,
COLOR_YELLOW,
COLOR_CYAN,
COLOR_MAGENTA
} Color;
typedef enum {
LOG_LEVEL_DEBUG,
LOG_LEVEL_INFO,
LOG_LEVEL_WARNING,
LOG_LEVEL_ERROR,
LOG_LEVEL_FATAL
} LogLevel;
void log_message(LogLevel level, const char* message) {
const char* level_names[] = {
"DEBUG", "INFO", "WARNING", "ERROR", "FATAL"
};
printf("[%s] %s\n", level_names[level], message);
}
int main() {
Color bg = COLOR_BLUE;
Color fg = COLOR_YELLOW;
printf("Background color: %d\n", bg);
printf("Foreground color: %d\n", fg);
log_message(LOG_LEVEL_INFO, "Application started");
log_message(LOG_LEVEL_DEBUG, "Processing data");
log_message(LOG_LEVEL_WARNING, "Low disk space");
log_message(LOG_LEVEL_ERROR, "File not found");
log_message(LOG_LEVEL_FATAL, "Out of memory");
return 0;
}
Constant Expressions
Compile-Time Constants
#include <stdio.h>
// Constant expressions - evaluated at compile time
#define ARRAY_SIZE (5 * 4) // 20
#define BUFFER_SIZE (ARRAY_SIZE + 10) // 30
// constexpr (C23) - compile-time constant expressions
// constexpr int MAX = 100; // C23 feature
int main() {
// Array size must be constant expression
int array[ARRAY_SIZE];
char buffer[BUFFER_SIZE];
// sizeof is a compile-time constant
const int int_size = sizeof(int);
const int array_size = sizeof(array);
printf("ARRAY_SIZE: %d\n", ARRAY_SIZE);
printf("BUFFER_SIZE: %d\n", BUFFER_SIZE);
printf("int_size: %d bytes\n", int_size);
printf("array_size: %d bytes\n", array_size);
printf("array elements: %d\n", (int)(sizeof(array) / sizeof(array[0])));
// Constant expressions can be used in case labels
const int CASE_VALUE = 42;
int value = 42;
switch (value) {
case CASE_VALUE:
printf("Value matches constant expression\n");
break;
default:
printf("No match\n");
}
return 0;
}
Constant Arrays and Strings
Constant Arrays
#include <stdio.h>
// Global constant arrays
const int days_in_month[] = {31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31};
const char* month_names[] = {
"January", "February", "March", "April",
"May", "June", "July", "August",
"September", "October", "November", "December"
};
// Constant 2D array
const int multiplication_table[5][5] = {
{1, 2, 3, 4, 5},
{2, 4, 6, 8, 10},
{3, 6, 9, 12, 15},
{4, 8, 12, 16, 20},
{5, 10, 15, 20, 25}
};
int main() {
printf("=== Months and Days ===\n");
for (int i = 0; i < 12; i++) {
printf("%-10s: %2d days\n", month_names[i], days_in_month[i]);
}
printf("\n=== Multiplication Table ===\n");
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
printf("%3d ", multiplication_table[i][j]);
}
printf("\n");
}
return 0;
}
Constant Strings
#include <stdio.h>
#include <string.h>
// String constants
const char* error_messages[] = {
"Success",
"File not found",
"Permission denied",
"Out of memory",
"Invalid parameter",
"Connection failed"
};
const char* help_text =
"Usage: program [options]\n"
"Options:\n"
" -h, --help Show this help\n"
" -v, --version Show version\n"
" -f, --file Input file\n";
int main() {
printf("=== Error Messages ===\n");
for (int i = 0; i < 6; i++) {
printf("Error %d: %s\n", i, error_messages[i]);
}
printf("\n=== Help Text ===\n");
printf("%s", help_text);
// String literals are constant
char *str1 = "Hello"; // Points to string literal (read-only)
const char *str2 = "World"; // Better: explicit const
// str1[0] = 'h'; // Undefined behavior! String literal may be read-only
return 0;
}
Constant Pointers
Pointer to Constant vs Constant Pointer
#include <stdio.h>
int main() {
int a = 10, b = 20;
int c = 30, d = 40;
// 1. Pointer to constant int (data is constant)
const int *p1 = &a;
// *p1 = 100; // Error: can't modify through p1
p1 = &b; // OK: can change pointer
// 2. Constant pointer to int (pointer is constant)
int * const p2 = &c;
*p2 = 300; // OK: can modify data
// p2 = &d; // Error: can't change pointer
// 3. Constant pointer to constant int (both constant)
const int * const p3 = &a;
// *p3 = 100; // Error: can't modify data
// p3 = &b; // Error: can't change pointer
printf("p1: %d (points to %d)\n", *p1, a);
printf("p2: %d\n", *p2);
printf("p3: %d\n", *p3);
// Demonstrating usage in functions
void print_array(const int *arr, int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]); // Can read, but not modify
}
printf("\n");
}
int numbers[] = {1, 2, 3, 4, 5};
print_array(numbers, 5);
return 0;
}
Constant Parameters and Return Values
const in Functions
#include <stdio.h>
#include <string.h>
// const parameters
int string_length(const char *str) {
// str is a pointer to constant char
// Can't modify the string content
int len = 0;
while (*str++) {
len++;
}
return len;
}
// const in function that doesn't modify data
void print_message(const char *msg) {
printf("Message: %s\n", msg);
}
// Returning const pointer
const char* get_error_message(int error_code) {
static const char* errors[] = {
"No error",
"File error",
"Memory error"
};
if (error_code >= 0 && error_code < 3) {
return errors[error_code];
}
return "Unknown error";
}
// Returning const data (by value)
const int get_pi() {
return 3; // Truncated, but const is meaningless for return by value
}
int main() {
char str[] = "Hello, World!";
const char *msg = "Test message";
printf("Length of '%s': %d\n", str, string_length(str));
print_message(msg);
const char *err = get_error_message(1);
printf("Error: %s\n", err);
// err[0] = 'X'; // Error: can't modify const data
return 0;
}
Compound Literal Constants (C99)
#include <stdio.h>
// Compound literals - create unnamed constants on the fly
typedef struct {
int x;
int y;
} Point;
void print_point(const Point *p) {
printf("(%d, %d)\n", p->x, p->y);
}
int main() {
// Integer array compound literal
int *arr = (int[]){1, 2, 3, 4, 5};
printf("Compound literal array: ");
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
printf("\n");
// Structure compound literal
Point *p = &(Point){10, 20};
print_point(p);
// Inline compound literal
print_point(&(Point){30, 40});
// Array of structures
Point *points = (Point[]){
{1, 1}, {2, 4}, {3, 9}, {4, 16}
};
printf("\nPoints:\n");
for (int i = 0; i < 4; i++) {
print_point(&points[i]);
}
return 0;
}
Constants in Header Files
constants.h
#ifndef CONSTANTS_H
#define CONSTANTS_H
// Mathematical constants
#define PI 3.141592653589793
#define E 2.718281828459045
#define GOLDEN_RATIO 1.618033988749895
// Physical constants
#define SPEED_OF_LIGHT 299792458.0 // m/s
#define PLANCK_CONSTANT 6.62607015e-34 // J⋅s
#define GRAVITATIONAL_CONSTANT 6.67430e-11 // m³/kg/s²
// Application constants
#define MAX_PATH_LENGTH 4096
#define MAX_BUFFER_SIZE 8192
#define DEFAULT_TIMEOUT 30 // seconds
// Error codes
typedef enum {
ERR_SUCCESS = 0,
ERR_NOT_FOUND = -1,
ERR_PERMISSION = -2,
ERR_INVALID_PARAM = -3,
ERR_OUT_OF_MEMORY = -4
} ErrorCode;
// Bit flags
#define FLAG_NONE 0x00
#define FLAG_READ 0x01
#define FLAG_WRITE 0x02
#define FLAG_EXEC 0x04
#define FLAG_ALL 0x07
// Inline function (const-like behavior)
static inline int min(int a, int b) {
return a < b ? a : b;
}
static inline int max(int a, int b) {
return a > b ? a : b;
}
#endif
main.c
#include <stdio.h>
#include "constants.h"
int main() {
printf("=== Mathematical Constants ===\n");
printf("PI: %.15f\n", PI);
printf("E: %.15f\n", E);
printf("Golden Ratio: %.15f\n", GOLDEN_RATIO);
printf("\n=== Physical Constants ===\n");
printf("Speed of Light: %.0f m/s\n", SPEED_OF_LIGHT);
printf("Planck Constant: %.2e J⋅s\n", PLANCK_CONSTANT);
printf("\n=== Application Constants ===\n");
printf("Max Path Length: %d\n", MAX_PATH_LENGTH);
printf("Default Timeout: %d seconds\n", DEFAULT_TIMEOUT);
printf("\n=== Error Codes ===\n");
printf("ERR_SUCCESS: %d\n", ERR_SUCCESS);
printf("ERR_NOT_FOUND: %d\n", ERR_NOT_FOUND);
printf("\n=== Bit Flags ===\n");
printf("FLAG_READ: 0x%02X\n", FLAG_READ);
printf("FLAG_WRITE: 0x%02X\n", FLAG_WRITE);
printf("FLAG_EXEC: 0x%02X\n", FLAG_EXEC);
printf("\n=== Inline Functions ===\n");
printf("min(10, 20): %d\n", min(10, 20));
printf("max(3.14, 2.72): %d\n", max(3.14, 2.72)); // Note: int version
return 0;
}
Constant Comparison Table
| Type | Syntax | Evaluation | Type Safety | Memory | Scope |
|---|---|---|---|---|---|
| Literal | 42 | Compile-time | No | None | Any |
#define | #define MAX 100 | Preprocessor | No | None | Global |
const | const int max = 100; | Run-time | Yes | Yes | Block |
enum | enum {MAX=100}; | Compile-time | Limited | None | Global |
constexpr (C23) | constexpr int max = 100; | Compile-time | Yes | Maybe | Block |
Best Practices
Do's and Don'ts
// DO: Use const for values that shouldn't change
const double PI = 3.14159;
const int MAX_USERS = 1000;
// DO: Use enum for related constants
typedef enum {
HTTP_OK = 200,
HTTP_NOT_FOUND = 404,
HTTP_ERROR = 500
} HttpStatus;
// DO: Use const in function parameters
void process_data(const int *data, size_t size);
// DO: Use #define for preprocessor conditions
#ifdef DEBUG
#define LOG(msg) printf("DEBUG: %s\n", msg)
#else
#define LOG(msg)
#endif
// DO: Use compound literals for temporary constants
draw_point(&(Point){10, 20});
// DON'T: Use magic numbers
if (temperature > 32) { // What is 32?
// ...
}
// DO: Use named constants
const int FREEZING_POINT_F = 32;
if (temperature > FREEZING_POINT_F) {
// ...
}
// DON'T: Modify const variables (will cause errors)
const int value = 10;
// value = 20; // Error!
// DON'T: Use #define for type-specific constants
#define PI 3.14159 // OK, but consider const double
// DON'T: Forget const for read-only parameters
void bad_function(char *str) { // Should be const char*
printf("%s\n", str);
}
// DO: Use const for read-only parameters
void good_function(const char *str) {
printf("%s\n", str);
}
Common Pitfalls
1. Modifying String Literals
#include <stdio.h>
int main() {
// BAD: Attempting to modify string literal
char *str = "Hello";
// str[0] = 'h'; // Undefined behavior! May crash
// GOOD: Use array for modifiable string
char arr[] = "Hello";
arr[0] = 'h'; // OK
printf("%s\n", arr);
return 0;
}
2. const and Pointers Confusion
#include <stdio.h>
int main() {
int x = 10, y = 20;
// Confusing declarations
const int *p1 = &x; // pointer to const int
int const *p2 = &x; // same as above
int * const p3 = &x; // const pointer to int
const int * const p4 = &x; // const pointer to const int
// *p1 = 100; // Error
p1 = &y; // OK
*p3 = 100; // OK
// p3 = &y; // Error
return 0;
}
3. enum Size and Type
#include <stdio.h>
enum Small {
SMALL_VALUE = 255 // Fits in char
};
enum Large {
LARGE_VALUE = 100000 // May need int
};
int main() {
printf("Size of enum Small: %zu bytes\n", sizeof(enum Small));
printf("Size of enum Large: %zu bytes\n", sizeof(enum Large));
// enum underlying type is implementation-defined
// Usually int, but can be smaller
return 0;
}
Performance Considerations
#include <stdio.h>
#include <time.h>
#define LOOP_COUNT 10000000
int main() {
clock_t start, end;
// Using literal constant
start = clock();
for (int i = 0; i < LOOP_COUNT; i++) {
int x = 100; // Constant
}
end = clock();
printf("Literal constant: %ld ticks\n", end - start);
// Using const variable
const int VALUE = 100;
start = clock();
for (int i = 0; i < LOOP_COUNT; i++) {
int x = VALUE; // May be optimized
}
end = clock();
printf("const variable: %ld ticks\n", end - start);
// Using #define
#define DEF_VALUE 100
start = clock();
for (int i = 0; i < LOOP_COUNT; i++) {
int x = DEF_VALUE; // Preprocessor substitution
}
end = clock();
printf("#define constant: %ld ticks\n", end - start);
return 0;
}
Summary Table
| Constant Type | Example | Storage | Type Safety | Modifiable | Best Use |
|---|---|---|---|---|---|
| Integer literal | 42 | None | No | No | Quick values |
| Float literal | 3.14 | None | No | No | Math constants |
| Character literal | 'A' | None | No | No | Single chars |
| String literal | "Hello" | Static | No | No | Fixed messages |
#define | #define MAX 100 | None | No | No | Configuration |
const variable | const int x = 5; | Stack/Data | Yes | No | Local constants |
const global | const double PI; | Data | Yes | No | Global constants |
enum | enum {RED, GREEN}; | None | Limited | No | Related constants |
const array | const int arr[5]; | Data | Yes | No | Lookup tables |
const pointer | const int* p; | Stack | Yes | Pointer only | Function params |
Conclusion
Constants are fundamental to C programming:
Key Takeaways
- Literals are the simplest form of constants
#definecreates preprocessor constants (no type checking)constcreates typed constants (type checking, memory allocated)enumcreates a set of related integer constants- Constant pointers protect data from modification
- Compound literals create temporary constants
Choosing the Right Constant
- Use
constfor most constants (type safety) - Use
#definefor preprocessor conditions and simple values - Use
enumfor related sets of integer constants - Use literals for obvious, self-explanatory values
- Use compound literals for temporary structures
Benefits of Using Constants
- Readability: Named constants are self-documenting
- Maintainability: Change in one place
- Type safety: Compiler catches errors
- Optimization: Compiler can optimize better
- Prevents bugs: Can't accidentally modify
Constants make code more robust, maintainable, and self-documenting. They are essential for professional C programming.