String Formatting in C: Complete Guide

Introduction to String Formatting

String formatting in C is the process of creating formatted strings using various functions from the standard library. It's essential for output, logging, data serialization, and creating human-readable representations of data.


String Formatting Architecture Overview

String Formatting System
├── Format Specifiers
│   ├── %d - Integers
│   ├── %f - Floating point
│   ├── %s - Strings
│   ├── %c - Characters
│   └── %p - Pointers
├── Formatting Functions
│   ├── printf() - Print to stdout
│   ├── fprintf() - Print to file
│   ├── sprintf() - Print to string
│   ├── snprintf() - Safe string print
│   └── asprintf() - Allocate and print
└── Format Modifiers
├── Width and precision
├── Left/right alignment
├── Zero padding
└── Sign handling

Basic printf() Formatting

1. Basic Format Specifiers

#include <stdio.h>
int main() {
int integer = 42;
float floating = 3.14159;
double double_val = 2.71828;
char character = 'A';
char string[] = "Hello, World!";
void* pointer = &integer;
printf("=== Basic Format Specifiers ===\n\n");
printf("Integer (%%d): %d\n", integer);
printf("Integer (%%i): %i\n", integer);
printf("Unsigned (%%u): %u\n", integer);
printf("Hexadecimal (%%x): %x\n", integer);
printf("Hexadecimal (%%X): %X\n", integer);
printf("Octal (%%o): %o\n", integer);
printf("\nFloating point (%%f): %f\n", floating);
printf("Floating point (%%F): %F\n", floating);
printf("Scientific (%%e): %e\n", floating);
printf("Scientific (%%E): %E\n", floating);
printf("Shortest (%%g): %g\n", floating);
printf("Shortest (%%G): %G\n", floating);
printf("\nDouble (%%lf): %lf\n", double_val);
printf("\nCharacter (%%c): %c\n", character);
printf("String (%%s): %s\n", string);
printf("\nPointer (%%p): %p\n", pointer);
printf("Percent sign: %%\n");
return 0;
}

Output:

=== Basic Format Specifiers ===
Integer (%d): 42
Integer (%i): 42
Unsigned (%u): 42
Hexadecimal (%x): 2a
Hexadecimal (%X): 2A
Octal (%o): 52
Floating point (%f): 3.141590
Floating point (%F): 3.141590
Scientific (%e): 3.141590e+00
Scientific (%E): 3.141590E+00
Shortest (%g): 3.14159
Shortest (%G): 3.14159
Double (%lf): 2.718280
Character (%c): A
String (%s): Hello, World!
Pointer (%p): 0x7ffc12345678
Percent sign: %

2. Format Modifiers

#include <stdio.h>
int main() {
int num = 42;
float pi = 3.14159;
char text[] = "Hello";
printf("=== Format Modifiers ===\n\n");
// Width specification
printf("Width modifiers:\n");
printf("[%5d]\n", num);      // Right align, width 5
printf("[%-5d]\n", num);     // Left align, width 5
printf("[%05d]\n", num);     // Zero pad, width 5
printf("[%+5d]\n", num);     // Show sign, width 5
printf("[% d]\n", num);      // Space for positive numbers
printf("\nPrecision modifiers:\n");
printf("[%.2f]\n", pi);       // 2 decimal places
printf("[%.5f]\n", pi);       // 5 decimal places
printf("[%8.2f]\n", pi);      // Width 8, 2 decimals
printf("[%08.2f]\n", pi);     // Zero pad, width 8, 2 decimals
printf("\nString modifiers:\n");
printf("[%10s]\n", text);     // Right align, width 10
printf("[%-10s]\n", text);    // Left align, width 10
printf("[%.3s]\n", text);     // First 3 characters
printf("[%10.3s]\n", text);   // Width 10, first 3 chars
printf("\nCombined modifiers:\n");
printf("|%8d|%-8d|%08d|\n", 123, 123, 123);
printf("|%8.2f|%-8.2f|%08.2f|\n", pi, pi, pi);
return 0;
}

Output:

=== Format Modifiers ===
Width modifiers:
[   42]
[42   ]
[00042]
[  +42]
[ 42]
Precision modifiers:
[3.14]
[3.14159]
[    3.14]
[00003.14]
String modifiers:
[     Hello]
[Hello     ]
[Hel]
[       Hel]
Combined modifiers:
|     123|123     |00000123|
|    3.14|3.14    |00003.14|

