Developer Week 048
Courses
Boot.Dev Back-end Developer Career Path (~53.52%) (📈 +0.48%)
The course added a new Module 8, to build an AI Agent, replacing the Maze Solver. For tracking purposes I added the lesson count to total, which is why the week’s increase in percentage complete was so small.
New 8. Build an AI Agent in Python (7/18)
new 8.1.3 Google Gemini
Ran into the following error when trying to use my API key:
ValueError: Missing key inputs argument! To use the Google AI API, provide (
api_key
) arguments. To use the Google Cloud API, provide (vertexai
,project
&location
) arguments.
https://googleapis.github.io/python-genai/#create-a-client
LOL it was error cased by naming my gemini_key.env
instead of just .env
- That’s a lesson I won’t forget anytime soon!
11. Learn Memory Management (56/101)
11.2.5
Assuming char
is 1 byte, int
is 4 bytes, and double
is 8 bytes, the memory layout for human_t
might look like this:
Wait! What is that padding
doing here?
It turns out that CPUs don’t like accessing data that isn’t aligned (incredible oversimplification alert, since obviously CPUs don’t have feelings (yet)), so C inserts padding to maintain alignment (e.g. every 4 bytes in this example).
11.3.1
Variables are human readable names that refer to some data in memory.
Memory is a big array of bytes, and data is stored in the array.
A variable is a human readable name that refers to an address in memory, which is an index into the big array of bytes. Here’s a diagram:
In C, you can print the address of a variable by using the address-of-operator: &
. Here’s an example:
#include <stdio.h>
int main() {
int age = 37;
printf("The address of age is: %p\n", &age);
return 0;
}
// The address of age is: 0xfff8
11.3.6 Pointer Basics
int *pointer_to_something; // declares `pointer_to_something` as a pointer to an int
int meaning_of_life = 42;
int *pointer_to_mol = &meaning_of_life;
// pointer_to_mol now holds the address of meaning_of_life
int meaning_of_life = 42;
int *pointer_to_mol = &meaning_of_life;
int value_at_pointer = *pointer_to_mol;
// value_at_pointer = 42
11.3.9 Arrays as Pointers in C
#include <stdio.h>
int main() {
int numbers[5] = {1, 2, 3, 4, 5};
// Accessing elements using array indexing
printf("numbers[2] = %d\n", numbers[2]); // Output: 3
// Accessing elements using pointers
printf("*(numbers + 2) = %d\n", *(numbers + 2)); // Output: 3
// Pointer arithmetic
int *ptr = numbers;
printf("Pointer ptr points to numbers[0]: %d\n", *ptr); // Output: 1
ptr += 2;
printf("Pointer ptr points to numbers[2]: %d\n", *ptr); // Output: 3
return 0;
}
11.3.12 Pointer Size
In C, pointers are always the same size because they just represent memory addresses. The size of a pointer is determined by the architecture of the system (e.g., 32-bit or 64-bit)
Boot.dev runs C in the browser using WASM, which is typically a 32-bit system. If you run this code on a 64-bit system, the size of the pointers will be 8 bytes.
The size of an array depends on both the number of elements and the size of each element. An array is a contiguous block of memory where each element has a specific type, and therefore, a specific size.
11.3.13 Arrays Decay to Pointers
int arr[5];
int *ptr = arr; // 'arr' decays to 'int*'
int value = *(arr + 2); // 'arr' decays to 'int*'
When Arrays Don’t Decay
sizeof
Operator: Returns the size of the entire array (e.g., sizeof(arr)), not just the size of a pointer.&
Operator Taking the address of an array with&arr
gives you a pointer to the whole array, not just the first element. The type of&arr
is a pointer to the array type, e.g.,int (*)[5]
for anint
array with 5 elements.- Initialization: When an array is declared and initialized, it is fully allocated in memory and does not decay to a pointer.
11.3.14 C Strings
- Unlike other programming languages, C strings do not store their length.
- The length of a C string is determined by the position of the null terminator (
'\0'
). - Functions like
strlen
calculate the length of a string by iterating through the characters until the null terminator is encountered. - This lack of length storage requires careful management to avoid issues such as buffer overflows and off-by-one errors during string operations.
11.3.16 Forward Declaration
typedef struct SnekObject snekobject_t;
This line is a forward declaration. Think of it like telling the compiler, “Hey, there’s a structure named SnekObject
that I’ll define later, and I want to use the shorter name snekobject_t
for it.” This is crucial because the SnekObject
structure needs to refer to itself (or rather, pointers to itself) inside its own definition. Without this forward declaration, the compiler wouldn’t know what snekobject_t
is when it encounters it inside the struct SnekObject
definition.
typedef struct SnekObject {
char *name;
snekobject_t *child;
} snekobject_t;
This is the actual definition of the SnekObject
structure.
typedef struct SnekObject
means we are defining a structure namedSnekObject
and immediately creating a type alias for it.{ ... }
encloses the members of the structure.char *name;
declares a member namedname
which is a pointer to a character (commonly used for strings).snekobject_t *child;
declares a member namedchild
which is a pointer to anothersnekobject_t
. This is where the forward declaration comes into play – we can declare a pointer tosnekobject_t
even though the full definition ofsnekobject_t
is still in progress.} snekobject_t;
finishes the structure definition and thetypedef
, makingsnekobject_t
a synonym forstruct SnekObject
.
snekobject_t new_node(char *name);
This line is a function prototype. It tells the compiler that there’s a function named new_node
that will be defined elsewhere.
snekobject_t
is the return type of the function. It means this function will create and return asnekobject_t
structure.new_node
is the name of the function.(char *name)
specifies that the function takes one argument, which
11.4.3 Switch Case
return a hard-coded string (char *)
mean I can return "desired string"
directly. There is no need to hard card a char *variable
for C.