Chapter 4: Advanced Topics
4.1 Pointers and memory management
Pointers let you access and change memory directly. They are one of the most powerful features of C, and you need to understand them to program in C effectively.
4.1.1 Understanding pointers
A pointer is a variable that stores the memory address of another variable.
Python:
x = 10
y = x # y references the same value as x
print(x, y) # Output: 10 10
C:
#include <stdio.h>
int main() {
int x = 10;
int *ptr = &x; // ptr stores the address of x
printf("Value of x: %d\n", x);
printf("Address of x: %p\n", &x);
printf("Value of ptr: %p\n", ptr);
printf("Value pointed to by ptr: %d\n", *ptr);
return 0;
}
Explanation:
int *ptr = &x;declares a pointerptrthat stores the address ofx.*ptrdereferences the pointer to access the value stored at the address.
4.1.2 Dynamic memory allocation
Dynamic memory allocation lets you allocate memory while the program runs, with functions such as malloc, calloc, realloc, and free.
Example:
#include <stdio.h>
#include <stdlib.h>
int main() {
int *arr;
int n = 5;
// Allocate memory for an array of 5 integers
arr = (int *)malloc(n * sizeof(int));
// Check if the memory has been successfully allocated by malloc
if (arr == NULL) {
printf("Memory not allocated.\n");
exit(0);
} else {
// Memory has been successfully allocated
for (int i = 0; i < n; ++i) {
arr[i] = i + 1;
}
// Print the elements of the array
printf("The elements of the array are: ");
for (int i = 0; i < n; ++i) {
printf("%d ", arr[i]);
}
}
// Free the allocated memory
free(arr);
return 0;
}
Explanation:
mallocallocates a block of memory of the size you ask for and returns a pointer to it.freereleases memory thatmallocallocated earlier.
4.1.3 Common pointer pitfalls
Used carelessly, pointers can cause several problems:
- A dangling pointer still points to a memory location that has been freed.
- A memory leak happens when allocated memory is never freed.
- A buffer overflow happens when a program writes more data to a buffer than it can hold.
Example of a dangling pointer:
#include <stdio.h>
#include <stdlib.h>
int main() {
int *ptr = (int *)malloc(sizeof(int));
*ptr = 10;
printf("Value: %d\n", *ptr);
free(ptr);
// ptr is now a dangling pointer
// printf("Value after free: %d\n", *ptr); // This would lead to undefined behavior
return 0;
}
4.2 Structs and enums
Structs and enums let you create complex data types in C.
4.2.1 Defining and using structs
A struct is a collection of variables (of different types) under a single name.
Python:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
p = Point(1, 2)
print(p.x, p.y) # Output: 1 2
C:
#include <stdio.h>
// Define a struct
struct Point {
int x;
int y;
};
int main() {
struct Point p1;
p1.x = 1;
p1.y = 2;
printf("Point p1: (%d, %d)\n", p1.x, p1.y);
return 0;
}
Explanation:
struct Pointdefines a structure namedPoint.p1is an instance ofPoint.
4.2.2 Enumerated types
An enum gives names to integral constants, which makes a program easier to read and maintain.
Example:
#include <stdio.h>
// Define an enum
enum Weekday { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };
int main() {
enum Weekday today;
today = Wednesday;
printf("Day %d\n", today); // Output: Day 3
return 0;
}
Explanation:
enum Weekdaydefines an enumerated type.todayis a variable of typeenum Weekday.
4.3 File I/O
C handles file input and output through file pointers and functions such as fopen, fclose, fprintf, and fscanf.
4.3.1 Reading from and writing to files
Example:
#include <stdio.h>
int main() {
FILE *fptr;
// Writing to a file
fptr = fopen("file.txt", "w");
if (fptr == NULL) {
printf("Error opening file!\n");
return 1;
}
fprintf(fptr, "Hello, World!\n");
fclose(fptr);
// Reading from a file
char buffer[255];
fptr = fopen("file.txt", "r");
if (fptr == NULL) {
printf("Error opening file!\n");
return 1;
}
while (fgets(buffer, 255, fptr)) {
printf("%s", buffer);
}
fclose(fptr);
return 0;
}
Explanation:
fopenopens a file. Mode"w"is for writing and mode"r"is for reading.fprintfwrites formatted output to a file.fgetsreads a line from a file.fclosecloses the file.
4.3.2 Working with binary files
Example:
#include <stdio.h>
int main() {
FILE *fptr;
int num = 1234;
// Writing to a binary file
fptr = fopen("file.bin", "wb");
if (fptr == NULL) {
printf("Error opening file!\n");
return 1;
}
fwrite(&num, sizeof(int), 1, fptr);
fclose(fptr);
// Reading from a binary file
int read_num;
fptr = fopen("file.bin", "rb");
if (fptr == NULL) {
printf("Error opening file!\n");
return 1;
}
fread(&read_num, sizeof(int), 1, fptr);
printf("Read number: %d\n", read_num);
fclose(fptr);
return 0;
}
Explanation:
fwritewrites binary data to a file.freadreads binary data from a file.- Mode
"wb"opens a binary file for writing, and mode"rb"opens one for reading.