22
. Plab – Tirgul 9 ex1 feedbacks

Plab – Tirgul 9 ex1 feedbacks. prelude Today we will see some common problems from ex1 Not all of them causes point reduction -but some cause bugs !

  • View
    214

  • Download
    1

Embed Size (px)

Citation preview

.

Plab – Tirgul 9

ex1 feedbacks

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

.

Memory relate bugs

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 );

.

Design and logics bugs

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

.

Efficiency & others

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

misc• What did we gain by:

int null = NULL;

const int ONE = 1;

const int ZERO = 0;

• README:

Many README’s contains “virus” information !

• Irrelevant comments & printings