View
214
Download
1
Embed Size (px)
Citation preview
prelude
• Today we will see some common problems from ex1
• Not all of them causes point reduction
- but some cause bugs !
• Code examples are taken from your files
Bugs are not ours“… Because you’ve only got the symptoms,
you haven’t got the whole disease.”
• Symptoms:Program crashes in “strdup” or “strlen”
• Cure: Write myStrdup and myStrlen
• Outcome: No crash
• Suggested disease: bugs in strdup? magic?
Bugs are not ours (cont.)• The real problem:
Accessing unallocated memory. The crash will occur somewhere/sometime else.
• e.g. In our tests
Bottom line:• Don’t ignore bugs, confront them!• Bugs are yours!
More bugsint getAppearancesNum( Dictionary const* dic,
char const* word ) {
if ( word == NULL || dic == NULL ||
dic->tree == NULL ) {
return e_dic_error;
}
int * count = getAccessToValue( dic-
>tree,strdup(word) );
if( count != NULL ){
return *count;
}
return e_dic_error;
}
Many functions, not just malloc, allocate memory!
Bad programming
(1) int * err = (int*) malloc(sizeof(int));
(2) assert(err != NULL);
(3) char* word =
getSuccessorKey( dic->tree, NULL, err);
Much better:
(1) int err;
(2) char* word =
getSuccessorKey( dic->tree, NULL, &err);
//efficient, clear, easy for maintainace
char * getSuccessorKey( const StrBinTree * tree ,const char * key, int *
rc );
Algorithm Designimplementation of
getSuccessorKey( Tree, key )
How do we approach this? “root-down” “node-up”
Dedicate extra time on thinking -> save lots of time on
debugging!!
Solution #1 – node-up
Step 1: Find node corresponding to key
Step 2: Traverse the tree: Internal node rightmost
leaf Leaf top most ancestor
where you are left son
door
banana foo
barapple
Needs: Keeping pointer to parents Complex logics (many sub-cases)
Solution #2 – root-down Top-down (divide & conquer):
if curr == key smallest element on the right
if curr < key call recursively on the right
if curr > key call recursively on left side (if returns null – return curr)
door
banana foo
barapple
Recursive Only “downward” pointers Simpler logic to program
less debugging, patches, etc.
Solution #2 – implementation
StrBinTreeNode* findSuccessorNode(StrBinTreeNode* subtree, char const* key) {
if (subtree == NULL) return NULL;
if (strcmp(subtree->key, key) <= 0) return findSuccessorNode(subtree->right, key);
StrBinTreeNode* leftTreeSuccessor = findSuccessorNode(subtree->left, key);
if (leftTreeSuccessor == NULL) return subtree;
return leftTreeSuccessor;}
This recursion does most of the work:
void deleteTree(StrBinTreeNode * tree) { if(tree!=NULL){
if(tree -> left != NULL) deleteTree(tree -> left);
if(tree -> right != NULL) deleteTree(tree ->
right); else{
free(tree->key); free(tree);
} }}
int destroyTree(StrBinTree * tree) { if(tree==NULL) return e_StrBinTree_error;
deleteTree(tree->root); free(tree); return e_StrBinTree_success;
}
When this code will be activated?
more basicsSurprisingly common bug – omitting the “else”: if ( parent == left ) incrementSon( left->parent );incrementSon( left->parent ); //the else is missing!
if ( parent == left ) incrementSon( left );if ( doTraverse )
incrementSon( right ) //should have been if-else
Lesson
• Don’t be “addicted” to automatic tools-debugger, malloc_stats, efence
• Examine the logics of your code!-Many times the quickest way
Multiple calls for the same func.if ( strcmp(father->key,son) == 0 ) {…
}else if ( strcmp(father->key,son) < 0 ) {…
}else if ( strcmp(father->key,son) > 0 ) {…
}
• Inefficient !!!Call strcmp once, keep it in a variable.
multiple function calls
for (i=1; i < numWords; i++) { firstWord = writeWord(outFile, dic, firstWord, &rc);
}
• Efficiency problem:Function’s calls have overhead.Better do the loop inside the function.
• Tradeoff with readability
Dynamic array• Reading a word of size n• Using dynamically growing array
• By additive factor:• Example: size = size + 100• Elements are copied O(n) times
• Growing by a multiplicative factor:• Example: size = size*2• Elements are copied O(logn) times
Makefile: dependencies errorsdictionary.o: strBinTree.c …
dictionary.o: strBinTree.h …
dictionary.o: ex1.c …
ex1: strBinTree.h …
Note: ex1.c shouldn’t include strBinTree.h
// wrong
// wrong
// wrong
// good
others1. non-useful code:
assert (node != NULL );
if (node == NULL )
return NULL; //unreachable
2. No “usage” printing:
assert( argc == 4);// bad
assert( argc = 4 );// very bad• In “main” you can return an error code• It is customary to print usage instructions