# Week 1 Memory
## Team
Date: 2/21/2023
Members:
- William 530785
- Nghi Nguyen 532297
## 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.
### Before you start
In your projects, make sure that the `CMakeLists.txt` file contains the following line, so that potential problems appear in the "Messages" tab:
> ```text
> target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -pedantic -Werror)
> ```
Make sure to check the messages after building.
### Activity 1: Printing memory addresses - I
Give the memory address ranges of the two arrays, `integers` and `doubles`, in the code listed below.
Explain why these ranges do or do not overlap.
This is how you include code listings in your markdown document:
```C
#include <stdio.h>
int sum_ints(void) {
int integers[1024] = {1};
for (int i = 1; i < 1024; ++i) integers[i] = integers[i - 1] + 1;
return integers[1023];
}
double mul_doubles(int init) {
double doubles[1024] = {init};
for (int i = 1; i < 1024; ++i) doubles[i] = doubles[i - 1] * 0.999;
return doubles[1023];
}
int main(void) {
double result = mul_doubles(sum_ints());
printf("Result = %lf\n", result);
}
```
• What are the memory address ranges of both arrays?

• Do these memory address ranges overlap?
Yes, because some of integer address is used by the double.
• Does the lifetime of the two arrays overlap? Why (not)?
The lifetime of the two arrays don't overlap, that is because at first, when the function sum_ints() is called, a new block of memory is added to the stack for the 'integers' array, and that memory block is also taken away when the function ends. After that, the mul_double() function is called, and the same memory address can now be used for the 'doubled' array. In conclusion, since the two functions are not 'alive' simultaneously, the same memory location can be used, hence, the lifetime of the two arrays do not overlap with each other.
• How much memory does the program need to store the two arrays?
 for invidual

### Activity 2: Printing memory addresses - II
Record the answer to the activity's questions here.
```C
#include <stdio.h>
int sum_ints(void) {
int integers[1024] = {1};
for (int i = 1; i < 1024; ++i) integers[i] = integers[i - 1] + 1;
return integers[1023];
}
double mul_doubles(void) {
double doubles[1024] = {sum_ints()};
for (int i = 1; i < 1024; ++i) doubles[i] = doubles[i - 1] * 0.999;
return doubles[1023];
}
int main(void) {
double result = mul_doubles();
printf("Result = %lf\n", result);
}
```
• What are the memory address ranges of both arrays?

• Do these memory address ranges overlap?
No, because they are alive at the same time.
• Does the lifetime of the two arrays overlap? Why (not)?
The lifetime of the two arrays do overlap, so that is why the address ranges do not overlap. When two arrays are alive at the same time, the address ranges of the two arrays have to be different from each other, so that the program will not crash.
• How much memory does the program need to store the two arrays?


### Activity 3: Using data that is no longer alive
Record the answer to the activity's questions here.
The following program is an attempt to create an array in a function. Compile and run this
program with the maximum warnings levels set: -Wall -Wextra -pedantic.
• Which warnings and / or errors does the compiler give when compiling this program?

• What do these warnings and / or errors mean?
It means that the programmer tried to return an address of a local variable (with automatic lifetime) inside the function even when the function exits.
• Does this approach to create an array at runtime work? Why (not)?
No, because the purpose of the program is to print the content of array from 1 to 10, but it will not work since in this program its trying to pass address that has been deallocated. it will show up undefined behvior and cannot do what the program intended to do.
segmentatio fault
### Activity 4: Using malloc

### Activity 5: Allocating zero bytes
What does the call to malloc return?
The address of the allocated memeory which is null
What happens if you try to store data in the block of memory obtained by malloc (by
storing a value at the address that was returned), and why does that happen?
Undefined behavior, in this case, malloc(0) still returns an address inside the heap. This is because of optimization, the system will still allocate memory on the heap when you try to call malloc(0), as the system thinks that you will later reallocate memory. Since the system have already allocated a memory block on the heap for you, you can store a value at that address.
Is it possible to allocate a block of memory that has a negative size?
Impossible, because malloc cannot take negative number as argument since its unsigned.
### Activity 6: Using allocated memory as an array
Record the answer to the activity's questions here.
```c
int * create_array(size_t capacity) {
int *ptr = (int*) malloc(capacity);
return ptr;
}
int main( void ) {
const size_t capacity = 24;
int * array = create_array(capacity);
for (size_t i = 1; i <= capacity; i++) array[i] = 42;
for (size_t i = 1; i <= capacity; i++) {
printf("array[%zu] = %d\n", i, array[i]);
}
}
```
How many int elements can be stored in the block of memory allocated by the create_array function?
6 elements
• What happens when you perform an out-of-bounds access to an array that is stored in
dynamically allocated memory?

Random value because you are trying to access array elemnts beyond the maximum array elements.
• What are the problems in the program listed below, and how can they be fixed (Include
the fixed program into your logbook)?

Fixed: 
out of bounnce

Another solution: inside the create_array() function, try calling mallo(capacity*sizeof(int)) instead of malloc(capacity).
### Activity 7: Fixing a memory leak
Record the answer to the activity's questions here.
```c
#include <stdio.h>
#include <stdlib.h>
int main(void) {
const int size = 1024 * 1024;
for (int i = 0; i < size; ++i) {
int * ptr = (int*) malloc(sizeof(int[size]));
if (ptr != NULL) ptr[0] = 0;
}
puts("All done!");
}
```

