Discussion Week 1 September 27, 2021 Today ● C++ intro ● valgrind ● gdb ● gprof ● makefiles C++ Important C++ Concepts for PA1 Pass by Value (Java) Pass by Reference (C++) The variable value is copied and stored in a new memory address void myFunc(int & a) {} Changes inside the function will not reflect on the original memory address Changes inside the function are made to the original memory address Important C++ Concepts for PA1 Garbage Collector (Java) Memory Management (C++) The garbage collector manages memory The programmer manages allocating and deallocating memory (“delete for every new”) C++ Resources 1. C++ Documentation 2. Stepik 1.4 The Fuss of C++ 3. Tutor Lab Hours Valgrind Valgrind Command for PA1 Valgrind Command for PA1 Memcheck is a memory error detector Valgrind Command for PA1 Memcheck is a memory error detector Leak-check Valgrind Command for PA1 Memcheck is a memory error detector Leak-check Executable Example 1 Common Mistake: Accessing elements past the end of an array Your program MIGHT segfault, or it might continue running, producing a result which is correct or incorrect -- sometimes with results varying between executions. Example 2 Common Mistake Forgetting to initialize a variable or array before using it. Errors Reported • The errors reported are for uninitialized values, and valgrind indicates where the access takes place. • If you run with the flag --track-origins=yes, valgrind will give additional information about where the uninitialized values came from. Example 3 Memory Leaks (Very Common!) Memory Leaks Reported • Valgrind includes an option to check for memory leaks. • With no flag given, it will list a heap summary where it will say if there is any memory that has been allocated but not freed. Live Debug Types of Memory Leaks • If you see leaks indicated as still reachable, this generally does not indicate a serious problem since the memory was probably still in use at the end of the program. • However, any leaks listed as "definitely lost" should be fixed (as should ones listed "indirectly lost" or "possibly lost"). How to look for memory leaks • If you use the new keyword, you’re allocating memory in the heap ○ Must be deleted in destructor or clear functions ○ Delete before moving pointers! GDB gdb ● ● Remember the -g and -O0 flags when compiling! To load file: gdb commands - run (r) ● ● Run the whole program with the command “run” (or “r”) Pass command line arguments after “run” (for example, “run file1” will make “file1” be argv[1]) Exits normally: Segmentation Fault: gdb commands - break (b) ● Set breakpoints with the command “break <location>” or “b <location>” ○ ○ ● Filename and line number: demo.cpp:27 Function name: my_func After setting breakpoints, run the file again (“run” or “r”) and it’ll stop at breakpoint gdb commands - print (p) ● At any point in the program, you can print variables to see their values ○ You can also dereference pointers! gdb commands - moving around the program ● ● The following commands can be used to run specific sections of your program: ○ Continue (c): run the program from the current location to the next breakpoint ○ Step (s): run the next line of the program (goes into functions) ○ Next (n): run the next line of the program (function calls are treated as a step) ○ Run (r): restart the program More commands: ○ Backtrace or where: prints a stack trace of the function calls in the program so far ○ Info breakpoints:lists your current breakpoints Live Debug gprof gprof ● ● When should you use gprof? ○ Code taking too long to run and don’t know where to look How to use gprof make Compiling with make More info on g++ flags: https://man7.org/linux/man-pages/man1/g++.1.html Testing Tips Testing Tips ● You can modify the provided test files! ○ Add print statements ○ Add other tests ○ Run the tests using a hardcoded value ■ ● Most of our provided tests are randomized You can add main functions to files that don’t have any ○ Write your own tests to make sure construction is right Local Environment Setup https://docs.google.com/document/d/1XqQ6AwEFNaEbdRl RMXhDvXVAb8nc8R4-eVG06pHHz4Q/edit?usp=sharing Reminders ● PA1 Due Tuesday 10/5 @ 10PM ● Reading Quiz due tomorrow at 8AM ● My office hours are on Mon, Tues, Thurs @2pm ● Check Ed calendar for lab hours! Extra C++ Practice Problems What will be printed when this code executes? void mystery(int* ptr, int y) { y = 4; ptr = &y; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } a) b) c) d) e) 15 21 4 Error Something else What will be printed when this code executes? void mystery(int* ptr, int y) { y = 4; ptr = &y; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } a) b) c) d) e) 15 21 4 Error Something else What will be printed when this code executes? void mystery(int* ptr, int y) { y = 4; ptr = &y; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } 15 What will be printed when this code executes? void mystery(int* ptr, int y) { y = 4; ptr = &y; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } 15 21 What will be printed when this code executes? void mystery(int* ptr, int y) { y = 4; ptr = &y; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } 15 21 0x20 What will be printed when this code executes? void mystery(int* ptr, int y) { y = 4; ptr = &y; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } 0x20 21 15 21 0x20 What will be printed when this code executes? void mystery(int* ptr, int y) { y = 4; ptr = &y; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } 0x20 4 15 21 0x20 What will be printed when this code executes? void mystery(int* ptr, int y) { y = 4; ptr = &y; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } 0x20 0x160 4 15 21 0x20 What will be printed when this code executes? void mystery(int* ptr, int y) { y = 4; ptr = &y; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } Output is: 15 0x160 4 15 21 0x20 What will be printed when this code executes? void mystery(int* ptr, int y) { y = 4; *ptr = y; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } a) b) c) d) e) 15 21 4 Error Something else What will be printed when this code executes? void mystery(int* ptr, int y) { y = 4; *ptr = y; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } a) b) c) d) e) 15 21 4 Error Something else What will be printed when this code executes? void mystery(int* ptr, int y) { y = 4; *ptr = y; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } 15 What will be printed when this code executes? void mystery(int* ptr, int y) { y = 4; *ptr = y; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } 15 21 What will be printed when this code executes? void mystery(int* ptr, int y) { y = 4; *ptr = y; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } 15 21 0x20 What will be printed when this code executes? void mystery(int* ptr, int y) { y = 4; *ptr = y; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } 0x20 21 15 21 0x20 What will be printed when this code executes? void mystery(int* ptr, int y) { y = 4; *ptr = y; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } 0x20 4 15 21 0x20 What will be printed when this code executes? void mystery(int* ptr, int y) { y = 4; *ptr = y; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } 0x20 4 15 4 21 0x20 What will be printed when this code executes? void mystery(int* ptr, int y) { y = 4; ptr* = y; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } Output is: 4 0x20 4 4 21 0x20 What’s the Difference? void mystery(int* ptr, int y) { y = 4; ptr = &y; } void mystery(int* ptr, int y) { y = 4; *ptr = y; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } What’s the Difference? In the first case we are updating the value stored in ptr (a memory address). In the second case we are dereferencing ptr and updating the value stored at the memory address that is stored in ptr. void mystery(int* ptr, int y) { y = 4; ptr = &y; } void mystery(int* ptr, int y) { y = 4; *ptr = y; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } How can we modify this code? void mystery(int* ptr2, int & y2) { y2 = 4; ptr2 = &y2; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } Quick check: what does main print? How can we modify this code? void mystery(int* ptr2, int & y2) { y2 = 4; ptr2 = &y2; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } Quick check: what does main print? 15 How can we modify this code? void mystery(int* ptr2, int & y2) { y2 = 4; ptr2 = &y2; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } Quick check: Draw memory model What will be printed when this code executes? void mystery(int* ptr2, int & y2) { y2 = 4; ptr2 = &y2; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } 15 What will be printed when this code executes? void mystery(int* ptr2, int & y2) { y2 = 4; ptr2 = &y2; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } 15 21 What will be printed when this code executes? void mystery(int* ptr2, int & y2) { y2 = 4; ptr2 = &y2; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } 15 21 0x20 What will be printed when this code executes? void mystery(int* ptr2, int & y2) { y2 = 4; ptr2 = &y2; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } 0x20 15 21 0x20 What will be printed when this code executes? void mystery(int* ptr2, int & y2) { y2 = 4; ptr2 = &y2; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } 0x20 15 4 0x20 What will be printed when this code executes? void mystery(int* ptr2, int & y2) { y2 = 4; ptr2 = &y2; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } 0x40 15 4 0x20 What will be printed when this code executes? void mystery(int* ptr2, int & y2) { y2 = 4; ptr2 = &y2; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } 0x40 15 4 0x20 What will be printed when this code executes? void mystery(int* ptr2, int & y2) { y2 = 4; ptr2 = &y2; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } Output is: 15 0x40 15 4 0x20 How can we modify this code? void mystery(int* ptr2, int & y2) { y2 = 4; ptr2 = &y2; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(ptr, y); cout << *ptr; return 0; } How can we change the code so this line modifies ptr in main? How can we modify this code? void mystery( int** ptr2, int & y2) { y2 = 4; *ptr2 = &y2; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(&ptr, y); cout << *ptr; return 0; } How can we change the code so this line modifies ptr in main? One solution: Pass in a pointer to the pointer! Let’s look at the memory model void mystery(int** ptr2, int & y2) y2 = 4; *ptr2 = &y2; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(&ptr, y); cout << *ptr; return 0; } { 0x80 15 21 0x20 Let’s look at the memory model void mystery(int** ptr2, int & y2) { y2 = 4; *ptr2 = &y2; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(&ptr, y); cout << *ptr; return 0; } 0x80 15 4 0x20 Let’s look at the memory model void mystery(int** ptr2, int & y2) { y2 = 4; *ptr2 = &y2; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(&ptr, y); cout << *ptr; return 0; } 0x80 15 4 0x40 What will be printed when this code executes? void mystery(int** ptr2, int & y2) { y2 = 4; *ptr2 = &y2; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(&ptr, y); cout << *ptr; return 0; } Output is: 4 0x80 15 4 0x40 How can we modify this code? void mystery( int** ptr2, int & y2) { y2 = 4; *ptr2 = &y2; } int main() { int x = 15; int y = 21; int* ptr = &x; mystery(&ptr, y); cout << *ptr; return 0; } How can we change the code so this line modifies ptr in main? One solution: Pass in a pointer to the pointer! Another solution: Reference to a pointer (int *& ptr2) What is the output? int main() { vector<int> v = {1, 2, 3, 4}; for (int i : v) { } i = 0; for (int i = 0; i < 4; i++) { cout << v[i] << “, ”; } } a) 1, 2, 3, 4, b) 0, 0, 0, 0, c) Error d) Something else What is the output? int main() { vector<int> v = {1, 2, 3, 4}; for (int i : v) { } i = 0; for (int i = 0; i < 4; i++) { cout << v[i] << “, ”; } } a) 1, 2, 3, 4, b) 0, 0, 0, 0, c) Error d) Something else What is the output? int main() { vector<int> v = {1, 2, 3, 4}; for (int& i : v) { } i = 0; for (int i = 0; i < 4; i++) { cout << v[i] << endl; } } a) 1, 2, 3, 4, b) 0, 0, 0, 0, c) Error d) Something else What is the output? int main() { vector<int> v = {1, 2, 3, 4}; for (int& i : v) { } i = 0; for (int i = 0; i < 4; i++) { cout << v[i] << endl; } } a) 1, 2, 3, 4, b) 0, 0, 0, 0, c) Error d) Something else