C/C++ Fundamentals Reference
Data Types
Fundamental Data Types
| Type |
Size (bytes) |
Range |
Description |
| char |
1 |
-128 to 127 or 0 to 255 |
Single character or small integer |
| unsigned char |
1 |
0 to 255 |
Unsigned character |
| short (short int) |
2 |
-32,768 to 32,767 |
Short integer |
| unsigned short |
2 |
0 to 65,535 |
Unsigned short integer |
| int |
4 |
-2,147,483,648 to 2,147,483,647 |
Standard integer |
| unsigned int |
4 |
0 to 4,294,967,295 |
Unsigned integer |
| long |
8 |
-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |
Long integer |
| unsigned long |
8 |
0 to 18,446,744,073,709,551,615 |
Unsigned long integer |
| float |
4 |
±3.4E±38 (7 digits precision) |
Single precision floating point |
| double |
8 |
±1.7E±308 (15 digits precision) |
Double precision floating point |
| long double |
16 |
Extended precision |
Extended precision floating point |
#include <stdio.h>
#include <limits.h>
#include <float.h>
int main() {
printf("char: %zu bytes, range: %d to %d\n", sizeof(char), CHAR_MIN, CHAR_MAX);
printf("int: %zu bytes, range: %d to %d\n", sizeof(int), INT_MIN, INT_MAX);
printf("long: %zu bytes, range: %ld to %ld\n", sizeof(long), LONG_MIN, LONG_MAX);
printf("float: %zu bytes, range: %E to %E\n", sizeof(float), FLT_MIN, FLT_MAX);
printf("double: %zu bytes, range: %E to %E\n", sizeof(double), DBL_MIN, DBL_MAX);
return 0;
}
Derived Data Types
- arrays - Collection of elements of same type
- pointers - Variables that store memory addresses
- structures - Custom data types with multiple members
- unions - Data types where members share same memory
- enumerations - Named integer constants
- functions - Code blocks that perform specific tasks
Memory Organization
Memory Layout
┌─────────────────┐ ← High Address
│ Stack │
│ (grows down) │
├─────────────────┤
│ │
│ Free Space │
│ │
├─────────────────┤
│ Heap │
│ (grows up) │
├─────────────────┤
│ BSS Segment │
│ (uninitialized)│
├─────────────────┤
│ Data Segment │
│ (initialized) │
├─────────────────┤
│ Text Segment │
│ (code) │ ← Low Address
└─────────────────┘
Memory Segments
- Text Segment: Contains executable code (read-only)
- Data Segment: Initialized global and static variables
- BSS Segment: Uninitialized global and static variables
- Heap: Dynamic memory allocation (malloc, new)
- Stack: Local variables, function parameters, return addresses
#include <stdio.h>
#include <stdlib.h>
int global_var = 100; // Data segment
int uninitialized_var; // BSS segment
int main() {
int local_var = 50; // Stack
int *heap_var = malloc(sizeof(int)); // Heap
*heap_var = 75;
printf("Global var address: %p\n", &global_var);
printf("Local var address: %p\n", &local_var);
printf("Heap var address: %p\n", heap_var);
free(heap_var);
return 0;
}
Basic Data Handling
Variables and Constants
// Variable declarations and initialization
int x = 10; // Initialize at declaration
int y; // Declare, initialize later
y = 20;
const int MAX_SIZE = 100; // Constant (cannot be changed)
#define PI 3.14159 // Preprocessor constant
// Type qualifiers
volatile int sensor_data; // Value may change unexpectedly
register int counter; // Suggest storing in CPU register
static int file_scope; // Internal linkage
extern int global_from_other_file; // External linkage
Arrays
// Array declaration and initialization
int numbers[5]; // Uninitialized array
int values[5] = {1, 2, 3, 4, 5}; // Initialized array
int partial[5] = {1, 2}; // Partially initialized (rest are 0)
int auto_size[] = {1, 2, 3}; // Size determined by initializer
// Multidimensional arrays
int matrix[3][4]; // 3x4 matrix
int cube[2][3][4] = { // 3D array with initialization
{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}},
{{13, 14, 15, 16}, {17, 18, 19, 20}, {21, 22, 23, 24}}
};
// Array access
for (int i = 0; i < 5; i++) {
numbers[i] = i * 10;
}
Pointers
// Pointer declaration and usage
int value = 42;
int *ptr = &value; // Pointer to int, initialized with address of value
int **double_ptr = &ptr; // Pointer to pointer
printf("Value: %d\n", value); // 42
printf("Address of value: %p\n", &value);
printf("Pointer value: %p\n", ptr);
printf("Value through pointer: %d\n", *ptr); // Dereferencing
// Pointer arithmetic
int arr[5] = {10, 20, 30, 40, 50};
int *p = arr; // Points to first element
printf("First element: %d\n", *p); // 10
printf("Second element: %d\n", *(p+1)); // 20
printf("Third element: %d\n", p[2]); // 30 (equivalent to *(p+2))
// Moving through array
for (int i = 0; i < 5; i++) {
printf("Element %d: %d at address %p\n", i, *p, p);
p++;
}
Tip: Array names are essentially constant pointers to the first element. arr and &arr[0] are equivalent.
Byte Addressable Memory
Understanding Memory Addresses
In C/C++, memory is byte-addressable, meaning each byte has a unique address. Understanding this is crucial for pointer arithmetic and memory manipulation.
#include <stdio.h>
int main() {
char c = 'A';
short s = 1000;
int i = 50000;
double d = 3.14159;
printf("char 'A' at address %p, size: %zu bytes\n", &c, sizeof(c));
printf("short 1000 at address %p, size: %zu bytes\n", &s, sizeof(s));
printf("int 50000 at address %p, size: %zu bytes\n", &i, sizeof(i));
printf("double 3.14159 at address %p, size: %zu bytes\n", &d, sizeof(d));
// Examining memory byte by byte
unsigned char *byte_ptr = (unsigned char*)&i;
printf("Integer %d stored as bytes: ", i);
for (size_t j = 0; j < sizeof(i); j++) {
printf("0x%02X ", byte_ptr[j]);
}
printf("\n");
return 0;
}
Memory Layout Example
Array: int arr[4] = {0x12345678, 0x9ABCDEF0, 0x11111111, 0x22222222}
Address │ Byte 0 │ Byte 1 │ Byte 2 │ Byte 3 │ Value
─────────┼────────┼────────┼────────┼────────┼──────────
0x1000 │ 78 │ 56 │ 34 │ 12 │ arr[0]
0x1004 │ F0 │ DE │ BC │ 9A │ arr[1]
0x1008 │ 11 │ 11 │ 11 │ 11 │ arr[2]
0x100C │ 22 │ 22 │ 22 │ 22 │ arr[3]
Important: The byte order shown above assumes little-endian architecture (least significant byte first). On big-endian systems, the byte order would be reversed.
Pointer Arithmetic and Byte Addressing
#include <stdio.h>
int main() {
int arr[4] = {0x12345678, 0x9ABCDEF0, 0x11111111, 0x22222222};
printf("Array addresses and values:\n");
for (int i = 0; i < 4; i++) {
printf("arr[%d] = 0x%08X at address %p\n", i, arr[i], &arr[i]);
}
// Pointer arithmetic - moves by sizeof(type) bytes
int *ptr = arr;
printf("\nPointer arithmetic:\n");
printf("ptr points to %p, value: 0x%08X\n", ptr, *ptr);
ptr++; // Moves by sizeof(int) = 4 bytes
printf("ptr++ points to %p, value: 0x%08X\n", ptr, *ptr);
// Byte-level access
unsigned char *byte_ptr = (unsigned char*)arr;
printf("\nByte-level access of first integer:\n");
for (int i = 0; i < 4; i++) {
printf("Byte %d: 0x%02X at address %p\n", i, byte_ptr[i], &byte_ptr[i]);
}
return 0;
}
C-Style Strings
String Representation
C-style strings are arrays of characters terminated by a null character ('\0' or ASCII 0).
#include <stdio.h>
#include <string.h>
int main() {
// Different ways to declare and initialize strings
char str1[] = "Hello"; // Size automatically calculated (6 bytes)
char str2[10] = "World"; // Fixed size array, partially filled
char str3[] = {'H', 'e', 'l', 'l', 'o', '\0'}; // Character array
char *str4 = "Constant string"; // Pointer to string literal
printf("String lengths:\n");
printf("str1: \"%s\" length: %zu, array size: %zu\n", str1, strlen(str1), sizeof(str1));
printf("str2: \"%s\" length: %zu, array size: %zu\n", str2, strlen(str2), sizeof(str2));
printf("str3: \"%s\" length: %zu, array size: %zu\n", str3, strlen(str3), sizeof(str3));
printf("str4: \"%s\" length: %zu\n", str4, strlen(str4));
// Examining string memory layout
printf("\nMemory layout of str1 (\"%s\"):\n", str1);
for (size_t i = 0; i < sizeof(str1); i++) {
if (str1[i] == '\0') {
printf("Index %zu: '\\0' (null terminator)\n", i);
} else {
printf("Index %zu: '%c'\n", i, str1[i]);
}
}
return 0;
}
String Memory Layout
char str[] = "Hello";
Index │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │
──────┼───┼───┼───┼───┼───┼───┤
Char │ H │ e │ l │ l │ o │\0 │
ASCII │72 │101│108│108│111│ 0 │
Warning: String literals are stored in read-only memory. Attempting to modify them through a pointer results in undefined behavior.
String Handling Operations
Standard String Functions
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char source[] = "Hello World";
char destination[50];
char buffer[100];
// String copying
strcpy(destination, source);
printf("strcpy result: %s\n", destination);
// Safe string copying (with size limit)
strncpy(buffer, source, sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = '\0'; // Ensure null termination
printf("strncpy result: %s\n", buffer);
// String concatenation
strcat(destination, " from C");
printf("strcat result: %s\n", destination);
// Safe string concatenation
strncat(buffer, " - safe version", sizeof(buffer) - strlen(buffer) - 1);
printf("strncat result: %s\n", buffer);
// String comparison
int cmp = strcmp("Apple", "Banana");
printf("strcmp(\"Apple\", \"Banana\"): %d\n", cmp); // Negative
cmp = strcmp("Hello", "Hello");
printf("strcmp(\"Hello\", \"Hello\"): %d\n", cmp); // Zero
// String searching
char *found = strchr(source, 'W');
if (found) {
printf("Found 'W' at position: %ld\n", found - source);
}
found = strstr(source, "World");
if (found) {
printf("Found \"World\" at position: %ld\n", found - source);
}
return 0;
}
Manual String Operations
// Custom string length function
size_t my_strlen(const char *str) {
size_t length = 0;
while (str[length] != '\0') {
length++;
}
return length;
}
// Custom string copy function
char *my_strcpy(char *dest, const char *src) {
char *original_dest = dest;
while (*src != '\0') {
*dest = *src;
dest++;
src++;
}
*dest = '\0'; // Add null terminator
return original_dest;
}
// Custom string comparison function
int my_strcmp(const char *str1, const char *str2) {
while (*str1 && (*str1 == *str2)) {
str1++;
str2++;
}
return *(unsigned char*)str1 - *(unsigned char*)str2;
}
// Reverse a string in-place
void reverse_string(char *str) {
if (!str) return;
size_t len = strlen(str);
for (size_t i = 0; i < len / 2; i++) {
char temp = str[i];
str[i] = str[len - 1 - i];
str[len - 1 - i] = temp;
}
}
Dynamic String Handling
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Dynamic string creation
char *create_string(const char *source) {
if (!source) return NULL;
size_t len = strlen(source);
char *new_str = malloc(len + 1); // +1 for null terminator
if (!new_str) return NULL; // Check for allocation failure
strcpy(new_str, source);
return new_str;
}
// String concatenation with dynamic allocation
char *concat_strings(const char *str1, const char *str2) {
if (!str1 || !str2) return NULL;
size_t len1 = strlen(str1);
size_t len2 = strlen(str2);
char *result = malloc(len1 + len2 + 1);
if (!result) return NULL;
strcpy(result, str1);
strcat(result, str2);
return result;
}
int main() {
char *dynamic_str = create_string("Hello");
printf("Dynamic string: %s\n", dynamic_str);
char *combined = concat_strings(dynamic_str, " World!");
printf("Combined string: %s\n", combined);
// Always free dynamically allocated memory
free(dynamic_str);
free(combined);
return 0;
}
Memory Management: Always pair malloc() with free(), and set pointers to NULL after freeing to avoid dangling pointers.
Common Patterns & Best Practices
Safe String Input
#include <stdio.h>
#include <string.h>
// Safe string input function
void safe_gets(char *buffer, size_t buffer_size) {
if (fgets(buffer, buffer_size, stdin)) {
// Remove newline if present
size_t len = strlen(buffer);
if (len > 0 && buffer[len-1] == '\n') {
buffer[len-1] = '\0';
}
}
}
int main() {
char name[50];
printf("Enter your name: ");
safe_gets(name, sizeof(name));
printf("Hello, %s!\n", name);
return 0;
}
Error Handling Patterns
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
// Function with proper error handling
char *safe_string_duplicate(const char *source) {
if (!source) {
fprintf(stderr, "Error: NULL pointer passed to safe_string_duplicate\n");
return NULL;
}
size_t len = strlen(source);
char *duplicate = malloc(len + 1);
if (!duplicate) {
fprintf(stderr, "Error: Memory allocation failed: %s\n", strerror(errno));
return NULL;
}
memcpy(duplicate, source, len + 1); // Include null terminator
return duplicate;
}
// File reading with error checking
int read_file_to_string(const char *filename, char **content) {
FILE *file = fopen(filename, "r");
if (!file) {
fprintf(stderr, "Error opening file '%s': %s\n", filename, strerror(errno));
return -1;
}
// Get file size
fseek(file, 0, SEEK_END);
long size = ftell(file);
fseek(file, 0, SEEK_SET);
*content = malloc(size + 1);
if (!*content) {
fprintf(stderr, "Memory allocation failed\n");
fclose(file);
return -1;
}
size_t bytes_read = fread(*content, 1, size, file);
(*content)[bytes_read] = '\0';
fclose(file);
return 0;
}
Memory Layout Debugging
#include <stdio.h>
// Function to print memory contents as hex
void print_memory(const void *ptr, size_t size) {
const unsigned char *byte_ptr = (const unsigned char*)ptr;
printf("Memory contents at %p:\n", ptr);
printf("Offset: ");
for (size_t i = 0; i < size; i++) {
printf("%02zX ", i);
}
printf("\n");
printf("Value: ");
for (size_t i = 0; i < size; i++) {
printf("%02X ", byte_ptr[i]);
}
printf("\n");
printf("ASCII: ");
for (size_t i = 0; i < size; i++) {
if (byte_ptr[i] >= 32 && byte_ptr[i] <= 126) {
printf(" %c ", byte_ptr[i]);
} else {
printf(" . ");
}
}
printf("\n\n");
}
int main() {
char string[] = "Hello\0Hidden";
int number = 0x12345678;
printf("String analysis:\n");
print_memory(string, sizeof(string));
printf("Integer analysis:\n");
print_memory(&number, sizeof(number));
return 0;
}
Performance Considerations
Performance Tips:
- Use memcpy() instead of strcpy() when you know the length
- Cache string lengths in loops to avoid repeated strlen() calls
- Use const for read-only string parameters
- Consider using static buffers for temporary strings in frequently called functions
- Use string builders or dynamic arrays for string concatenation in loops
Common Pitfalls
Watch Out For:
- Buffer Overflows: Always check bounds when copying strings
- Missing Null Terminators: strncpy() doesn't always add '\0'
- Dangling Pointers: Don't use pointers after freeing memory
- Memory Leaks: Every malloc() needs a corresponding free()
- Modifying String Literals: String literals are read-only
- Uninitialized Arrays: Local arrays contain garbage values
Quick Reference
Essential Functions
| Function |
Purpose |
Example |
| strlen() |
Get string length |
size_t len = strlen("hello"); |
| strcpy() |
Copy string |
strcpy(dest, src); |
| strncpy() |
Copy n characters |
strncpy(dest, src, n); |
| strcat() |
Concatenate strings |
strcat(dest, src); |
| strcmp() |
Compare strings |
int cmp = strcmp(s1, s2); |
| strchr() |
Find character |
char *p = strchr(str, 'c'); |
| strstr() |
Find substring |
char *p = strstr(str, "sub"); |
| malloc() |
Allocate memory |
char *p = malloc(100); |
| free() |
Free memory |
free(p); |