1 / 43

Modular Programming

Modular Programming. Advantages of using functions (to make a modular program) are: Changing the program into separate pieces Code reusing Easier modification and maintenance of the program More understandable program

ghalib
Download Presentation

Modular Programming

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Modular Programming Advantages of using functions (to make a modular program) are: Changing the program into separate pieces Code reusing Easier modification and maintenance of the program More understandable program Functions can be called from anywhere in the main program with different input data Functions enable the programmers to generate their own libraries of the functions. How is the information exchanging between the main function and function subprograms?

  2. Functions with input arguments The arguments of the functions are used to carry information between the function subprogram and the main function Input arguments carry information into the function subprogram Output arguments are the return results of the functions Examples: c = factorial(n) / (factorial(r)*factorial(n-r)); print_rboxed(135.68); actual parameters

  3. Calling print_rboxed(135.68) /* * Displays a real number in a box. */ void print_rboxed(double rnum) { printf("***********\n"); printf("* *\n"); printf("* %7.2f *\n", rnum); printf("* *\n"); printf("***********\n"); } *********** * * * 135.68 * Formal Parameter * * ***********

  4. /* * Computes n! for n greater than or equal to zero */ int indicates function result is an integer number factorial(int n) { int i, /* local variables */ product = 1; /* Computes the product n x (n-1) x (n-2) x ... x 2 x 1 */ for (i = n; i > 1; --i) { product *= i; } /* Returns function result */ return (product); }

  5. Functions with input arguments • The local and formal parameters of a function cannot be referenced by name in other functions • Functions can not reference the variables defined in the main by the name • Functions can use the constant names (#define ..) if they are in the same file. Also functions should have been defined after the constant names definition

  6. Syntax of function definition function interface comment return-type function-name(formal parameter declaration list) { local variable declarations executable statements } Example: /* Finds the larger of two numbers */ double bigger(double n1, double n2) { double larger; if (n1 > n2) larger=n1; else larger=n2; return(larger); }

  7. A function can be called with different actual parameters. for example for finding the number of combinations of selecting 2 items from 6 items without regards to order main program calls factorial 3 times: c = factorial(6) / (factorial (2) * factorial(6-2); • Calling factorial with n=6 in the main program int factorial(int n) value of 6 copies into n { int i, /* local variables */ product = 1; /* Computes the product n x (n-1) x (n-2) x ... x 2 x 1 */ for (i = n; i > 1; --i) { product *= i; } /* Returns function result */ return (product); Returns the result value of 720 }

  8. Logical FunctionsThe type int result by a function can be interpret as a logical value: Function That Checks Whether a Value Is Even /* * Indicates whether or not num is even (divisible by 2): * returns 1 if it is, 0 if not */ int even(int num) { int ans; ans = ((num % 2) == 0); return (ans); }

  9. Function with Multiple Arguments /* * Multiplies its first argument by the power of 10 specified * by its second argument. */ double scale(double x, int n) { double scale_factor; /* local variable */ scale_factor = pow(10, n); return (x * scale_factor); } • A function can be tested by a program (driver program) included main function and a call to that function

  10. Testing Function scale /* * Tests function scale. */ #include <math.h> /* Function prototype */ double scale(double x, int n); int main(void) { double num 1; int num 2; /* Get values for num 1 and num 2 */ printf("Enter a real number> "); scanf("%lf", &num 1); printf("Enter an integer> "); scanf("%d", &num 2); /* Call scale and display result. */ printf("Result of call to function scale is %.3f\n", scale(nu_m 1, num 2)); return (0); }

  11. double scale(double x, int n) { double scale_factor; /* local variable - 10 to power n */ scale_factor = pow(10, n); return (x * scale_factor); } ---------------- Output: Enter a real number> 2.5 Enter an integer> -2 Result of call to function scale is 0.025 ------------------- After calling function scale in the main Function main data area Function scale data area num_1 = 2.5 x=2.5 num_2= -2 n=-2 scale_factor=?

  12. Argument List Correspondence • The number of actual arguments in a call to a function must be the same as the number of formal arguments listed in the function definition • The order of actual argument must be the same as the order of formal arguments • Each actual argument must be of a data type that can be assigned to the corresponding formal parameter with no unexpected loss of information

  13. Case Study with Top-Down Design • Problem: Write a program that finds the smallest divisor of a number or determines that the number is a prime number. • Analysis Constant: NMAX 1000 Input: int n Output: int min_div

  14. Design Algorithm: • Get the number to check whether it is prime 1.1 Get a value for n 1.2 if n < 2 Display an error message else if n <= NMAX Do Step 2 and 3 else Display an error message 2. Find smallest divisor other than 1, or determine number is prime 3. Display smallest divisor or a message number is prime 3.1 if the smallest divisor is n Display a message that n is prime else Display the smallest divisor of n

  15. #include <stdio.h> #define NMAX 1000 Int main(void) { int n, /* ckeck for prime*/ min_div; /* minimum divisor */ /* Gets a number to test. */ printf("Enter a number that you think is a prime number> "); scanf("%d", &n); /* Checks that the number is in the range 2...NMAX */ if (n < 2) { printf("Error: number too small. The smallest prime is 2.\n"); } else if (n <= NMAX) { /* Finds the smallest divisor (> 1) of n */ min_div = find_div(n); /* Displays the smallest divisor or a message that n is prime. */ if (min_div == n) printf("%d is a prime number.\n", n); else printf("%d is the smallest divisor of %d.\n", min_div, n); } else { printf("Error: largest number accepted is %d.\n", NMAX); } return (0); }

  16. Step 2 as a sub-problem: Function find_div • Analysis • Input (formal parameter) int n • Output (result to return) int divisor • Local variable int trial • Design 1. if n is even, set divisor to 2, otherwise, set divisor to 0 and trial to 3 2. As long as divisor is 0, keep trying odd integers (trial). If a divisor is found, store it in divisor. If trial exceeds , store n in divisor. 3. Return divisor

  17. #include <math.h> /* Finds the smallest divisor of n between 2 and n (n is greater than 1) */ Int find_div(int n) { int trial, /* current candidate for smallest divisor of n */ divisor; /* smallest divisor of n; zero means divisor not yet found */ /* Chooses initialization of divisor and trial depends on n being even or odd. */ if (even(n)) { divisor = 2; } else { divisor = 0; trial = 3; } /* Tests each odd integer as a divisor of n until a divisor is found */ while (divisor == 0) { if (trial > sqrt(n)) divisor = n; else if ((n % trial) == 0) divisor = trial; else trial += 2; } return (divisor); /* Returns problem output to calling module. */ }

  18. Function Output Parameters with Pointers • So far the return part of a function ,at most could only return one result value. • By using pointers functions can return multiple result values to the caller • So far the input argument values could be passed only by the values. It means the value of actual parameters are copied into the value of formal parameters and call to the functions can not change value of arguments. • By using pointers the address of the arguments can be passed to the functions and the value of these arguments can be changed by the functions. For example the second argument of the scanf or fscanf is passing by address when calling scanf of fscanf

  19. Pointers • A pointer is a variable whose value is the address of a memory cell that reserved for another variable For example: int *nump means nump is a pointer to another variable of type int: n nump • Each pointer has two parts: 1- Direct value of a pointer, which is an address of a memory cell. For example nump is 1024 2- Indirect value of a pointer, which is the value of the memory cell whose address is the pointer’s direct value. For example *nump is 84 84 1024

  20. Meaning of * Symbol “*” can be used for all of these purposes • Binary operator. For example: 2 * 3 means 2 times 3 • For file pointer. For example FILE *inp; means inp is a pointer to file • Definition of the pointers. For example: char *singp; means signp is of type “pointer to char”. Note that signp is address of a memory cell. 4. Unary operator. for example “*nump” gets 84 which is the int value and can be used in the expressions. Also “*singp” is a char value such as ‘a’ or ‘b’

  21. Example of a function that uses arguments of the type of pointers /*Separates a number into three parts: a sign (+, -, or blank), a whole number magnitude, and a fractional part.*/ void separate(double num, /* input - value to be split */ char *signp, /* output - sign of num */ int *wholep, /* output - whole number magnitude of num */ double *fracp) /* output - fractional part of num */ { double magnitude; /* local variable - magnitude of num */ /* Determines sign of num */ if (num < 0) *signp = '-'; else if (num == 0) *signp = ' '; else *signp = '+'; /* Finds magnitude of num (its absolute value) and separates it into whole and fractional parts */ magnitude = fabs(num); *wholep = floor(magnitude); *fracp = magnitude - *wholep; }

  22. Example of a program that calls a function with multiple output arguments /* Demonstrates the use of a function with input and output parameters.*/ #include <stdio.h> #include <math.h> void separate(double num, char *signp, int *wholep, double *fracp); int main(void) { prototype of separate double value; /* input - number to analyze */ char sn; /* output - sign of value */ int whl; /* output - whole number magnitude of value */ double fr; /* output - fractional part of value */ /* Gets data */ printf("Enter a value to analyze> "); scanf("%lf", &value); /* Separates data value into three parts */ separate(value, &sn, &whl, &fr); /* Prints results */ printf("Parts of %.4f\n sign: %c\n", value, sn); printf(" whole number magnitude: %d\n", whl); printf(" fractional part: %.4f\n", fr); return (0); } separate should be defined here…. Enter a value to analyze> 35.817 Parts of 35.8170 sign: + whole number magnitude: 35 fractional part: 0.8170

  23. Side effect of function call separate(value, &sn, &whl,&fr) Function main Function separate Data AreaData Area value value 35.817 35.817 sign sn 7421 Address of sn = &sn ? whl wholep 7422 ? fracp fr 7423 ? magnitude ?

  24. More on Functions • When a pointer is passed to a function it can be used as “output” or “input/output” parameter. • Scope of the name refers to the region of a program where the name is visible • For example scope of the formal and local variables, is from their declaration to the closing brace of a function in which they are declared • The scope of predefine constants is the whole program (they are global) • If the same name is repeated to declare the variable one of them may shadow another one. For example in the following example fun-two can be called by one, main and itself but function one can only ba called by main and itself not fun-two

  25. #define MAX 950 #define LIMIT 200 void one(int anarg, double second); /* prototype 1 */ int fun_two(int one, char anarg); /* prototype 2 */ int main(void) { int localvar; both of two functions one and fun_two can be called here . . . } /* end main */ void one(int anarg, double second) /* header 1 */ { int onelocal; /* local 1 */ function fun-two can be called here . . . } /* end one */ int fun_two(int one, char anarg) /* header 2 */ { int localvar; /* local 2 */ function one can not be called here . . . } /* end fun_two */

  26. Using formal parameters as actual parameters void scan_fraction(int *nump, /* output - numerator */ int *denomp) /* output - denominator */ { char slash; /* local - character between numerator & denominator */ int status; /* status code returned by scanf indicating number of valid values obtained */ int error; /* flag indicating whether or not an error has been detected in current input */ char discard; /* unprocessed character from input line */ do { /* No errors detected yet */ error = 0; /* Get a fraction from the user */ status = scanf("%d%c%d", nump, &slash,denomp ); …………… } while (error); }

  27. Recursive Functions • A function that calls itself is said to be recursive • Also if f1 calls f2 and f2 calls f1, f1 is considered as a recursive function • A recursive algorithm has the following form: if this is a simple case solve it else redefine the problem using recursion • For the simple case of the problem a straightforward, non-recursive solution is known

  28. Recursive Functions • For example to calculate the multiplication of 6 by 3 when only we allowed to use the addition operation: • The simple case is multiplication of 6 by 1 • And the recursive algorithm is: 1. Multiply 6 by 2. 1.1 Multiply 6 by 1 simple case 1.2 Add 6 to the result 2. Add 6 to the result of problem 1

  29. Recursive Functions /* * Performs integer multiplication using + operator. * Assumes n > 0 */ int multiply(int m, int n) { int ans; if (n == 1) ans = m; /* simple case */ else ans = m + multiply(m, n - 1); /* recursive step */ return (ans); }

  30. 18 multiply (6,3) Tracing a recursive function m is 6 n is 3 3 == 1 is false ans is 6 + multiply(6, 2) return ans Each activation frame corresponding to each function call m is 6 n is 2 2 == 1 is false ans is 6 + multiply(6, 1) return ans 12 m is 6 n is 1 1 == 1 is true ans is 6 return ans 6

  31. m n ans Local Variable and Parameter Stack of multiply(6,3) 1 6 3 ? 6 2 ? 2 6 3 ? 6 1 ? m n ans 6 2 ? 3 6 3 ? 7 6 3 ? return from the third call 6 1 6 m n ans 4 6 2 ? 8 6 3 18 6 3 ? 6 2 ? return from the first call 5 6 3 ? 6 2 12 return from the second call 6 6 3 ?

  32. Tracing a Recursive Function int multiply(int m, int n) { int ans; printf("Entering multiply with m = %d, n = %d\n", m, n); if (n == 1) ans = m; /* simple case */ else ans = m + multiply(m, n - 1); /* recursive step */ printf("multiply(%d, %d) returning %d\n", m, n, ans); return (ans); } Entering multiply with m = 8, n = 3 Entering multiply with m = 8, n = 2 Entering multiply with m = 8, n = 1 multiply(8, 1) returning 8 multiply(8, 2) returning 16 multiply(8, 3) returning 24 printf is used to make a self-trace recursive function

  33. Case Study: Bisection Method for Finding Roots • Problem: Develop a function bisect that approximates a root of a function f on an interval that contains an odd number of roots • Analysis Input: double x_l, x_r; /* endpoints of interval */ double epsilon; /* error tolerance */ Output: double root; /* approximate root of f */ Variable: double x_mid; /*interval midpoint */

  34. Design: Algorithm 1. if this is a simple case, solve it 1.1 simple case 1 if interval shorter than epsilon, return the midpoint 1.2 simple case 2 if function value at midpoint is zero, return midpoint else redefine the problem using recursion 1.3 bisect interval and execute a recursive call on the half interval that contains the root 1.3.1 if f(x_l)*f(x_mid)<0 1.3.2 Find the root by bisecting[x_l,x_mid] 1.3.3 Find the root by bisecting[x_mid, x_r]

  35. Implementation: double bisect(double x_l, /* input - endpoints of interval in which */ double x_r, /* to look for a root */ double epsilon) /* input - error tolerance */ { double root, /* approximate root */ x_mid; /* interval midpoint */ /* Compute midpoint of interval */ x_mid = (x_l + x_r) / 2.0; if (x_r - x_l < epsilon) /* simple case 1 */ root = x_mid; else if (f(x_mid) == 0.0) /* simple case 2 */ root = x_mid; else if (f(x_l) * f(x_mid) < 0.0) /* root in [x_l, x_mid] */ root = bisect(x_l, x_mid, epsilon); else /* root in [x_mid, x_r] */ root = bisect(x_mid, x_r, epsilon); return (root); }

  36. Case Study: Performing Arithmetic Operations on Common Fractions • Problem: Write a program that will allow you to add, subtract, multiply, and divide common fractions. The program will prompt you for a fraction, an operator, and another fraction and then display the problem and the result. The process will be repeated until you enter an n to answer the question, Continue? (y/n)

  37. Analysis Input: int n1, d1; /* numerator, denominator of first fraction */ int n2, d2; /* second fraction */ char op; /* arithmetic operator + - * / */ char again; /* whether to continue */ Output: int n_ans; /* numerator of answer */ int d_ans; /* denominator of answer */

  38. Design 1. Initialize again to y 2. As long as user wants to continue 3. Get a fraction problem 3.1 Get first fraction 3.2 Get operator 3.3 Get second fraction 4. Compute the result 4.1 Select a task based on operator 4.2 Put the result fraction in reduced form 5. Display problem and result 6. Check if user wants to continue

  39. Implementation (Step 4 of the Algorithm) /* Gets a fraction problem */ scan_fraction(&n1, &d1); op = get_operator(); scan_fraction(&n2, &d2); /* Computes the result */ switch (op) { case '+': add_fractions(n1, d1, n2, d2, &n_ans, &d_ans); break; case '-': add_fractions(n1, d1, -n2, d2, &n_ans, &d_ans); break; case '*': multiply_fractions(n1, d1, n2, d2, &n_ans, &d_ans); break; case '/': multiply_fractions(n1, d1, d2, n2, &n_ans, &d_ans); } reduce_fraction(&n_ans, &d_ans);

  40. Testing • A stub is a skeleton function that consists of a header, trace messages and assigned values to the output parameters. • Using stubs for incomplete functions enables testing of the flow of control among the other functions before these function are completed. • The process of testing the flow control between a main and subordinate functions is called top-down testing.

  41. Stup for Function multiply_fractions /* ***** STUB ***** * Multiplies fractions represented by pairs of integers. * Product of n1/d1 and n2/d2 is stored in variables pointed * to by n_ansp and d_ansp. Result is not reduced. */ void multiply_fractions(int n1, int d1, /* input - first fraction */ int n2, int d2, /* input - second fraction */ int *n_ansp, /* output - */ int *d_ansp) /* product of two fractions */ { /* Displays trace message */ printf("\nEntering multiply fractions with\n"); printf("n1 = %d, d1 = %d, n2 = %d, d2 = %d\n", n1, d1, n2, d2); /* Defines output arguments */ *n_ansp = 1; *d_ansp = 1; }

  42. Testing • The stub functions can be completed and test individually. A test of an individual function is referred to as unit test. • When a module is completed and tested, it can be substituted for its stub in the program. • Bottom-up testing is the process of testing individual functions of a program. • Testing the entire program after replacing all its stubs with the pre-tested functions is referred to as system integration test.

  43. Common Programming Errors • The correspondence between actual parameters and formal parameters (number, type, order) • Actual output arguments must be of the same pointer types as the corresponding formal parameters. • Recursive functions should be tested to make sure they terminate properly • If return is using for the expression containing the call to the recursive function, every path through a non-void function should lead to a return statement.

More Related