⚠️ This is not the current iteration of the course! Head here for the current offering.

Section 2: Debugging, Alignment, and Signed Integers

This section goes deeper on concepts related to memory representations in C. It will cover topics such as dynamic memory allocation, memory segmentation, memory alignment, and signed integers.

Warmup: Primitive Alignment

short my_short;
int my_int;
char my_char;
char *char_ptr;
int *int_ptr;

WARMUP A. For each of the above variables, identify their alignment. Give an example of a valid, properly-aligned address for each.

WARMUP B. Why is having properly aligned memory addresses important? What could happen when using unaligned memory addresses, and how might this impact performance?

Question 1: Memory Segments

Consider the following C program. It concatenates a series of num_words C strings into one. Let's analyze how it uses memory and how these values are stored!

#include <stdio.h>
#include <stdio.h>
#include <string.h>

const unsigned int num_words = 3;

char* concatenate(char** list)
{
    size_t total_len = 0;
    for (unsigned int i = 0; i < num_words; i++) {
        total_len += strlen(*list + i);
    }

    char *concatenated = (char*) malloc(total_len);

    total_len = 0;
    for (unsigned int i = 0; i < num_words; i++)
    {
        size_t len = strlen(*list + i);
        strncpy(concatenated + total_len, *list + i, len);
        total_len += len;
    }

    return concatenated;
}

int main()
{
    char* list[3];

    char* str_1 = "CS";
    char* str_2 = "CI";
    char* str_3 = "0300!";

    list[0] = str_1;
    list[1] = str_2;
    list[2] = str_3;

    printf("String 1: %s\n", str_1);
    printf("String 2: %s\n", str_2);
    printf("String 3: %s\n", str_3);

    char* concatenated = concatenate(list);
    printf("%s\n", concatenated);

    return 0;
}

QUESTION 1A. What segment of memory is the variable num_words located in?

QUESTION 1B. What segment of memory is the address of the concatenate function located in? (&concatenate)

QUESTION 1C. What segment of memory is the variable str_1 located in?

QUESTION 1D. What segment of memory is the object that concatenated points to in?

QUESTION 1E. What segment of memory is the variable concatenated located in?

Question 2: Buggy Code

Let's revisit the concatenator! Recall that it should concatenate a series of num_words C strings, but unfortunately it has some bugs regarding memory management and access!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const unsigned int num_words = 3;

char* concatenate(char** list)
{
    size_t total_len = 0;
    for (unsigned int i = 0; i < num_words; i++) {
        total_len += strlen(*list + i);
    }

    char* concatenated = (char*) malloc(total_len);

    total_len = 0;
    for (unsigned int i = 0; i < num_words; i++)
    {
        size_t len = strlen(*list + i);
        strncpy(concatenated + total_len, *list + i, len);
        total_len += len;
    }

    return concatenated;
}

int main()
{
    char* list[3];

    char* str_1 = "CS";
    char* str_2 = "CI";
    char* str_3 = "0300!";

    list[0] = str_1;
    list[1] = str_2;
    list[2] = str_3;

    printf("String 1: %s\n", str_1);
    printf("String 2: %s\n", str_2);
    printf("String 3: %s\n", str_3);

    char* concatenated = concatenate(list);
    printf("%s\n", concatenated);

    return 0;
}

QUESTION 2A. Identify the 3 bugs in the concatenator program. What are these bugs, and how could we fix them?

QUESTION 2B. Why would we want to use malloc in this situation as opposed to static or automatic memory?

Question 3: Signed Integers

Let's spend a little more time working with unsigned and signed integers!

Consider the following C program which adds some integers.

int main() {
    int x = 0x7031ab3c;
    int y = 0x142230f2;
    int result = x + y;
    printf("%d + %d = %d\n", x, y, result);

    return 0;
}

QUESTION 3A. What will the above code print? Is this different from what you expect? (Hint: you can make use of this hex to decimal number converter.)

QUESTION 3B. What would the above code print if we changed x, y, and result to unsigned int, like the following code block:

int main() {
    unsigned int x = 0x7031ab3c;
    unsigned int y = 0x142230f2;
    unsigned int result = x + y;
    printf("%u + %u = %u\n", x, y, result);

    return 0;
}

Question 4: Struct Alignment

Suppose that we wanted to change the concatenator code keep track of words in word_entry_t structs instead of an array of C strings.

typedef struct {
    short count;
    unsigned int str_len;
    char checked;
    char* word;
} word_entry_t;

QUESTION 4A. What is the size and alignment of the struct struct_t? Does this seem efficient?

QUESTION 4B. How could we reorganize the fields of struct_t to reduce the memory required? What is the size and alignment of struct_t using this more efficient ordering?