* How to avoid errors in programs? * If an error happen, how can we find it? * What can go wrong with the program below? #include unsigned myStrLen(char* s) { int len = 0; char* p = s; while (*p != '\0') { p++; len++; } return len; } int main(int argc, char** argv) { std::cout << "Len " << argv[1] << " = " << myStrLen(argv[1]) << std::endl; return 0; } * How can you try to identify the error? #include #include unsigned myStrLen(char* s) { assert(s != NULL); int len = 0; char* p = s; while (*p != '\0') { p++; len++; } return len; } int main(int argc, char** argv) { assert(argc == 2); std::cout << "Len " << argv[1] << " = " << myStrLen(argv[1]) << std::endl; return 0; } * What are assertions good for? * How can you see the code that is produced by the assertion? * How to disable the assertion? #define NDEBUG #include * What are common errors in C/C++? * What will be printed by the program below? #include struct Data { int x; }; Data foo(Data d) { return d; } int main() { Data d0; d0.x = 1; Data d1 = foo(d0); std::cout << "Data = " << d1.x << std::endl; d0.x = 2; std::cout << "Data = " << d1.x << std::endl; } - Remember: in C++, parameters and return values are passed by copy! * What will be printed by the program below? #include void arithProg(int* limit, int* sum) { *sum = 0; for (int i = 0; i < *limit; i++) { *sum += i; } } int main() { int S, N = 10; arithProg(&N, &S); std::cout << S << std::endl; } * And now, what will be printed by this new 'main'? int main() { int S, N = 10; arithProg(&N, &S); std::cout << S << std::endl; arithProg(&N, &N); std::cout << N << std::endl; } * Could you use assertions to flag this problem? #include void arithProg(int* limit, int* sum) { assert(limit != sum); *sum = 0; for (int i = 0; i < *limit; i++) { *sum += i; } } * Why doesn't the program below do what you want? #include void arithProg(int* limit, int* sum) { assert(&limit != &sum); *sum = 0; for (int i = 0; i < *limit; i++) { *sum += i; } } - Remember: updates in a pointer might change other pointers! * What will be printed by the program below? #include struct Data { int x; }; Data* getData(int value) { Data d; d.x = value; return &d; } int main() { Data *d0 = getData(0); Data *d1 = getData(1); std::cout << "Data = " << d0->x << std::endl; std::cout << "Data = " << d1->x << std::endl; } * What is the problem with this program? * What is the meaning of the warning? E.g.: "dangling0.cpp:10:11: warning: address of stack memory associated with local variable 'd' returned [-Wreturn-stack-address]" * How could you fix it? #include struct Data { int x; }; Data* getData(int value) { Data *d = new Data(); d->x = value; return d; } int main() { Data *d0 = getData(0); Data *d1 = getData(1); std::cout << "Data = " << d0->x << std::endl; std::cout << "Data = " << d1->x << std::endl; } - Remember: you cannot access local variables after the function where they exist returns! * What is the value that the program below prints? #include struct Data { int x; }; int main() { Data *d0 = new Data(); d0->x = 0; std::cout << d0->x << std::endl; delete d0; Data *d1 = new Data(); d1->x = 1; d0->x = 2; std::cout << d1->x << std::endl; } - Remember: you cannot access the contents of a pointer after deletion. * What is the value that this program below prints? #include int main() { int a[1] = {17}; int b[1] = {19}; b[1] = 3; std::cout << a[0] << std::endl; } * What is the problem with this program? * Can you check the addresses of the arrays? #include #include int main() { int a[1] = {17}; int b[1] = {19}; printf("%p\n%p\n%p\n%p\n", (void*)&b, (void*)&b[1], (void*)&a, (void*)&a[1]); b[1] = 3; std::cout << a[0] << std::endl; } * What is the meaning of the warning that we get? "array.cpp:7:3: warning: array index 1 is past the end of the array (which contains 1 element) [-Warray-bounds]" - Remember: arrays cannot be accessed outside their bounds! * What does the program below print? #include int searchArray(int to_search[], int len, int to_find) { int i; for( i = 0; i < len; ++i) { if ( to_search[i] == to_find) { return i; } } } #define N 6 int main() { int x[N] = {2, 3, 5, 7, 11, 13}; std::cout << searchArray(x, N, 5) << std::endl; } * What about the following main function? int main() { int x[N] = {2, 3, 5, 7, 11, 13}; std::cout << searchArray(x, N, 8) << std::endl; } * What is the problem with the code above? * What is the meaning of the warning? "ret0.cpp:10:1: warning: control may reach end of non-void function [-Wreturn-type]" * How could you fix the program above? - Remember: if a function returns a value, it must do it through any path that the function contains. * What about the following fix? Does it work? #include int searchArray(int to_search[], int len, int to_find) { int i = -1; for( i = 0; i < len; ++i) { if ( to_search[i] = to_find) { return i; } } return i; } #define N 6 int main() { int x[N] = {2, 3, 5, 7, 11, 13}; std::cout << searchArray(x, N, 5) << std::endl; } * What is the meaning of the warning? "ret0.cpp:6:23: warning: using the result of an assignment as a condition without parentheses [-Wparentheses]" * What is actually that code above doing? - Remember: the expression "if(a = x)" is valid in C/C++! * What does the program below print? #include char last(char* s) { int i, l; for(i = 0; s[i] != '\0'; ++i) { l = s[i]; } return l; } int main(int argc, char** argv) { for (int i = 1; i < argc; i++) { std::cout << "Last char: " << last(argv[i]) << std::endl; } } * How could we deal with this problem? #include #include char last(char* s) { assert(strlen(s) > 0); int i, l; for(i = 0; s[i] != '\0'; ++i) { l = s[i]; } return l; } int main(int argc, char** argv) { for (int i = 1; i < argc; i++) { std::cout << "Last char: " << last(argv[i]) << std::endl; } } - Remember: every variable must be initialized before being used! * What is the problem with this program below? #include void logic1(int n) { if (n != 1 || n != 2) { std::cout << n << " is odd prime, or has non-trivial divisor\n"; } } int main(int argc, char** argv) { logic1(argc); } * Can you write the truth table for n != 1 || n != 2 n n!=1 n!=2 || 1 0 1 1 2 1 0 1 ? 1 1 1 * What's the problem of the expression? - It will never be false. * Can you pin-point the problem with this function, that does the same thing? void logic1(int n) { if (!(n == 1 && n == 2)) { std::cout << n << " is odd prime, or has non-trivial divisor\n"; } } - Remember: there are different ways to combine ==, !=, && and ||, and several of them make no sense! * What does this program below print? #include int prec(int n, int m) { return 2 + n > m ? n : m; } int main() { std::cout << prec(10, 11) << std::endl; } * How to fix this program? #include int prec(int n, int m) { return 2 + (n > m ? n : m); } int main() { std::cout << prec(10, 11) << std::endl; } - Remember: the ternary operator has very low priority! * What is a debugger? * Can you give me examples of debuggers? - gdb, lldb, ipdb, pydb, etc * Can you inspect every command of the program below in action? #include int main(int argc, char** argv) { std::cout << "Hello World!\n"; return 0; } * What does the '-g' flag does? $> clang++ -g hello.cpp * How can we use lldb to see the commands executed one-by-one? $> lldb a.out (lldb) process launch ... (lldb) breakpoint set -name main (lldb) process launch ... (lldb) frame variable ... (lldb) frame variable argv[0] ... (lldb) thread step-out * Can you explain what each statement above does? * Consider the program below, which contains an index out of bounds error. Can you find the error using lldb? #include #include int foo(int v) { int a[1]; a[1] = 17; return a[1] + v; } int main() { int x = 25; std::cout << foo(x) << std::endl; } * How can you use lldb on the program above? $> clang++ -g stack.cpp $> lldb a.out (lldb) breakpoint set -name foo (lldb) process launch (lldb) thread backtrace (lldb) frame variable &a[1] ... (lldb) frame variable &v ... * So, what's going on with the program above? * How can you set up an input file? (lldb) setting set target.input-path t.txt (lldb) process launch - or - (lldb) process launch -i t.txt * How can you find the bug in buggy.cpp using lldb? $> lldb buggy.exe (lldb) process launch (lldb) thread backtrace (lldb) memory read --format x --count 1 0x7ffeefbff6a4 # "consider also:" (lldb) x/w 0x00007ffeefbff6a4 (lldb) breakpoint set --name LinkedList::remove (lldb) breakpoint modify -c "item_to_remove==1" (lldb) frame variable item_to_remove (lldb) thread step-over