String Formatting Functions

1. sprintf() - Format to String

#include <stdio.h>
int main() {
char buffer[100];
char name[] = "Alice";
int age = 25;
float height = 1.75;
// Format into buffer
int chars_written = sprintf(buffer, "Name: %s, Age: %d, Height: %.2f m", 
name, age, height);
printf("Formatted string: %s\n", buffer);
printf("Characters written: %d\n", chars_written);
// Multiple sprintf calls
char result[200] = "";
char temp[50];
sprintf(temp, "Name: %s\n", name);
strcat(result, temp);
sprintf(temp, "Age: %d\n", age);
strcat(result, temp);
sprintf(temp, "Height: %.2f\n", height);
strcat(result, temp);
printf("\nMulti-line result:\n%s", result);
return 0;
}

2. snprintf() - Safe String Formatting

#include <stdio.h>
int main() {
char buffer[20];
char long_text[] = "This is a very long string that won't fit";
printf("=== snprintf() - Buffer Overflow Protection ===\n\n");
// snprintf will truncate to fit buffer size
int needed = snprintf(buffer, sizeof(buffer), 
"Data: %s", long_text);
printf("Buffer size: %zu\n", sizeof(buffer));
printf("Buffer content: '%s'\n", buffer);
printf("Characters needed (would have written): %d\n", needed);
if (needed >= sizeof(buffer)) {
printf("Warning: Output was truncated!\n");
}
// Safe way to handle dynamic allocation
if (needed > 0) {
char* dynamic_buffer = malloc(needed + 1);
if (dynamic_buffer) {
sprintf(dynamic_buffer, "Data: %s", long_text);
printf("\nDynamic buffer (%d bytes): %s\n", 
needed + 1, dynamic_buffer);
free(dynamic_buffer);
}
}
return 0;
}

3. asprintf() - Allocating Formatted String (GNU extension)

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
int main() {
char* result;
char* name = "Bob";
int score = 95;
char grade = 'A';
// asprintf allocates exactly the right amount of memory
int chars = asprintf(&result, "Student: %s, Score: %d, Grade: %c",
name, score, grade);
if (chars >= 0) {
printf("Formatted string: %s\n", result);
printf("Length: %d\n", chars);
free(result);  // Must free when done
}
// Building complex strings
char* parts[] = {"Hello", "World", "from", "asprintf"};
char* message;
int total = asprintf(&message, "%s %s %s %s!", 
parts[0], parts[1], parts[2], parts[3]);
if (total >= 0) {
printf("\n%s\n", message);
free(message);
}
return 0;
}

Advanced Formatting Techniques

1. Dynamic Width and Precision

#include <stdio.h>
int main() {
int width = 10;
int precision = 3;
double value = 123.456789;
printf("=== Dynamic Width and Precision ===\n\n");
// Using * for dynamic width/precision
printf("Dynamic width (%d): [%*d]\n", width, width, 42);
printf("Dynamic precision (%d): [%.*f]\n", precision, precision, value);
printf("Dynamic both (%d,%d): [%*.*f]\n", 
width, precision, width, precision, value);
// Table formatting with dynamic widths
char* items[] = {"Apple", "Banana", "Cherry", "Date"};
int prices[] = {50, 35, 75, 120};
int quantities[] = {10, 20, 15, 8};
printf("\n%-*s %*s %*s %*s\n", 
10, "Item", 8, "Price", 10, "Quantity", 12, "Total");
for (int i = 0; i < 4; i++) {
int total = prices[i] * quantities[i];
printf("%-*s %*d %*d %*d\n",
10, items[i],
8, prices[i],
10, quantities[i],
12, total);
}
return 0;
}

Output:

=== Dynamic Width and Precision ===
Dynamic width (10): [        42]
Dynamic precision (3): [123.457]
Dynamic both (10,3): [   123.457]
Item          Price   Quantity       Total
Apple           50         10         500
Banana          35         20         700
Cherry          75         15        1125
Date           120          8         960

2. Field Width from Variable