### Activity 8: Dangerous `free`s

1) try to call the free function on a
pointer that was not obtained using malloc, and

you cannot free memory from stack
(2) call free on a pointer, whose value is NULL.e answer to the activity's questions here.

you free nothing, nothing would happen.
### Activity 9: Using realloc
Record the answer to the activity's questions here.
```c
int main( void ) {
float *grades = NULL;
size_t capacity = 1024;
for (int count = 0; count < 10000; capacity += 1024, ++count) {
float *new_grades = (float*)realloc(grades, sizeof(float[capacity]));
if (new_grades != NULL){
grades = new_grades;
}
}
}
```
Solution: 
Another solution:
Of the 1000 calls to realloc, how often is the memory reallocated to another memory address?
8 times
```c
// Extended code
#include <stdio.h>
#include <stdlib.h>
int main( void ) {
float *grades = NULL;
size_t capacity = 1024;
for (int count = 0; count < 10000; capacity += 1024, ++count) {
float *new_grades = (float*)realloc(grades, sizeof(float[capacity]));
if (count>=0 && count<=1000) {
if (grades != new_grades) printf("the first 1000 calls, the block of memory is expanded\n");
} else if (grades != new_grades) printf("the block of memory is expanded\n");
if (new_grades != NULL){
grades = new_grades;
}
}
}
```
The memory is never reallocated to another memory address, but it's memory size keeps expanding.
### Activity 10: Using a dynamically sized buffer
Download the project for this activity from Blackboard.
Include your code & notes here.
#include <stdio.h> // for printf, fopen, fgetc
#include <stdlib.h> // for realloc & free
#include <assert.h> // for assert
/*
* Reads the file "E.coli.txt" into a dynamically allocated array
*/
int main( void ) {
char *ptr = NULL; // the memory address of the array
size_t capacity = 20; // the capacity of the array
const size_t capacityOGValue = capacity;
size_t count = 0; // the number of actual values stored in the array
ptr = realloc(ptr, sizeof(char[capacity])); // allocate memory
if (ptr == NULL){ // check if allocation worked
fprintf(stderr, "Memory allocation failed\n");
printf("Memory allocation failed\n");
return 1;
}
// open the file "E.coli.txt" for reading in text mode
FILE *file = fopen("E.coli.txt", "r");
if (file == NULL) { // check if file was opened
fprintf(stderr, "Error opening file\n");
return 1;
}
int c = fgetc(file); // read next character from file
while (c != EOF) { //expand size
if (count == capacity){
ptr = realloc(ptr, sizeof(char[capacity]) * sizeof(char[capacityOGValue]) * (count / sizeof(char[capacityOGValue]))); // allocate memory
capacity = capacity + capacityOGValue;
printf("%zu \n", capacity);
if (ptr == NULL){ // check if allocation worked
fprintf(stderr, "Memory allocation failed\n");
return 1;
}
}
ptr[count++] = (char) c; // store current character, then increase count
c = fgetc(file); // read next character from file
}
// count how many 'a's are in the file
int freq = 0;
for (size_t i = 0; i < count; ++i) if (ptr[i] == 'a') freq++;
printf("Character 'a' appears %d times in the array - this should be 1142069\n", freq);
// let the program crash if the frequency is not correct
assert(freq == 1142069);
free(ptr); // release the memory
}
Another solution:
```c
#include <stdio.h> // for printf, fopen, fgetc
#include <stdlib.h> // for realloc & free
#include <assert.h> // for assert
/*
* Reads the file "E.coli.txt" into a dynamically allocated array
*/
int main( void ) {
char *ptr = NULL; // the memory address of the array
size_t capacity = 20; // the capacity of the array
size_t count = 0; // the number of actual values stored in the array
ptr = realloc(ptr, sizeof(char[capacity])); // allocate memory
if (ptr == NULL){ // check if allocation worked
fprintf(stderr, "Memory allocation failed\n");
return 1;
}
// open the file "E.coli.txt" for reading in text mode
FILE *file = fopen("E.coli.txt", "r");
if (file == NULL) { // check if file was opened
fprintf(stderr, "Error opening file\n");
return 1;
}
int c = fgetc(file); // read next character from file
while (c != EOF) {
/* TODO: re-allocate memory pointed to by ptr if count == capacity
* TODO: check if the pointer returned by realloc is not NULL
*/
ptr[count++] = (char) c; // store current character, then increase count
if (count == capacity) {
capacity +=1024;
char *new_ptr = realloc(ptr, sizeof(char[capacity])); // allocate memory
if (new_ptr != NULL){
ptr = new_ptr;
}
}
c = fgetc(file); // read next character from file
}
// count how many 'a's are in the file
int freq = 0;
for (size_t i = 0; i < count; ++i) if (ptr[i] == 'a') freq++;
printf("Character 'a' appears %d times in the array - this should be 1142069\n", freq);
// let the program crash if the frequency is not correct
assert(freq == 1142069);
free(ptr); // release the memory
}
```
## Looking back
### What we've learnt
We have learnt about dynamic memeory and how you can use malloc to create user defined memory inside the heap.
### What were the surprises
That we have to free the memory inside the heap or else problems like files corruption could occur inside the system.
### What problems we've encountered
Question 1,2,7,9. We were debating about the memory range.
### What was or still is unclear
William: still little bit unclear why exactly the reasoning why you cannot free memory inside the stack but you could in malloc.