Arrays and Strings in C
Arrays are contiguous memory blocks. Strings in C are char arrays terminated by a null byte ('\0'). There is no bounds checking.
One-Dimensional Arrays
int nums[5] = {1, 2, 3, 4, 5};
int zeros[10] = {0}; /* all zero */
int partial[] = {1, 2}; /* size deduced: 2 */
printf("%d\n", nums[0]);
printf("%zu\n", sizeof nums / sizeof nums[0]); /* element count */
Multidimensional
int matrix[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
for (int r = 0; r < 3; r++)
for (int c = 0; c < 4; c++)
printf("%d ", matrix[r][c]);
Memory layout is row-major: matrix[1][2] is the 7th element in flat order.
Strings
char greeting[] = "Hello"; /* mutable, includes '\0' */
const char *msg = "World"; /* string literal — often read-only */
char buf[32];
strncpy(buf, "Hi", sizeof buf - 1);
buf[sizeof buf - 1] = '\0'; /* ensure null termination */
string.h Functions
#include <string.h>
size_t len = strlen("hello"); /* 5 */
strcmp("abc", "abd"); /* negative */
strncmp(a, b, n); /* bounded compare */
strcpy(dest, src); /* unsafe if dest too small */
strncpy(dest, src, n);
char *p = strstr("hello world", "world");
Safe String Patterns
/* Prefer snprintf over sprintf */
char buf[64];
snprintf(buf, sizeof buf, "Value: %d", 42);
/* Never use gets() — removed in C11 */
char line[256];
if (fgets(line, sizeof line, stdin))
line[strcspn(line, "\n")] = '\0'; /* strip newline */
Common Pitfalls
- Treating compiler warnings as optional rather than actionable feedback.
- Skipping error checks on library and system calls.
- Copy-pasting examples without adapting to your project’s conventions.
Best Practices
- Enable strict compiler warnings and fix them before merging.
- Write small, testable units with clear input/output contracts.
- Document non-obvious invariants and preconditions.
- Use version control and code review for every change.
Memory and Performance Notes
String literals may live in read-only memory. Writing to char *s = "hi" causes a crash on many systems.
Exercise
Write reverse_string(char *s) that reverses a string in place. Test with palindromes and empty strings.
Hint: Use two pointers — one at start, one at end — swapping characters until they meet.
Summary
Apply these concepts in small programs before moving to larger projects. Combine with adjacent topics in the learning path for deeper mastery.
Real-World Application
These concepts appear in production codebases — from operating system kernels to embedded firmware. Study open-source projects that use this topic extensively to see idiomatic patterns at scale.
Debugging Checklist
- Reproduce the issue with the smallest possible input.
- Enable compiler warnings and sanitizers.
- Use a debugger to inspect state at the failure point.
- Verify assumptions about types, sizes, and return values.
- Compare working and broken code paths side by side.
- Write a regression test once the bug is fixed.
Further Reading
Consult the ISO C standard, Effective C by Robert C. Seacord, and your compiler documentation for platform-specific behavior.
Quick Reference
Review the code examples on this page before starting the exercise. Type them manually to build muscle memory.
Additional Examples
Consider how this topic applies in a larger project:
// Break the problem into smaller functions
// Test each function independently
// Integrate incrementally
Working through variations of the examples above builds deeper understanding than reading alone.
Interview and Review Questions
- Explain the core concept of this topic in your own words.
- What happens when this code runs with edge-case input (empty, null, zero, max value)?
- How would you debug a bug related to this topic in production?
- What are the performance implications of the approach shown here?
- How does this feature compare to the equivalent in another language you know?