#include <stdio.h>
int main() {
int data[] = {5, 50, 500, 5000, 50000};
int max_width = 0;
// Find maximum width needed
for (int i = 0; i < 5; i++) {
int width = snprintf(NULL, 0, "%d", data[i]);
if (width > max_width) max_width = width;
}
printf("=== Dynamic Column Widths ===\n");
printf("Maximum width needed: %d\n\n", max_width);
printf("%-*s %-*s %-*s\n", 
max_width, "Index",
max_width, "Value",
max_width, "Square");
for (int i = 0; i < 5; i++) {
printf("%-*d %-*d %-*d\n",
max_width, i,
max_width, data[i],
max_width, data[i] * data[i]);
}
return 0;
}

3. Scientific and Engineering Notation

#include <stdio.h>
#include <math.h>
int main() {
double numbers[] = {0.000123, 0.0123, 1.23, 123, 12300, 1230000};
printf("=== Scientific and Engineering Notation ===\n\n");
printf("%-15s %-15s %-15s %-15s\n", 
"Number", "Fixed", "Scientific", "Engineering");
for (int i = 0; i < 6; i++) {
double n = numbers[i];
printf("%-15g ", n);
printf("%-15.3f ", n);
printf("%-15.3e ", n);
// Engineering notation (power of 3 exponent)
int exp;
double mantissa = frexp(n, &exp);
exp = (exp - 1) / 3 * 3;
printf("%-15.3fe%+03d\n", n / pow(10, exp), exp);
}
return 0;
}

Formatting Different Data Types

1. Hexadecimal and Binary Formatting

#include <stdio.h>
void print_binary(unsigned int num) {
printf("0b");
for (int i = 31; i >= 0; i--) {
printf("%d", (num >> i) & 1);
if (i % 4 == 0 && i > 0) printf("_");
}
}
int main() {
unsigned int values[] = {0, 1, 42, 255, 1024, 0xABCD};
printf("=== Hexadecimal and Binary Formatting ===\n\n");
printf("%-10s %-12s %-12s %-35s\n", 
"Decimal", "Hex", "Octal", "Binary");
for (int i = 0; i < 6; i++) {
printf("%-10u ", values[i]);
printf("0x%-8X ", values[i]);
printf("%-10o ", values[i]);
print_binary(values[i]);
printf("\n");
}
// Memory address formatting
int x = 42;
int* ptr = &x;
printf("\nPointer formatting:\n");
printf("  %%p: %p\n", ptr);
printf("  %%#x: %#x\n", (unsigned long)ptr);
printf("  %%#X: %#X\n", (unsigned long)ptr);
return 0;
}

2. Date and Time Formatting

#include <stdio.h>
#include <time.h>
int main() {
time_t now = time(NULL);
struct tm* tm_info = localtime(&now);
char buffer[100];
printf("=== Date and Time Formatting ===\n\n");
// Manual formatting
printf("Manual: %04d-%02d-%02d %02d:%02d:%02d\n",
1900 + tm_info->tm_year,
tm_info->tm_mon + 1,
tm_info->tm_mday,
tm_info->tm_hour,
tm_info->tm_min,
tm_info->tm_sec);
// Using strftime
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_info);
printf("strftime: %s\n", buffer);
strftime(buffer, sizeof(buffer), "%A, %B %d, %Y", tm_info);
printf("Long date: %s\n", buffer);
strftime(buffer, sizeof(buffer), "%I:%M:%S %p", tm_info);
printf("12-hour time: %s\n", buffer);
// Custom formatting with leading zeros
printf("\nCustom formats:\n");
printf("  YYYYMMDD: %04d%02d%02d\n",
1900 + tm_info->tm_year,
tm_info->tm_mon + 1,
tm_info->tm_mday);
printf("  HHMMSS: %02d%02d%02d\n",
tm_info->tm_hour,
tm_info->tm_min,
tm_info->tm_sec);
return 0;
}

3. Currency Formatting

#include <stdio.h>
#include <locale.h>
int main() {
// Set locale for currency formatting
setlocale(LC_ALL, "en_US.UTF-8");
double amounts[] = {1234.56, 0.99, 1000000.00, -42.50};
char* currencies[] = {"USD", "EUR", "GBP", "JPY"};
printf("=== Currency Formatting ===\n\n");
printf("%-10s %-15s %-15s %-15s\n",
"Currency", "Amount", "Formatted", "Accounting");
for (int i = 0; i < 4; i++) {
double amt = amounts[i];
printf("%-10s ", currencies[i]);
printf("$%-14.2f ", amt);
// Standard formatting
if (amt >= 0) {
printf("$%'.2f        ", amt);
} else {
printf("($%'0.2f)      ", -amt);
}
// Accounting format
if (amt >= 0) {
printf(" %'10.2f ", amt);
} else {
printf("(%'9.2f) ", -amt);
}
printf("\n");
}
return 0;
}

