c
examples
examples.c🔧c
/**
* =============================================================================
* Header Files and Include Guards in C - Examples
* =============================================================================
*
* This file demonstrates header file concepts and include guards.
* For a complete example, we'll simulate a multi-file project in a single file.
*
* In a real project, these would be separate .h and .c files.
*
* Compile: gcc -Wall -Wextra -std=c99 -o examples examples.c -lm
* Run: ./examples
*
* Topics Covered:
* 1. Include guard pattern
* 2. Header file organization
* 3. Forward declarations
* 4. Opaque pointers
* 5. Inline functions in headers
* 6. C++ compatibility
* =============================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
// =============================================================================
// Example 1: Basic Include Guard Pattern
// =============================================================================
/*
* This is how you would write a header file with include guards:
*
* File: math_utils.h
*/
// --- BEGIN math_utils.h ---
#ifndef MATH_UTILS_H
#define MATH_UTILS_H
// Constants
#define MATH_PI 3.14159265359
#define MATH_E 2.71828182845
// Type definitions
typedef struct {
double x;
double y;
} Point2D;
typedef struct {
double x;
double y;
double z;
} Point3D;
// Function prototypes
double math_distance_2d(Point2D a, Point2D b);
double math_distance_3d(Point3D a, Point3D b);
double math_area_circle(double radius);
double math_area_triangle(double base, double height);
#endif /* MATH_UTILS_H */
// --- END math_utils.h ---
/*
* File: math_utils.c (implementation)
*/
// #include "math_utils.h" // Would include the header
double math_distance_2d(Point2D a, Point2D b) {
double dx = b.x - a.x;
double dy = b.y - a.y;
return sqrt(dx * dx + dy * dy);
}
double math_distance_3d(Point3D a, Point3D b) {
double dx = b.x - a.x;
double dy = b.y - a.y;
double dz = b.z - a.z;
return sqrt(dx * dx + dy * dy + dz * dz);
}
double math_area_circle(double radius) {
return MATH_PI * radius * radius;
}
double math_area_triangle(double base, double height) {
return 0.5 * base * height;
}
void example_include_guards(void) {
printf("\n=== Example 1: Basic Include Guard Pattern ===\n");
Point2D p1 = {0.0, 0.0};
Point2D p2 = {3.0, 4.0};
printf("Point 1: (%.1f, %.1f)\n", p1.x, p1.y);
printf("Point 2: (%.1f, %.1f)\n", p2.x, p2.y);
printf("Distance: %.2f\n", math_distance_2d(p1, p2));
printf("\n");
double radius = 5.0;
printf("Circle with radius %.1f:\n", radius);
printf(" Area: %.4f\n", math_area_circle(radius));
printf(" (using PI = %.10f)\n", MATH_PI);
}
// =============================================================================
// Example 2: Multiple Inclusion Prevention Demo
// =============================================================================
/*
* Without include guards, including a header twice would cause errors.
*
* Simulating the scenario:
* - a.h defines struct Color
* - b.h includes a.h and uses Color
* - main.c includes both a.h and b.h
*
* Without guards: Error - Color redefined!
* With guards: Works correctly - Color defined only once
*/
// --- BEGIN color.h (with guards) ---
#ifndef COLOR_H
#define COLOR_H
typedef struct {
uint8_t r, g, b, a;
} Color;
#define COLOR_RED ((Color){255, 0, 0, 255})
#define COLOR_GREEN ((Color){0, 255, 0, 255})
#define COLOR_BLUE ((Color){0, 0, 255, 255})
#define COLOR_WHITE ((Color){255, 255, 255, 255})
#define COLOR_BLACK ((Color){0, 0, 0, 255})
Color color_blend(Color c1, Color c2);
void color_print(Color c);
#endif /* COLOR_H */
// --- END color.h ---
// --- BEGIN graphics.h ---
#ifndef GRAPHICS_H
#define GRAPHICS_H
// Including color.h again is safe due to include guards
// #include "color.h" // This would be here in real code
void graphics_draw_pixel(int x, int y, Color c);
void graphics_fill_rect(int x, int y, int w, int h, Color c);
#endif /* GRAPHICS_H */
// --- END graphics.h ---
Color color_blend(Color c1, Color c2) {
Color result;
result.r = (c1.r + c2.r) / 2;
result.g = (c1.g + c2.g) / 2;
result.b = (c1.b + c2.b) / 2;
result.a = (c1.a + c2.a) / 2;
return result;
}
void color_print(Color c) {
printf("Color(R=%d, G=%d, B=%d, A=%d)", c.r, c.g, c.b, c.a);
}
void graphics_draw_pixel(int x, int y, Color c) {
printf("Drawing pixel at (%d, %d) with ", x, y);
color_print(c);
printf("\n");
}
void graphics_fill_rect(int x, int y, int w, int h, Color c) {
printf("Filling rect at (%d, %d) size %dx%d with ", x, y, w, h);
color_print(c);
printf("\n");
}
void example_multiple_inclusion(void) {
printf("\n=== Example 2: Multiple Inclusion Prevention ===\n");
Color red = COLOR_RED;
Color blue = COLOR_BLUE;
printf("Red: ");
color_print(red);
printf("\nBlue: ");
color_print(blue);
printf("\n");
Color purple = color_blend(red, blue);
printf("Blended (purple): ");
color_print(purple);
printf("\n\n");
graphics_draw_pixel(10, 20, red);
graphics_fill_rect(0, 0, 100, 50, blue);
}
// =============================================================================
// Example 3: Forward Declarations
// =============================================================================
/*
* Forward declarations let you declare a type without fully defining it.
* This is useful for reducing header dependencies and handling circular references.
*/
// --- BEGIN node.h ---
#ifndef NODE_H
#define NODE_H
// Forward declaration - Tree is defined in tree.h
struct Tree;
typedef struct Node {
int value;
struct Node *left;
struct Node *right;
struct Tree *owner; // Only pointer, no full definition needed
} Node;
Node* node_create(int value);
void node_destroy(Node *node);
void node_print(Node *node);
#endif /* NODE_H */
// --- END node.h ---
// --- BEGIN tree.h ---
#ifndef TREE_H
#define TREE_H
// Now we include node.h because we need the full Node definition
// #include "node.h"
typedef struct Tree {
Node *root;
int size;
char name[32];
} Tree;
Tree* tree_create(const char *name);
void tree_destroy(Tree *tree);
void tree_insert(Tree *tree, int value);
void tree_print(Tree *tree);
#endif /* TREE_H */
// --- END tree.h ---
// Implementations
Node* node_create(int value) {
Node *node = malloc(sizeof(Node));
if (node) {
node->value = value;
node->left = NULL;
node->right = NULL;
node->owner = NULL;
}
return node;
}
void node_destroy(Node *node) {
if (node) {
node_destroy(node->left);
node_destroy(node->right);
free(node);
}
}
void node_print(Node *node) {
if (node) {
node_print(node->left);
printf("%d ", node->value);
node_print(node->right);
}
}
Tree* tree_create(const char *name) {
Tree *tree = malloc(sizeof(Tree));
if (tree) {
tree->root = NULL;
tree->size = 0;
strncpy(tree->name, name, sizeof(tree->name) - 1);
tree->name[sizeof(tree->name) - 1] = '\0';
}
return tree;
}
void tree_destroy(Tree *tree) {
if (tree) {
node_destroy(tree->root);
free(tree);
}
}
static void tree_insert_node(Tree *tree, Node **node, int value) {
if (*node == NULL) {
*node = node_create(value);
if (*node) {
(*node)->owner = tree;
tree->size++;
}
} else if (value < (*node)->value) {
tree_insert_node(tree, &(*node)->left, value);
} else {
tree_insert_node(tree, &(*node)->right, value);
}
}
void tree_insert(Tree *tree, int value) {
if (tree) {
tree_insert_node(tree, &tree->root, value);
}
}
void tree_print(Tree *tree) {
if (tree) {
printf("Tree '%s' (size=%d): ", tree->name, tree->size);
node_print(tree->root);
printf("\n");
}
}
void example_forward_declarations(void) {
printf("\n=== Example 3: Forward Declarations ===\n");
Tree *tree = tree_create("MyTree");
tree_insert(tree, 50);
tree_insert(tree, 30);
tree_insert(tree, 70);
tree_insert(tree, 20);
tree_insert(tree, 40);
tree_insert(tree, 60);
tree_insert(tree, 80);
tree_print(tree);
tree_destroy(tree);
}
// =============================================================================
// Example 4: Opaque Pointers (Pimpl Pattern)
// =============================================================================
/*
* Opaque pointers hide implementation details from users.
* The structure is declared but not defined in the header.
*/
// --- BEGIN database.h (public API) ---
#ifndef DATABASE_H
#define DATABASE_H
#include <stdbool.h>
// Opaque type - implementation is hidden
typedef struct Database Database;
// Result type for operations
typedef enum {
DB_OK = 0,
DB_ERROR_OPEN,
DB_ERROR_CLOSE,
DB_ERROR_QUERY,
DB_ERROR_NOT_FOUND
} DatabaseResult;
// Public API
Database* database_open(const char *filename);
void database_close(Database *db);
DatabaseResult database_query(Database *db, const char *query);
bool database_is_connected(const Database *db);
const char* database_error_string(DatabaseResult result);
#endif /* DATABASE_H */
// --- END database.h ---
// --- BEGIN database.c (private implementation) ---
// #include "database.h"
// Private structure definition - users can't access internal fields
struct Database {
char filename[256];
bool connected;
int query_count;
char last_error[128];
// ... more private fields
};
Database* database_open(const char *filename) {
Database *db = malloc(sizeof(Database));
if (db) {
strncpy(db->filename, filename, sizeof(db->filename) - 1);
db->filename[sizeof(db->filename) - 1] = '\0';
db->connected = true;
db->query_count = 0;
db->last_error[0] = '\0';
printf("[DB] Opened database: %s\n", filename);
}
return db;
}
void database_close(Database *db) {
if (db) {
printf("[DB] Closed database: %s (queries: %d)\n",
db->filename, db->query_count);
db->connected = false;
free(db);
}
}
DatabaseResult database_query(Database *db, const char *query) {
if (!db || !db->connected) {
return DB_ERROR_QUERY;
}
db->query_count++;
printf("[DB] Query %d: %s\n", db->query_count, query);
return DB_OK;
}
bool database_is_connected(const Database *db) {
return db && db->connected;
}
const char* database_error_string(DatabaseResult result) {
switch (result) {
case DB_OK: return "Success";
case DB_ERROR_OPEN: return "Failed to open database";
case DB_ERROR_CLOSE: return "Failed to close database";
case DB_ERROR_QUERY: return "Query failed";
case DB_ERROR_NOT_FOUND: return "Record not found";
default: return "Unknown error";
}
}
// --- END database.c ---
void example_opaque_pointers(void) {
printf("\n=== Example 4: Opaque Pointers (Pimpl Pattern) ===\n");
Database *db = database_open("users.db");
if (database_is_connected(db)) {
printf("Database connected: Yes\n\n");
DatabaseResult result;
result = database_query(db, "SELECT * FROM users");
printf("Result: %s\n", database_error_string(result));
result = database_query(db, "INSERT INTO users VALUES (1, 'Alice')");
printf("Result: %s\n", database_error_string(result));
}
printf("\n");
database_close(db);
printf("\nNote: Users cannot access db->filename or other internals!\n");
printf("This provides encapsulation and allows internal changes\n");
printf("without breaking the public API.\n");
}
// =============================================================================
// Example 5: Inline Functions in Headers
// =============================================================================
/*
* Small utility functions can be defined inline in headers.
* They should be marked 'static inline' to avoid multiple definition errors.
*/
// --- BEGIN inline_utils.h ---
#ifndef INLINE_UTILS_H
#define INLINE_UTILS_H
#include <stdlib.h>
#include <string.h>
// Inline min/max functions
static inline int inline_min(int a, int b) {
return (a < b) ? a : b;
}
static inline int inline_max(int a, int b) {
return (a > b) ? a : b;
}
static inline int inline_clamp(int value, int min_val, int max_val) {
return inline_min(inline_max(value, min_val), max_val);
}
// Inline string utilities
static inline bool inline_str_empty(const char *str) {
return str == NULL || *str == '\0';
}
static inline size_t inline_str_len(const char *str) {
return str ? strlen(str) : 0;
}
// Safe memory operations
static inline void* inline_safe_malloc(size_t size) {
void *ptr = malloc(size);
if (ptr == NULL && size > 0) {
fprintf(stderr, "Memory allocation failed!\n");
}
return ptr;
}
static inline void inline_safe_free(void **ptr) {
if (ptr && *ptr) {
free(*ptr);
*ptr = NULL;
}
}
// Bit manipulation
static inline bool inline_bit_get(uint32_t value, int bit) {
return (value >> bit) & 1;
}
static inline uint32_t inline_bit_set(uint32_t value, int bit) {
return value | (1 << bit);
}
static inline uint32_t inline_bit_clear(uint32_t value, int bit) {
return value & ~(1 << bit);
}
#endif /* INLINE_UTILS_H */
// --- END inline_utils.h ---
void example_inline_functions(void) {
printf("\n=== Example 5: Inline Functions in Headers ===\n");
// min/max/clamp
printf("inline_min(5, 3) = %d\n", inline_min(5, 3));
printf("inline_max(5, 3) = %d\n", inline_max(5, 3));
printf("inline_clamp(150, 0, 100) = %d\n", inline_clamp(150, 0, 100));
printf("\n");
// String utilities
const char *test1 = "Hello";
const char *test2 = "";
const char *test3 = NULL;
printf("inline_str_empty(\"%s\") = %s\n", test1, inline_str_empty(test1) ? "true" : "false");
printf("inline_str_empty(\"\") = %s\n", inline_str_empty(test2) ? "true" : "false");
printf("inline_str_empty(NULL) = %s\n", inline_str_empty(test3) ? "true" : "false");
printf("inline_str_len(\"%s\") = %zu\n", test1, inline_str_len(test1));
printf("\n");
// Bit manipulation
uint32_t value = 0b00001010; // 10 in decimal
printf("Original value: %u (0b%08b)\n", value, value);
printf("Bit 1 set: %s\n", inline_bit_get(value, 1) ? "yes" : "no");
printf("Bit 2 set: %s\n", inline_bit_get(value, 2) ? "yes" : "no");
printf("After setting bit 0: %u\n", inline_bit_set(value, 0));
printf("After clearing bit 1: %u\n", inline_bit_clear(value, 1));
}
// =============================================================================
// Example 6: C++ Compatibility
// =============================================================================
/*
* For headers that might be used from C++, wrap declarations in extern "C".
* This prevents C++ name mangling.
*/
// --- BEGIN c_api.h ---
#ifndef C_API_H
#define C_API_H
#ifdef __cplusplus
extern "C" {
#endif
// API version
#define C_API_VERSION_MAJOR 1
#define C_API_VERSION_MINOR 0
// Types
typedef struct {
int x, y;
} C_API_Point;
typedef struct {
int width, height;
} C_API_Size;
typedef struct {
C_API_Point origin;
C_API_Size size;
} C_API_Rect;
// Functions - these can be called from C++
C_API_Rect c_api_rect_create(int x, int y, int w, int h);
int c_api_rect_area(C_API_Rect rect);
bool c_api_rect_contains_point(C_API_Rect rect, C_API_Point point);
C_API_Rect c_api_rect_intersection(C_API_Rect a, C_API_Rect b);
#ifdef __cplusplus
}
#endif
#endif /* C_API_H */
// --- END c_api.h ---
// Implementation
C_API_Rect c_api_rect_create(int x, int y, int w, int h) {
C_API_Rect rect = {{x, y}, {w, h}};
return rect;
}
int c_api_rect_area(C_API_Rect rect) {
return rect.size.width * rect.size.height;
}
bool c_api_rect_contains_point(C_API_Rect rect, C_API_Point point) {
return point.x >= rect.origin.x &&
point.x < rect.origin.x + rect.size.width &&
point.y >= rect.origin.y &&
point.y < rect.origin.y + rect.size.height;
}
C_API_Rect c_api_rect_intersection(C_API_Rect a, C_API_Rect b) {
int x1 = inline_max(a.origin.x, b.origin.x);
int y1 = inline_max(a.origin.y, b.origin.y);
int x2 = inline_min(a.origin.x + a.size.width, b.origin.x + b.size.width);
int y2 = inline_min(a.origin.y + a.size.height, b.origin.y + b.size.height);
C_API_Rect result = {{0, 0}, {0, 0}};
if (x2 > x1 && y2 > y1) {
result.origin.x = x1;
result.origin.y = y1;
result.size.width = x2 - x1;
result.size.height = y2 - y1;
}
return result;
}
void example_cpp_compatibility(void) {
printf("\n=== Example 6: C++ Compatibility ===\n");
C_API_Rect rect1 = c_api_rect_create(0, 0, 100, 80);
C_API_Rect rect2 = c_api_rect_create(50, 40, 100, 80);
printf("Rectangle 1: origin=(%d,%d), size=%dx%d, area=%d\n",
rect1.origin.x, rect1.origin.y,
rect1.size.width, rect1.size.height,
c_api_rect_area(rect1));
printf("Rectangle 2: origin=(%d,%d), size=%dx%d, area=%d\n",
rect2.origin.x, rect2.origin.y,
rect2.size.width, rect2.size.height,
c_api_rect_area(rect2));
C_API_Point point = {75, 60};
printf("\nPoint (%d, %d):\n", point.x, point.y);
printf(" In rect1: %s\n", c_api_rect_contains_point(rect1, point) ? "Yes" : "No");
printf(" In rect2: %s\n", c_api_rect_contains_point(rect2, point) ? "Yes" : "No");
C_API_Rect intersection = c_api_rect_intersection(rect1, rect2);
printf("\nIntersection: origin=(%d,%d), size=%dx%d\n",
intersection.origin.x, intersection.origin.y,
intersection.size.width, intersection.size.height);
printf("\nNote: With 'extern \"C\"', these functions can be called\n");
printf("directly from C++ code without name mangling issues.\n");
}
// =============================================================================
// Example 7: Header Organization Patterns
// =============================================================================
/*
* Demonstrating common header organization patterns.
*/
// --- Pattern 1: Configuration Header ---
// config.h
#ifndef CONFIG_H
#define CONFIG_H
// Build configuration
#ifndef DEBUG
#define DEBUG 0
#endif
// Version info
#define APP_VERSION_MAJOR 2
#define APP_VERSION_MINOR 5
#define APP_VERSION_PATCH 1
#define APP_VERSION_STRING "2.5.1"
// Feature flags
#define FEATURE_LOGGING 1
#define FEATURE_NETWORKING 0
// Limits
#define MAX_BUFFER_SIZE 4096
#define MAX_FILENAME_LEN 256
#endif /* CONFIG_H */
// --- Pattern 2: Types Header ---
// types.h
#ifndef TYPES_H_EXAMPLE
#define TYPES_H_EXAMPLE
// Basic type aliases
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t i8;
typedef int16_t i16;
typedef int32_t i32;
typedef int64_t i64;
typedef float f32;
typedef double f64;
// Common result type
typedef enum {
RESULT_OK = 0,
RESULT_ERROR = -1,
RESULT_NOT_FOUND = -2,
RESULT_INVALID = -3
} Result;
#endif /* TYPES_H_EXAMPLE */
// --- Pattern 3: Error Handling Header ---
// error.h
#ifndef ERROR_H
#define ERROR_H
typedef enum {
ERR_NONE = 0,
ERR_MEMORY,
ERR_IO,
ERR_INVALID_ARG,
ERR_NOT_FOUND,
ERR_PERMISSION,
ERR_TIMEOUT,
ERR_UNKNOWN
} ErrorCode;
typedef struct {
ErrorCode code;
char message[256];
const char *file;
int line;
} Error;
#define ERROR_INIT ((Error){ERR_NONE, "", __FILE__, __LINE__})
static inline void error_set(Error *err, ErrorCode code, const char *msg) {
if (err) {
err->code = code;
strncpy(err->message, msg, sizeof(err->message) - 1);
err->message[sizeof(err->message) - 1] = '\0';
}
}
static inline bool error_ok(const Error *err) {
return err == NULL || err->code == ERR_NONE;
}
#endif /* ERROR_H */
void example_header_organization(void) {
printf("\n=== Example 7: Header Organization Patterns ===\n");
printf("Configuration (from config.h):\n");
printf(" Version: %s\n", APP_VERSION_STRING);
printf(" Debug: %s\n", DEBUG ? "Yes" : "No");
printf(" Max buffer: %d\n", MAX_BUFFER_SIZE);
printf("\n");
printf("Type aliases (from types.h):\n");
printf(" sizeof(u8) = %zu\n", sizeof(u8));
printf(" sizeof(u32) = %zu\n", sizeof(u32));
printf(" sizeof(f32) = %zu\n", sizeof(f32));
printf("\n");
printf("Error handling (from error.h):\n");
Error err = ERROR_INIT;
printf(" Initial error state: %s\n", error_ok(&err) ? "OK" : "Error");
error_set(&err, ERR_NOT_FOUND, "File not found");
printf(" After setting error: %s\n", error_ok(&err) ? "OK" : "Error");
printf(" Error message: %s\n", err.message);
}
// =============================================================================
// Example 8: Version Header Pattern
// =============================================================================
// --- version.h ---
#ifndef VERSION_H
#define VERSION_H
#define LIB_VERSION_MAJOR 3
#define LIB_VERSION_MINOR 2
#define LIB_VERSION_PATCH 1
#define LIB_VERSION_STRING "3.2.1"
// Compute version as a single number for comparisons
#define LIB_VERSION_NUMBER \
((LIB_VERSION_MAJOR * 10000) + (LIB_VERSION_MINOR * 100) + LIB_VERSION_PATCH)
// Version checking macro
#define LIB_VERSION_AT_LEAST(major, minor, patch) \
(LIB_VERSION_NUMBER >= ((major * 10000) + (minor * 100) + patch))
// Build information
#define LIB_BUILD_DATE __DATE__
#define LIB_BUILD_TIME __TIME__
// Feature availability based on version
#if LIB_VERSION_AT_LEAST(3, 0, 0)
#define LIB_HAS_NEW_API 1
#else
#define LIB_HAS_NEW_API 0
#endif
#if LIB_VERSION_AT_LEAST(3, 2, 0)
#define LIB_HAS_ASYNC 1
#else
#define LIB_HAS_ASYNC 0
#endif
typedef struct {
int major;
int minor;
int patch;
const char *string;
const char *build_date;
const char *build_time;
} LibVersion;
static inline LibVersion lib_get_version(void) {
LibVersion v = {
LIB_VERSION_MAJOR,
LIB_VERSION_MINOR,
LIB_VERSION_PATCH,
LIB_VERSION_STRING,
LIB_BUILD_DATE,
LIB_BUILD_TIME
};
return v;
}
#endif /* VERSION_H */
void example_version_header(void) {
printf("\n=== Example 8: Version Header Pattern ===\n");
LibVersion ver = lib_get_version();
printf("Library Version Information:\n");
printf(" Version: %s\n", ver.string);
printf(" Major: %d, Minor: %d, Patch: %d\n",
ver.major, ver.minor, ver.patch);
printf(" Build: %s %s\n", ver.build_date, ver.build_time);
printf(" Version number: %d\n", LIB_VERSION_NUMBER);
printf("\n");
printf("Feature availability:\n");
printf(" New API (3.0.0+): %s\n", LIB_HAS_NEW_API ? "Yes" : "No");
printf(" Async support (3.2.0+): %s\n", LIB_HAS_ASYNC ? "Yes" : "No");
printf("\n");
printf("Version checking:\n");
printf(" >= 2.0.0: %s\n", LIB_VERSION_AT_LEAST(2, 0, 0) ? "Yes" : "No");
printf(" >= 3.2.0: %s\n", LIB_VERSION_AT_LEAST(3, 2, 0) ? "Yes" : "No");
printf(" >= 4.0.0: %s\n", LIB_VERSION_AT_LEAST(4, 0, 0) ? "Yes" : "No");
}
// =============================================================================
// Example 9: Module with Private Header
// =============================================================================
/*
* Large modules often have a public header and a private/internal header.
* The private header is only included by the module's implementation files.
*/
// --- BEGIN string_buffer.h (PUBLIC) ---
#ifndef STRING_BUFFER_H
#define STRING_BUFFER_H
#include <stddef.h>
// Opaque type
typedef struct StringBuffer StringBuffer;
// Public API
StringBuffer* strbuf_create(size_t initial_capacity);
void strbuf_destroy(StringBuffer *sb);
void strbuf_append(StringBuffer *sb, const char *str);
void strbuf_append_char(StringBuffer *sb, char c);
void strbuf_clear(StringBuffer *sb);
const char* strbuf_get(const StringBuffer *sb);
size_t strbuf_length(const StringBuffer *sb);
#endif /* STRING_BUFFER_H */
// --- END string_buffer.h ---
// --- BEGIN string_buffer_internal.h (PRIVATE) ---
#ifndef STRING_BUFFER_INTERNAL_H
#define STRING_BUFFER_INTERNAL_H
// Include public header
// #include "string_buffer.h"
// Private structure definition
struct StringBuffer {
char *data;
size_t length;
size_t capacity;
};
// Private helper functions
static inline bool strbuf_grow(StringBuffer *sb, size_t needed) {
if (sb->length + needed < sb->capacity) {
return true;
}
size_t new_capacity = sb->capacity * 2;
while (new_capacity < sb->length + needed) {
new_capacity *= 2;
}
char *new_data = realloc(sb->data, new_capacity);
if (new_data == NULL) {
return false;
}
sb->data = new_data;
sb->capacity = new_capacity;
return true;
}
#endif /* STRING_BUFFER_INTERNAL_H */
// --- END string_buffer_internal.h ---
// Implementation (would be in string_buffer.c)
// #include "string_buffer_internal.h"
StringBuffer* strbuf_create(size_t initial_capacity) {
StringBuffer *sb = malloc(sizeof(StringBuffer));
if (sb == NULL) return NULL;
size_t cap = (initial_capacity > 0) ? initial_capacity : 16;
sb->data = malloc(cap);
if (sb->data == NULL) {
free(sb);
return NULL;
}
sb->data[0] = '\0';
sb->length = 0;
sb->capacity = cap;
return sb;
}
void strbuf_destroy(StringBuffer *sb) {
if (sb) {
free(sb->data);
free(sb);
}
}
void strbuf_append(StringBuffer *sb, const char *str) {
if (sb == NULL || str == NULL) return;
size_t len = strlen(str);
if (!strbuf_grow(sb, len + 1)) return;
strcpy(sb->data + sb->length, str);
sb->length += len;
}
void strbuf_append_char(StringBuffer *sb, char c) {
if (sb == NULL) return;
if (!strbuf_grow(sb, 2)) return;
sb->data[sb->length++] = c;
sb->data[sb->length] = '\0';
}
void strbuf_clear(StringBuffer *sb) {
if (sb) {
sb->data[0] = '\0';
sb->length = 0;
}
}
const char* strbuf_get(const StringBuffer *sb) {
return sb ? sb->data : "";
}
size_t strbuf_length(const StringBuffer *sb) {
return sb ? sb->length : 0;
}
void example_private_header(void) {
printf("\n=== Example 9: Module with Private Header ===\n");
StringBuffer *sb = strbuf_create(0);
strbuf_append(sb, "Hello");
strbuf_append(sb, ", ");
strbuf_append(sb, "World");
strbuf_append_char(sb, '!');
printf("String: \"%s\"\n", strbuf_get(sb));
printf("Length: %zu\n", strbuf_length(sb));
strbuf_clear(sb);
strbuf_append(sb, "Cleared and new content");
printf("After clear: \"%s\"\n", strbuf_get(sb));
strbuf_destroy(sb);
printf("\nNote: The internal structure and helper functions\n");
printf("are hidden from users of the public API.\n");
}
// =============================================================================
// Main Function
// =============================================================================
int main(void) {
printf("============================================================\n");
printf(" HEADER FILES AND INCLUDE GUARDS IN C - EXAMPLES \n");
printf("============================================================\n");
example_include_guards();
example_multiple_inclusion();
example_forward_declarations();
example_opaque_pointers();
example_inline_functions();
example_cpp_compatibility();
example_header_organization();
example_version_header();
example_private_header();
printf("\n============================================================\n");
printf(" ALL EXAMPLES COMPLETED \n");
printf("============================================================\n");
return 0;
}