200 likes | 334 Views
Plab – Tirgul 4 structs & arrays, file I/O, debugging memory errors. Assignment: struct vs. pointer to struct. struct Complex { double x,y; };. Complex *cp1, *cp2; cp1 = (Complex*)malloc ... cp2 = (Complex*)malloc ... cp1->x=7; cp1->y=3; cp2 = cp1;. Complex c1, c2; c1.x=7; c1.y=3;
E N D
Plab – Tirgul 4structs & arrays, file I/O,debugging memory errors .
Assignment: struct vs. pointer to struct struct Complex { double x,y;}; Complex *cp1, *cp2;cp1 = (Complex*)malloc ...cp2 = (Complex*)malloc ...cp1->x=7; cp1->y=3; cp2 = cp1; Complex c1, c2;c1.x=7; c1.y=3; c2 = c1; x=7 garbage x=7 x=7 y=3 garbage y=3 y=3 c1 c2 cp1 cp2
Arrays & structs as arguments • When an array is passed as an argument to a function, the address of the 1st element is passed. • Structs are passed by value, exactly as the basic types.
Arrays & structs as arguments struct MyStr { int a[10]; }; void f(int a[]) { a[7] = 89; } void g(MyStr s) { s.a[7] = 84; } main() { MyStr x; x.a[7] = 0; f(x.a); printf("%d\n", x.a[7]); g(x); printf("%d\n", x.a[7]); } Output: 89 89
argv & argc • To pass command line arguments to our program we should use the following main declaration: main(int argc, char* argv[]) { ... • Compare to main(String[] args) in java. • Unlike java the first argument is the name of the program itself. • char** argv • char argv[][]
argv & argc: example • $ prog1 –u danny –p 1234argc = 5 argv[0] = “prog1” argv[1] = “-u” ... argv[4] = “1234”Always: argv[argc] = 0
Default function arguments • We can specify default value for trailing arguments of a function. • An alternative to overloading. • Example:print(int value, int base=10) { . . .print(31, 16);print(31);// equivalent to print(31,10) h(int x=0, int y) // error! Only in C++ Only in C++
File I/O • File I/O is mostly similar to stdin & stdout I/O. • Most I/O functions we encountered have a “file” counterpart which receives a FILE pointer (handle). • Examples:getchar(void) fgetc(FILE*) scanf(const char *,...) fscanf(FILE*, const char*,...)printf(const char *,...) fprintf(FILE*, const char*,...) • The standard streams (stdin, stdout, stderr) are also of FILE* type. See related man pages: fprintf, fscanf, etc.
File I/O example: mywc #include <stdio.h>#include <errno.h>#include <ctype.h>main(int argc, char* argv[]) { FILE* fp; int wc = 0, ch; if (argc != 2) { printf("Usage: mywc <filename>\n"); exit(1); } errno = 0; fp = fopen(argv[1], "r"); if (fp == NULL) { perror(“”); exit(1); }
File I/O example while (1) { while ((ch = fgetc(fp)) != EOF && isspace(ch)) ; if (ch == EOF) break; wc++; while ((ch = fgetc(fp)) != EOF && !isspace(ch)) ; if (ch == EOF) break; } fclose(fp); printf("There are %d words in %s\n", wc, argv[1]); return 0; } Related man pages: fopen, fclose
Memory related bugs • Memory leaks. • Accessing random/freed memory addresses (e.g. off-by-one errors). .
malloc_stats() • By including malloc.h you can use the malloc_stats() function which prints to the stderr information about the amount of used memory. • Example: . . . malloc_stats(); destroyDictionary(dict); malloc_stats(); . . .
malloc_stats() cntd. With memory leak: Arena 0: system bytes = 8140 in use bytes = 6860 . . . Arena 0: system bytes = 8140 in use bytes = 4084 . . . Without memory leak: Arena 0:system bytes = 8124 in use bytes = 6860. . . Arena 0:system bytes = 8124 in use bytes = 4 . . .
mtrace • Log all memory allocations to a file. • The file name is contained in the MALLOC_TRACE environment variable. • For example:$setenv MALLOC_TRACE ~/plab/ex1/trace • Analyze the file to find memory leaks using the mtrace utility. • The program must: • be compiled with –g flag • #include <mcheck.h>
mtrace example The program: #include <mcheck.h> int main() { mtrace(); // later we can call muntrace() . . . The trace file looks like this: = Start @ [0x80486fd] + 0x804a0e0 0x8 @ [0x804887d] + 0x804a0f0 0x8 @ [0x8048c7d] + 0x804a100 0x14 @ /lib/libc.so.6:(__strdup+0x29)[0x400d7a29] + 0x804a118 0x5 @ [0x8048c7d] + 0x804a128 0x14 @ /lib/libc.so.6:(__strdup+0x29)[0x400d7a29] + 0x804a140 0x3 @ [0x8048c7d] + 0x804a150 0x14. . .
mtrace example cntd. The result of analysis ($ mtrace ex1 trace) Memory not freed: ----------------- Address Size Caller 0x0804a100 0x14 at /home/mush/plab/ex1/strBinTree.c:65 0x0804a128 0x14 at /home/mush/plab/ex1/strBinTree.c:65 0x0804a150 0x14 at /home/mush/plab/ex1/strBinTree.c:65 Another example: Memory not freed: ----------------- Address Size Caller 0x0804a118 0x5 at /lib/libc.so.6:(__strdup+0x29)[0x400d7a29] 0x0804a140 0x3 at /lib/libc.so.6:(__strdup+0x29)[0x400d7a29]
MALLOC_CHECK_ • By setting this environment variable to 0, 1, 2we can handle some bugs, most notably freeing twice the same memory. • Usually double free causes segmentation fault. • When MALLOC_CHECK_ is 0 freeing twice works. • When MALLOC_CHECK_ is 1 an error message is printed. • Example: free(): invalid pointer 0x80497b8! • When MALLOC_CHECK_ is 2 the program (gracefully) aborts.
ElectricFence • ElectricFence is a library which allows to catch accesses to memory that was already freed, as well as off-by-one errors. • It will cause the program to segfault in the above cases, which is usually better than continue running and have unpredictable errors later. Example: char* a = (char*)malloc(100*sizeof(char));. . . a[100] = 'c'; // ElectricFence will cause segfault
ElectricFence cntd. Example: Node* n1 = (Node*)malloc(sizeof(Node));. . . free(n1); . . . n1->x = 7; // ElectricFence will cause segfault • To use ElectricFence you should link your program with the efence library. • For example:g++ prog1.o list.o read.o -lefence
Commercial products • Purify • BoundsChecker • MS’s VisualStudio