Complex String Building

1. Building JSON Strings

#include <stdio.h>
#include <string.h>
typedef struct {
char name[50];
int age;
char city[50];
double salary;
} Person;
char* person_to_json(Person* p, char* buffer, size_t size) {
snprintf(buffer, size,
"{\n"
"  \"name\": \"%s\",\n"
"  \"age\": %d,\n"
"  \"city\": \"%s\",\n"
"  \"salary\": %.2f\n"
"}",
p->name, p->age, p->city, p->salary);
return buffer;
}
int main() {
Person people[] = {
{"Alice Smith", 30, "New York", 75000.00},
{"Bob Johnson", 25, "Los Angeles", 65000.50},
{"Charlie Brown", 35, "Chicago", 82000.75}
};
char buffer[500];
printf("=== JSON Formatting ===\n\n");
for (int i = 0; i < 3; i++) {
printf("%s\n", person_to_json(&people[i], buffer, sizeof(buffer)));
if (i < 2) printf("\n");
}
// Build JSON array
char json_array[2000] = "[\n";
for (int i = 0; i < 3; i++) {
person_to_json(&people[i], buffer, sizeof(buffer));
strcat(json_array, buffer);
if (i < 2) strcat(json_array, ",\n");
}
strcat(json_array, "\n]");
printf("\nJSON Array:\n%s\n", json_array);
return 0;
}

2. Building CSV Strings

#include <stdio.h>
#define MAX_FIELDS 10
typedef struct {
char* fields[MAX_FIELDS];
int field_count;
} CSVRecord;
char* csv_escape(char* dest, const char* src, size_t dest_size) {
int j = 0;
for (int i = 0; src[i] != '\0' && j < dest_size - 1; i++) {
if (src[i] == '"' || src[i] == ',' || src[i] == '\n') {
if (j < dest_size - 2) {
dest[j++] = '"';
dest[j++] = src[i];
dest[j++] = '"';
}
} else {
dest[j++] = src[i];
}
}
dest[j] = '\0';
return dest;
}
int main() {
CSVRecord records[] = {
{{"John Doe", "30", "New York", "75000"}, 4},
{{"Jane Smith", "28", "Los Angeles", "82000"}, 4},
{{"Bob \"The Builder\" Johnson", "35", "Chicago, IL", "65000"}, 4}
};
char buffer[256];
char escaped[256];
printf("=== CSV Formatting ===\n\n");
// Header
printf("Name,Age,City,Salary\n");
// Records
for (int i = 0; i < 3; i++) {
for (int j = 0; j < records[i].field_count; j++) {
csv_escape(escaped, records[i].fields[j], sizeof(escaped));
printf("%s", escaped);
if (j < records[i].field_count - 1) {
printf(",");
}
}
printf("\n");
}
return 0;
}

3. Building SQL Queries

#include <stdio.h>
#include <string.h>
typedef struct {
char column[50];
char value[100];
int is_string;
} QueryCondition;
void build_select_query(char* query, size_t size,
const char* table,
const char* columns[],
int col_count,
const QueryCondition* conditions,
int cond_count) {
char temp[1024];
int offset = 0;
// SELECT clause
offset += snprintf(query + offset, size - offset, "SELECT ");
for (int i = 0; i < col_count; i++) {
offset += snprintf(query + offset, size - offset, "%s",
columns[i]);
if (i < col_count - 1) {
offset += snprintf(query + offset, size - offset, ", ");
}
}
// FROM clause
offset += snprintf(query + offset, size - offset, " FROM %s", table);
// WHERE clause
if (cond_count > 0) {
offset += snprintf(query + offset, size - offset, " WHERE ");
for (int i = 0; i < cond_count; i++) {
if (conditions[i].is_string) {
offset += snprintf(query + offset, size - offset,
"%s = '%s'",
conditions[i].column,
conditions[i].value);
} else {
offset += snprintf(query + offset, size - offset,
"%s = %s",
conditions[i].column,
conditions[i].value);
}
if (i < cond_count - 1) {
offset += snprintf(query + offset, size - offset, " AND ");
}
}
}
offset += snprintf(query + offset, size - offset, ";");
}
int main() {
const char* columns[] = {"id", "name", "age", "city"};
QueryCondition conditions[] = {
{"age", "30", 0},
{"city", "New York", 1}
};
char query[1024];
build_select_query(query, sizeof(query),
"users",
columns, 4,
conditions, 2);
printf("=== SQL Query Building ===\n\n");
printf("Generated query:\n%s\n", query);
return 0;
}

