# Week 1 - Memory
## Team
Team Name: Peach Technologies
Date: Wednesday 9 February 2022
|----------------------------------------------------------------------------|
Members:
Nafizul Habib Redwan
Siebe de Bruijn
Naomi Verschuur
Yazan Tayeh
|----------------------------------------------------------------------------|
Role
Facilitator: Nafizul Habib Redwan
Reflector: Yazan Tayeh
Spokesperson: Siebe de Bruijn
Recorder: Naomi Verschuur
|----------------------------------------------------------------------------|
| **Facilitator** keeps track of time, assigns tasks and makes sure all the group members are heard and that decisions are agreed upon. | |
| **Spokesperson** communicates group’s questions and problems to the teacher and talks to other teams; presents the group’s findings. | |
| **Reflector** observes and assesses the interactions and performance among team members. Provides positive feedback and intervenes with suggestions to improve groups’ processes. | |
| **Recorder** guides consensus building in the group by recording answers to questions. Collects important information and data. | |
## Activities
Make sure to have the activities signed off regularly to ensure progress is tracked.
Set up a project in CLion to write the small programs needed in some of the activities.
### Activity 1: Memory usage - the sizeof operator
@yazantayeh
Record your answer here:
| Data Type | Size in Bytes |
|-----------|---------------|
| char | 1 |
| short int | 2 |
| int | 4 |
| long int | 4 |
| long long int | 8 |
| float | 4 |
| double | 8 |
| long double | 16 |
| char* | 8 |
| int* | 8 |
| float* | 8 |
| double* | 8 |
| void* | 8 |
### Activity 2: Array and structure sizes
@NaomiVerschuur
```c
typedef struct {
char name[80];
int age;
} person_t;
void size_array(int array[]) {
printf("Size of array parameter: %lu\n", sizeof(array));
}
void size_struct(person_t p) {
printf("Size of p parameter: %lu\n", sizeof(p));
}
int main() {
int array[10];
person_t bob = {.name = "Bob", .age = 22};
printf("Size of int array: %lu\n", sizeof(array));
printf("Size of person_t structure: %lu\n", sizeof(bob));
size_array(array);
size_struct(bob);
}
```
Record your answer here:
The output printed into the consol is
```c
Size of int array: 40;
Size of persont structure: 84;
Size of array parameter: 8;
Size of p parameter: 84
```
The array changes when passing as an arguement, while the struct remains the same after being passed through the arguement.
When passing an array as an arguement, the array pointer is passed and not the entire array. And the pointer size is always 8.
### Activity 3: Memory addresses
@sdbruijn
```C
int main( void ) {
int a = 0xA0B0C0D0;
short int b = 0x7856;
const char * s = "Hello!";
char buf[] = "Pointer";
short int c = 0x3412;
printf("int a: %p\n", (void*) &a);
printf("short int b: %p\n", (void*) &b);
printf("const char *s: %p\n", (void*) &s);
printf("char buf[]: %p\n", (void*) buf);
printf("short int c: %p\n", (void*) &c);
}
```
Record your answer here:
| Variable | Memory Address |
| ----------- | -------------- |
| int a | 0x7fffc8d6a3dc |
| short int b | 0x7fffc8d6a3da |
| cons char s | 0x7fff1f08eed0 |
| char buf[] | 0x7fff1f08eec8 |
| short int c | 0x7fff1f08eec6|
| first character of s |0x402004
The different variables are layed out in a contiguous way, all being relatively close to eachother, that being in range of a few byets. There are gaps in between, but not ones too large. The first character of s does seem to be stored in a totally different address than the others, with only the first byte being the same, and it branching out after. However, this is stored still relatively close to the other variables
### Activity 4: Observing automatic lifetime
@Nafiz
Record your answer here:
loc of x 000000000061FDF0
loc of y 000000000061FDF8
loc of c 000000000061FDDC
loc of x 000000000061FDF0
loc of y 000000000061FDF8
loc of c 000000000061FDDC
loc of x 000000000061FDF0
loc of y 000000000061FDF8
loc of z 000000000061FDDC
26
### Activity 5: Observing the stack
@NaomiVerschuur
Record your answer here:
Code:
```c
#include <stdio.h>
int poly(int a) {
int b = a * (a + 1);
return b / 2;
}
int add_polys(int x, int y) {
int bx = poly(x);
int by = poly(y);
return bx + by;
}
int print_bar(int a, int b, int x, int y){
printf("int a: %p\n", (void*) &a);
printf("int b: %p\n", (void*) &b);
printf("int x: %p\n", (void*) &x);
printf("int y: %p\n", (void*) &y);
}
int print_foo(int bx, int by){
printf("int bx: %p\n", (void*) &bx);
printf("int by: %p\n", (void*) &by);
}
int main( void ) {
int a; int b; int x; int y;
int bx; int by;
printf("%d\n", add_polys(42, 24));
print_bar(a,b,x,y);
print_foo(bx, by);
}
```
Output in Console:
```c
int a: 0x30dd558e8
int b: 0x30dd558e4
int x: 0x30dd558e0
int y: 0x30dd558dc
int bx: 0x30dd558e8
int by: 0x30dd558e4
```
When comparing the answers it can be seen that `int a` and `int bx` are the same. Showing that they use the same memory. As well as how`int b` and `int by` uses the same memory addresses.
### Activity 6: Leaking local addresses
@yazantayeh
```c
The answer is: 42
The answer is: 24
```
The value has changed after defining an array in the ``i_do_nothing()`` function because the local address of the value has leaked out of scope when the pointer of that variable was returned from the function
### Activity 7: Memory addresses of local variables
@NaomiVerschuur
Record your answer here:
Which warnings and / or errors does the compiler give when compiling this program?
* --> error: address of stack memory associated with local variable `array` returned [-Werror,-Wreturn-stack-address]
What do these warnings and / or errors mean?
* --> The problem with the array is that it is created inside the function. Meaning that the memory which was allocated for the array is actually allocated on a location in memory called the stack. The consequences of this is that as soon as the function returns the array will also go away along with all of its elements. So trying to access the elements of the array after the function returns may cause some problems.
Does this approach to create an array at runtime work? Why (not)?
* --> This approach does not work becasue the address of the stack memory associated with the local variable `array` is returned.
### Activity 8: Using malloc
@Nafiz
Record your answer here:
- In the main function , we allocated a memory address for the unsigned long and float variables and using the free function to release them
- Also the function allocate_memory returns the ptr of the int count
### Activity 9: Using allocated memory as an array
@Nafiz
The program listed below is a failed attempt to allocate memory for storing an array of 20 integers.
Answer the following questions:
How many int elements can be stored in the allocated block of memory?
- The program can store up to 20 Ints.
-
What happens when you perform an out-of-bounds access to an array that is stored in
dynamically allocated memory?
-
- Out of bounds array access have undefined behaviour and can result in crashed or incorrect program output.
What is the problem in the program listed below, and how can it be fixed?
- The problem was not putting the character & before the variable which resulted in some errors in the program
-
```c
int main( void ) {
const int capacity = 20;
int *ptr = (int*) malloc(capacity);
for (int i = 0; i < capacity; i++) {
printf("ptr[%d] = %d\n", i, ptr[i]);
}
}
```
Record your answer here:
### Activity 10: Infinite memory?
@yazantayeh
The program doesn't crash in this case
### Activity 11: Fixing a memory leak
@yazantayeh
Since the program doesnt crash we were unable to complete this task
### Activity 12: Dangerous `free`s
@Nafiz
When trying to call the free function on a pointer that was not obtained
using malloc, there are two possible actions that will follow:
1. It has an undefined behavior occurs
2. you can free without calling malloc but only if the value you pass to free is a NULL pointer, which was in our case.
### Activity 13: Using realloc
@NaomiVerschuur
```c=
int main( void ) {
float *grades = NULL;
for (int capacity = 10; capacity <= 100; capacity += 10)
{
float *new_grades = (float*)realloc(grades, sizeof(float[capacity]));
if (new_grades != NULL)
{
grades = new_grades;
}
}
}
```
Record your answer here:
How many explicit calls to **free** must be added to the program listed above, in order to release all the memory that has been allocated?
- 1 is the number of explicit calls to free that needs to be added to the program in order for it to release all the memory that has been allocated. This is because the free function only needs to be called once at the end of the program.
### Activity 14: Using a dynamically sized buffer
@sdbruijn
```c=
#include <stdio.h>
int main( void ) {
char *ptr = NULL;
unsigned long capacity = 20;
ptr = realloc(ptr, sizeof(char[capacity]));
if (!ptr){
fprintf(stderr, "Memory allocation failed\n");
return 1;
}
FILE *file = fopen("input.txt", "r");
if (!file) {
fprintf(stderr, "Error opening file\n");
return 1;
}
unsigned long count = 0;
int c = fgetc(file);
while (c != EOF) {
if (count == capacity) {
capacity *= 1.5;
realloc(ptr, capacity);
ptr[count++] = (char) c;
c = fgetc(file);
}
}
}
```
This program was ran and tested with input.txt containing the lyrics to Fireflies by Owl City.
# Looking back
### What we've learnt
- How arrays are stored in memory
- Leaking local memory addresses
- The stack and automatic lifetime
- The heap and dynamic lifetime
### What were the surprises
- The memory address might leak
- The programmer can dynamically allocate memory
### What problems we've encountered
- Naomi's computer froze and the code did not work on her Mac for some of the assignment.
### What was or still is unclear
- How to properly use malloc()
### How did the group perform?
How was the collaboration? What were the reasons for hick-ups? What worked well? What can be improved next time?
- Our team worked very well together
- Knowing each other’s strengths and weaknesses improved productivity
- The team had productive discussions regarding each topic
> Written with [StackEdit](https://stackedit.io/).