My Learning Journey: Understanding C
Community Article
Published
March 9, 2025
Hey everyone! I'm just starting with C programming, and I wanted to document my learning journey by breaking down this program. This code is from alex the dev im just adding comments on the code so i understand what's going on. Currently im on chapter 5 of c&c if you want to compare. formatting thanks to copilot
1. Including the Necessary Libraries
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
What I Learned:
stdlib.h
:
Provides functions for dynamic memory allocation (malloc
,realloc
,free
).stdio.h
:
Contains functions for input/output operations such asprintf
, file operations (fopen
,fread
,fclose
).string.h
:
Offers string handling functions likestrcmp
(to compare strings) andmemcpy
(to copy memory).
2. Defining a Structure to Hold Arguments
typedef struct arguments {
char **files;
unsigned int files_count;
} arguments;
- Structures (
struct
) are used in C to group related variables together. - Members of the Structure:
char **files
:
This is a double pointer.- A
char *
represents a single string (an array of characters). - A
char **
represents an array of strings, meaning it can hold multiple file names.
- A
unsigned int files_count
:
Keeps track of how many file names have been provided. Usingunsigned int
ensures the number is never negative.
3. Parsing Command-Line Arguments
void parse_arguments(int argc, char **argv, arguments *args) {
args->files = malloc(argc * sizeof(char *));
int index = 0;
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--help") == 0) {
printf("Usage: ./main [file1] or [--help]
");
exit(0);
} else {
args->files[index] = argv[i];
index++;
}
}
args->files_count = index;
}
What I Learned:
- Function Parameters:
int argc
: Number of command-line arguments.char **argv
: Array of strings, where each string is one command-line argument.arguments *args
: A pointer to ourarguments
structure so the function can modify it.
- Dynamic Memory Allocation:
args->files = malloc(argc * sizeof(char *));
Here we allocate memory for an array of pointers. The->
operator is used becauseargs
is a pointer to a structure. Itβs a shorthand for(*args).files
.
- Looping Through Arguments:
- We start at index
1
(sinceargv[0]
is the program name). - If an argument is
"--help"
, the program prints a help message and exits. - Other arguments are assumed to be file names and stored in the
files
array.
- We start at index
- Storing the File Count:
- After the loop, the number of file names stored is saved in
args->files_count
.
- After the loop, the number of file names stored is saved in
4. Reading a File into Memory
#define MAX_LEN 128
int read_file(char *path, char **buffer) {
int tmp_capacity = MAX_LEN;
char *tmp = malloc(tmp_capacity * sizeof(char));
int tmp_size = 0;
if (tmp == NULL) {
perror("Memory allocation error");
exit(1);
}
FILE *f = fopen(path, "r");
if (f == NULL) {
perror("File opening error");
exit(1);
}
int size = 0;
do {
if (tmp_size + MAX_LEN > tmp_capacity) {
tmp_capacity *= 2;
tmp = realloc(tmp, tmp_capacity * sizeof(char));
if (tmp == NULL) {
perror("Memory allocation error");
exit(1);
}
}
size = fread(tmp + tmp_size, sizeof(char), MAX_LEN, f);
tmp_size += size;
} while (size > 0);
fclose(f);
tmp[tmp_size] = '\0';
*buffer = tmp;
return tmp_size;
}
What I Learned:
- Defining Constants:
#define MAX_LEN 128
sets the size of chunks to read from the file.
- Memory Allocation for File Content:
- Initially, a buffer
tmp
of sizeMAX_LEN
is allocated. - If more space is needed as we read the file,
realloc
is used to double the buffer size.
- Initially, a buffer
- File Operations:
- The file is opened with
fopen
. If opening fails, an error is printed. - The file is read in chunks using
fread
, and the pointer arithmetic (tmp + tmp_size
) makes sure new data is appended correctly.
- The file is opened with
- Buffer Finalization:
- After reading, the file is closed and a null terminator (
'\0'
) is added to mark the end of the string. - The pointer to the allocated buffer is returned through
*buffer
.
- After reading, the file is closed and a null terminator (
5. The Main Function: Putting Everything Together
int main(int argc, char **argv) {
arguments args = {0};
parse_arguments(argc, argv, &args);
char *buffer = NULL;
int buffer_size = 0;
for (int i = 0; i < args.files_count; i++) {
char *content = NULL;
int size = read_file(args.files[i], &content);
buffer = realloc(buffer, buffer_size + size + 1);
memcpy(buffer + buffer_size, content, size);
buffer_size += size;
free(content);
}
printf("%s\n", buffer);
free(buffer);
free(args.files);
return 0;
}
π Final Thoughts
I really learned a lot while documenting this program!
If youβre also learning C, I hope this helps. If you have any questions (or if I explained something wrong π
), let me know!
Happy coding! π