Performance Optimization

1. Comparing Formatting Methods

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define ITERATIONS 1000000
#define BUFFER_SIZE 100
void benchmark_sprintf() {
char buffer[BUFFER_SIZE];
for (int i = 0; i < ITERATIONS; i++) {
sprintf(buffer, "Value: %d, Pi: %.2f", i, 3.14159);
}
}
void benchmark_snprintf() {
char buffer[BUFFER_SIZE];
for (int i = 0; i < ITERATIONS; i++) {
snprintf(buffer, BUFFER_SIZE, "Value: %d, Pi: %.2f", i, 3.14159);
}
}
void benchmark_asprintf() {
char* buffer;
for (int i = 0; i < ITERATIONS; i++) {
asprintf(&buffer, "Value: %d, Pi: %.2f", i, 3.14159);
free(buffer);
}
}
void benchmark_manual() {
char buffer[BUFFER_SIZE];
for (int i = 0; i < ITERATIONS; i++) {
char* p = buffer;
p += sprintf(p, "Value: ");
p += sprintf(p, "%d", i);
p += sprintf(p, ", Pi: ");
p += sprintf(p, "%.2f", 3.14159);
*p = '\0';
}
}
double measure_time(void (*func)()) {
clock_t start = clock();
func();
clock_t end = clock();
return ((double)(end - start)) / CLOCKS_PER_SEC;
}
int main() {
printf("=== Performance Comparison ===\n");
printf("Iterations: %d\n\n", ITERATIONS);
printf("sprintf():    %.3f seconds\n", measure_time(benchmark_sprintf));
printf("snprintf():   %.3f seconds\n", measure_time(benchmark_snprintf));
printf("asprintf():   %.3f seconds\n", measure_time(benchmark_asprintf));
printf("Manual concat: %.3f seconds\n", measure_time(benchmark_manual));
return 0;
}

2. Optimizing Repeated Formatting

#include <stdio.h>
// Pre-computed format string
const char* format_template = "User: %-20s | Age: %3d | Score: %6.2f\n";
void print_user(const char* name, int age, double score) {
printf(format_template, name, age, score);
}
int main() {
printf("=== Optimized Formatting ===\n\n");
// Using pre-computed format string
print_user("Alice", 25, 95.5);
print_user("Bob", 30, 87.3);
print_user("Charlie", 28, 91.8);
// Format string can be reused
char buffer[1000];
int pos = 0;
pos += sprintf(buffer + pos, "Data:\n");
for (int i = 0; i < 5; i++) {
pos += sprintf(buffer + pos, "  Item %d: %d\n", i, i * i);
}
printf("\n%s", buffer);
return 0;
}

Error Handling in String Formatting

1. Checking Return Values

#include <stdio.h>
#include <errno.h>
int safe_sprintf(char* buffer, size_t size, const char* format, ...) {
va_list args;
va_start(args, format);
int result = vsnprintf(buffer, size, format, args);
va_end(args);
if (result < 0) {
// Encoding error
return -1;
}
if ((size_t)result >= size) {
// Truncation occurred
errno = ENOSPC;
return -1;
}
return result;
}
int main() {
char buffer[10];
int result;
printf("=== Error Handling ===\n\n");
// Successful formatting
result = safe_sprintf(buffer, sizeof(buffer), "Hi");
if (result >= 0) {
printf("Success: '%s' (%d chars)\n", buffer, result);
}
// Truncation
result = safe_sprintf(buffer, sizeof(buffer), 
"This is a very long string");
if (result < 0 && errno == ENOSPC) {
printf("Truncation detected: buffer too small\n");
}
// Multiple calls with error checking
char* parts[] = {"Part1", "Part2", "Part3", "Part4"};
char full[30];
int offset = 0;
for (int i = 0; i < 4; i++) {
int written = safe_sprintf(full + offset, 
sizeof(full) - offset,
"%s%s", 
i == 0 ? "" : "-",
parts[i]);
if (written < 0) {
printf("Error formatting at part %d\n", i);
break;
}
offset += written;
}
if (offset < sizeof(full)) {
printf("Result: %s\n", full);
}
return 0;
}

