# Week 1 - Memory ## Team Team name: #include<coders> Date: 10.02.2022 Members | Role | Name | |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------| | **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. | Kuda | | **Reflector** observes and assesses the interactions and performance among team members. Provides positive feedback and intervenes with suggestions to improve groups’ processes. | Alexandru Stan | | **Recorder** guides consensus building in the group by recording answers to questions. Collects important information and data. | Luigi Negulescu | ## 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 #include <iostream> int main(){ int type_int; float floattype; char chartype; double doubletype; short int shortint; long int typelongint; long long int llint; long double typeldouble; printf("Size of int:\%u bytes\n", sizeof(type_int)); printf("Size of short int: \%u bytes\n", sizeof(shortint)); printf("Size of long int: \%u bytes\n", sizeof(typelongint)); printf("Size of long long int:\%u bytes\n", sizeof(llint)); printf("Size of float: %u bytes\n", sizeof(floattype)); printf("Size of double: %zu bytes\n", sizeof(doubletype)); printf("Size of long double: %zu bytes\n", sizeof(typeldouble)); printf("Size of char: %zu byte\n", sizeof(chartype)); } ### Activity 2: Array and structure sizes This is how you include code listings in your markdown document: ```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); } ``` Each element will took 4 bytes to be stored into array, so 4*10elements = 40 bytes. When you pass an array to a function, array will be implicitly converted to a pointer that points to the first element of the array. So, in the function size_array(int array[]) when the size of operator is used the result will be size of the pointer, which is usually 8 bytes. The size of the struct type does not differ. ### Activity 3: Memory addresses ```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); } ``` The characters of the string "Hello" are not stored near the variables a, b, s, and c. There are gaps between the variables. ![](https://i.imgur.com/chW7kp5.png) ### Activity 4: Observing automatic lifetime int add(int a, int b) { int c = a + b; printf("Address of a:%p\n ", (void*) &a); printf("Address of b:%p\n ", (void*) &b); printf("Address of c:%p\n ", (void*) &c); return c; } int mul(int x, int y) { int z = x * y; printf("Address of x:%p\n ", (void*) &x); printf("Address of y:%p\n ", (void*) &y); printf("Address of z:%p\n ", (void*) &z); return z; } int main( void ) { printf("%d\n", mul(add(3, 4), add(1, 5))); } When the program is running it allocates a piece of memory for functions. So when we call a function, we use that piece of memory to store the values of our variables and when the function is finished the values stored on the memory will be deleted and that piece of memory will be reused for other functions in the same way. ### Activity 5: Observing the stack int poly(int a) { int b = a * (a + 1); printf("Address of a :%p\n ", (void*) &a); printf("Address of b :%p\n ", (void*) &b); return b / 2; } int add_polys(int x, int y) { int bx = poly(x); int by = poly(y); printf("Address of x :%p\n ", (void*) &x); printf("Address of y :%p\n ", (void*) &y); printf("Address of bx:%p\n ", (void*) &bx); printf("Address of by:%p\n ", (void*) &by); return bx + by; } int main( void ) { printf("%d\n", add_polys(poly(42), poly(24)); } The memory addresses of any of these local variables are reused by other local variables, the possible explanation for it, could be that there is a function called in antoher function. ### Activity 6: Leaking local addresses After the variable "answer" is used, it gets automatically deleted and now the array "no_answer" is stored at the same memory address. ### Activity 7: Memory addresses of local variables When running the program one major error is "undefined reference to "do_some_work"". We think this error means that this void function does nothing and it's only declared with no scope, after the function declaration if you put "{ }" the program will run without errors. ### Activity 8: Using malloc int* allocate_memory(int count) { auto *ptr = (int *) malloc(sizeof(count)); return ptr; } int main() { auto variable1 = (unsigned long *) malloc(1* sizeof(unsigned long )); auto variable2 = (float*) malloc( 256* sizeof(float)); printf("%p",allocate_memory(5)); } ### Activity 9: Using allocated memory as an array 1. 5 integers can be stored 2. Accessing out of bounds elements is just undefined behavior, which means it might fail, and it might not. If, for instance, the memory allocator has provided a memory chunk larger than what you've asked for the array, the OS won't care if you go out of bound, because you'll be accessing memory that does belong to your process. 3. For storing 20 integers the capacity should be 80. ### Activity 10: Infinite memory? This program allocates 2^28 bytes of memory and it "crashes" when it remains out of memory. ### Activity 11: Fixing a memory leak const unsigned int block_size = 1 << 28; void *ptr = malloc(block_size); while (ptr != NULL) { ptr = malloc(block_size); free(ptr); } ### Activity 12: Dangerous `free`s The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs. ### Activity 13: Using realloc Just one free should be added, free(new_grades) ### Activity 14: Using a dynamically sized buffer int main( void ) { char *ptr = NULL; unsigned long capacity = 20; ptr = static_cast<char *>(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){ ptr = static_cast<char *>(realloc(ptr, 1.5 * sizeof(char[capacity]))); } ptr[count++] = (char) c; c = fgetc(file); } } ## Looking back ### What we've learnt During this week we have learned about the memory and how to use some useful functions such as malloc/realloc. ### What were the surprises There were no surprises. ### What problems we've encountered We had some problems during the activity 10 and 11 and we were not able to solve them. ### What was or still is unclear Altough we partially understood how things works in the memory it is not very clear yet how releasing memory works. ### How did the group perform? The group perfomed very well, we succesfully managed to finish most of the tasks except 2 activities that we did not understand very well. One thing that can be improved more i think is the communication.