Locale-Specific Formatting

#include <stdio.h>
#include <locale.h>
int main() {
double number = 1234567.89;
printf("=== Locale-Specific Formatting ===\n\n");
// Default locale
printf("Default locale: %'.2f\n", number);
// Try different locales
const char* locales[] = {"en_US.UTF-8", "de_DE.UTF-8", 
"fr_FR.UTF-8", "es_ES.UTF-8"};
for (int i = 0; i < 4; i++) {
if (setlocale(LC_ALL, locales[i]) != NULL) {
printf("%s: %'.2f\n", locales[i], number);
} else {
printf("%s: not available\n", locales[i]);
}
}
return 0;
}

Best Practices Summary

Do's and Don'ts

// ✅ DO: Use snprintf() for safety
char buffer[100];
snprintf(buffer, sizeof(buffer), "Value: %d", x);
// ✅ DO: Check return values
int written = snprintf(buffer, sizeof(buffer), "%s", long_string);
if (written >= sizeof(buffer)) {
// Handle truncation
}
// ✅ DO: Use appropriate format specifiers
printf("%zu", sizeof(int));        // size_t
printf("%td", ptr_diff);            // ptrdiff_t
printf("%" PRId64, int64_val);     // int64_t (inttypes.h)
// ✅ DO: Limit string width to prevent overflow
printf("%.100s", user_input);       // Limit to 100 chars
// ✅ DO: Use asprintf() for dynamic allocation
char* result;
asprintf(&result, "Complex %s %d", str, num);
// Use result
free(result);
// ❌ DON'T: Use sprintf without bounds checking
sprintf(buffer, "%s", long_string);  // Buffer overflow risk!
// ❌ DON'T: Pass user input directly as format string
printf(user_input);  // Format string vulnerability!
// Use: printf("%s", user_input);
// ❌ DON'T: Assume buffer is large enough
char small[10];
sprintf(small, "This is way too long");  // Overflow!
// ❌ DON'T: Ignore return values
snprintf(buffer, sizeof(buffer), "%d", x);  // Check if it succeeded!
// ❌ DON'T: Mix up format specifiers
printf("%d", long_value);  // Wrong specifier - undefined behavior!

Format Specifier Quick Reference

TypeFormatExample
int%d or %iprintf("%d", 42);
unsigned int%uprintf("%u", 42u);
long%ldprintf("%ld", 42L);
long long%lldprintf("%lld", 42LL);
size_t%zuprintf("%zu", sizeof(int));
float%fprintf("%f", 3.14f);
double%f or %lfprintf("%lf", 3.14);
char%cprintf("%c", 'A');
char*%sprintf("%s", "hello");
void*%pprintf("%p", ptr);
hex%x or %Xprintf("%x", 255);
octal%oprintf("%o", 255);

Common Format Modifiers

ModifierMeaningExample
-Left align%-10s
+Show sign%+d
(space)Space for positive% d
0Zero pad%05d
#Alternate form%#x
*Dynamic width%*d
.Precision%.2f

Conclusion

String formatting in C is a powerful feature with many applications:

Key Functions

  • printf() - Output to stdout
  • sprintf() - Format to string
  • snprintf() - Safe string formatting
  • asprintf() - Dynamic allocation
  • fprintf() - Format to file

Best Practices

  1. Always use snprintf() for safety
  2. Check return values for errors
  3. Limit string lengths for user input
  4. Never use user input as format string
  5. Use appropriate format specifiers
  6. Consider locale for internationalization
  7. Pre-allocate buffers for performance

Common Applications

  • Logging and debugging
  • Data serialization (JSON, CSV, XML)
  • Report generation
  • User interface output
  • Network protocol formatting

Mastering string formatting is essential for creating robust, secure, and well-formatted output in C programs.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper