CCSA 221 Programming in C CHAPTER 8 WORKING WITH FUNCTIONS ALHANOUF ALAMR 1
Outline Defining a Function Arguments and Local Variables ◦Automatic Local Variables Returning Function Results Declaring a Function Prototype Functions and Arrays ◦Arrays as parameters ◦Sorting Arrays ◦Multidimensional Arrays Global Variables Automatic and Static Variables Recursive Functions 2
What is a function A function in C: is a self-contained unit of program code designed to accomplish a particular task. The concept has some equivalent in all high-level programming languages: functions, subroutines, and procedures The use of a function: a "black box" ◦defined in terms of the information that goes in (its input) and the value or action it produces (its output). ◦what goes on inside the black box is not your concern, unless you are the one who has to write the function. ◦Think on how you used functions printf, scanf, getchar ! What kind of “output” comes out from a function black box ? ◦Some functions find a value for a program to use. Example: getchar() returns to the program the next character from the standard input buffer. ◦Some functions cause an action to take place. Example: printf() causes data to be printed on the screen ◦In general, a function can both produce actions and provide values. 3
Defining a function 4 #include void printMessage (void) { printf ("Programming is fun.\n"); } int main (void) { printMessage (); return 0; } Function Definition -occurs ONE time for all -outside other functions Function calls (invocations) -occurs ANY (0-N) times -statement inside (other) functions body
Transfer of control flow 5 main printMesage printf When a function call is executed, program execution is transferred directly to the indicated function. After the called routine is finished (as signaled by the closing brace) the program returns to the calling routine, where program execution continues at the point where the function call was executed. { { { } }
Function definitions 6 return-type function-name(argument declarations) { declarations and statements } void printMessage ( void ) { printf ("Programming is fun.\n"); } General form of function definition: return-typearguments
Function prototype The first line of the function definition Contains everything that others (other functions) need to know about the function in order to use it (call it) void printMessage (void) void calculateTriangularNumber (int n) 7 return-type function-name(argument declarations) { declarations and statements } Function prototype
Function arguments arguments (parameters): a kind of input for the function blackbox In the function definition: formal arguments (formal parameters) ◦Formal parameter: a name that is used inside the function body to refer to its argument In the function call: actual arguments (actual parameters) ◦The actual arguments are values are assigned to the corresponding formal parameters. ◦The actual argument can be a constant, a variable, or an even more elaborate expression. ◦The actual argument is evaluated, and its value is copied to the corresponding formal parameter for the function. ◦Because the called function works with data copied from the calling function, the original data in the calling function is protected from whatever manipulations the called function applies to the copies. 8
Example: arguments 9 // Function to calculate the nth triangular number #include void calculateTriangularNumber ( int n ) { int i, triangularNumber = 0; for ( i = 1; i <= n; ++i ) triangularNumber += i; printf ("Triangular number %i is %i\n", n, triangularNumber); } int main (void) { calculateTriangularNumber (10); calculateTriangularNumber (20); calculateTriangularNumber (50); return 0; } formal argument actual argument local variables
Automatic local variables 10 main calculateTriangularNumber { { } n i triangularNb
Example: scope of local variables 11 #include void f1 (float x) { int n=6; printf(“%f \n”, x+n); } int f2(void) { float n=10; printf(“%f \n”,n); } int main (void) { int n=5; f1(3); f2(); return 0; }
Example: arguments 12 #include void gcd (int u, int v) { int temp; printf ("The gcd of %i and %i is ", u, v); while ( v != 0 ) { temp = u % v; u = v; v = temp; } printf ("%i\n", u); } int main (void) { gcd (150, 35); gcd (1026, 405); gcd (83, 240); return 0; }
Example: arguments are passed by copying values ! 13 #include void gcd (int u, int v) { int temp; printf ("The gcd of %i and %i is ", u, v); while ( v != 0 ) { temp = u % v; u = v; v = temp; } printf ("%i\n", u); } int main (void) { int x=10,y=15; gcd (x, y); printf(“x=%i y=%i \n”,x,y); return 0; } The actual parameters x and y are not changed ! The formal parameters u and v are assigned new values in the function
Example: arguments are passed by copying values ! 14 #include void multiplyBy2 (float x) { printf(“parameter at start: %.2f, at %p \n”,x, &x); x*=2; printf(“parameter at end: %.2f, at %p \n”,x, &x); } int main (void) { float y = 7; printf (“y before call: %.2f, at %p \n", y, &y); multiplyBy2 (y); printf (“y after call: %.2f, at %p \n", y, &y); return 0; }
Arguments by copying 15 main multiplyBy2 { { } 7 y x 147
Returning function results A function in C can optionally return a single value return expression; The value of expression is returned to the calling function. If the type of expression does not agree with the return type declared in the function declaration, its value is automatically converted to the declared type before it is returned. A simpler format for declaring the return statement is as follows: return; Execution of the simple return statement causes program execution to be immediately returned to the calling function.This format can only be used to return from a function that does not return a value. If execution proceeds to the end of a function and a return statement is not encountered, it returns as if a return statement of this form had been executed. Therefore, in such a case, no value is returned. If the declaration of the type returned by a function is omitted, the C compiler assumes that the function returns an int ! 16
Return example 17 void printMessage (void) { printf ("Programming is fun.\n"); return; }
Example: function result 18 /* Function to find the greatest common divisor of two nonnegative integer values and to return the result */ #include int gcd (int u, int v) { int temp; while ( v != 0 ) { temp = u % v; u = v; v = temp; } return u; } int main (void) { int result; result = gcd (150, 35); printf ("The gcd of 150 and 35 is %i\n", result); result = gcd (1026, 405); printf ("The gcd of 1026 and 405 is %i\n", result); printf ("The gcd of 83 and 240 is %i\n", gcd (83, 240)); return 0; }
As with ordinary variables and values, it is also possible to pass the value of an array element and even an entire array as an argument to a function. To pass a single array element to a function, the array element is specified as an argument to the function. So, to take the square root of averages[i] and assign the result to a variable called sq_root_result, we use a statement: sq_root_result = squareRoot (averages[i]); To pass an array to a function, it is only necessary to list the name of the array, without any subscripts, inside the call to the function. As an example, if you assume that gradeScores has been declared as an array containing 100 elements, the expression: minimum (gradeScores). in effect passes the entire 100 elements contained in the array gradeScores to the function called minimum. Functions and Arrays 19
Naturally, on the other side of the coin, the minimum function must be expecting an entire array to be passed as an argument and must make the appropriate formal parameter declaration. So the minimum function might look something like this: int minimum (int values[100]) {... return minValue; } The declaration defines the function minimum as returning a value of type int and as taking as its argument an array containing 100 integer elements. 20 Functions and Arrays
21 // Function to find the minimum value in an array #include int minimum (int values[10]) { int minValue, i; minValue = values[0]; for ( i = 1; i < 10; ++i ) if ( values[i] < minValue ) minValue = values[i]; return minValue; } int main (void) { int scores[10], i, minScore; int minimum (int values[10]); printf ("Enter 10 scores\n"); for ( i = 0; i < 10; ++i ) scanf ("%i", &scores[i]); minScore = minimum (scores); printf ("\n Minimum score is %i\n", minScore); return 0; } Functions and Arrays Output: Enter 10 scores Minimum score is 65
22 Note that there is a prototype declaration for the minimum function inside main. int minimum (int values[10]); This tells the compiler that minimum returns an int and takes an array of 10 integers. Remember, it’s not necessary to make this declaration here because the minimum function is defined before it’s called from inside main. Functions and Arrays
23 //Function to change array elements #include void multiplyBy2 (float array[], int n) { int i; for ( i = 0; i < n; ++i ) array[i] *= 2; } int main (void) { float floatVals[4] = { 1.2f, -3.7f, 6.2f, 8.55f }; int i; multiplyBy2 (floatVals, 4); for ( i = 0; i < 4; ++i ) printf ("%.2f ", floatVals[i]); printf ("\n"); return 0; } Output: Note the statement: array[i] *= 2; it multiplies the expression on the left side of the operator by the expression on the right side of the operator and stores the result back into the variable on the left side of the operator. It is equivalent to the following statement: array[i] = array[i] * 2; the function multiplyBy2 actually changes values inside the floatVals array. Assignment Operators
24 // Program to sort an array of integers into ascending order #include void sort (int a[], int n) { int i, j, temp; for ( i = 0; i < n - 1; ++i ) for ( j = i + 1; j < n; ++j ) if ( a[i] > a[j] ) { temp = a[i]; a[i] = a[j]; a[j] = temp; } } int main (void) { int i; int array[16]={34, -5, 6, 0, 12, 100, 56, 22,44, -3, -9, 12, 17, 22, 6, 11}; printf ("The array before the sort:\n"); for ( i = 0; i < 16; ++i ) printf ("%i ", array[i]); sort (array, 16); printf ("\n\n The array after the sort:\n"); for ( i = 0; i < 16; ++i ) printf ("%i ", array[i]); printf ("\n"); return 0; } Sorting Arrays Output: The array before the sort: The array after the sort:
25 Multidimensional Arrays A multidimensional array element can be passed to a function just as any ordinary variable or single-dimensional array element can. The statement: squareRoot (matrix[i][j]); calls the squareRoot function, passing the value contained in matrix[i][j] as the argument. An entire multidimensional array can be passed to a function in the same way that a single-dimensional array can:You simply list the name of the array. The C statement: scalarMultiply (measured_values, constant); can be used to invoke a function that multiplies each element in the matrix measured_values by the value of constant. Note that measured_values is declared to be a two-dimensional array of integers.
26 // Using Multidimensional Arrays and Functions #include int main (void){ int sampleMatrix[3][5] = { { 7, 16, 55, 13, 12 }, { 12, 10, 52, 0, 7 }, { -2, 1, 2, 4, 9 } }; printf ("Original matrix:\n"); displayMatrix (sampleMatrix); scalarMultiply (sampleMatrix, 2); printf ("\nMultiplied by 2:\n"); displayMatrix (sampleMatrix); scalarMultiply (sampleMatrix, -1); printf ("\nThen multiplied by -1:\n"); displayMatrix (sampleMatrix); return 0; } // Function to multiply a 3 x 5 array by a scalar void scalarMultiply (int matrix[3][5], int scalar) { int row, column; for ( row = 0; row < 3; ++row ) for ( column = 0; column < 5; ++column ) matrix[row][column] *= scalar; } void displayMatrix (int matrix[3][5]) { int row, column; for ( row = 0; row < 3; ++row) { for ( column = 0; column < 5; ++column ) printf ("%5i", matrix[row][column]); printf ("\n"); } } Output: Original matrix: Multiplied by 2: Then multiplied by -1:
27 // Using Multidimensional Variable-Length Arrays and Functions #include int main (void){ int sampleMatrix[3][5] = { { 7, 16, 55, 13, 12 }, { 12, 10, 52, 0, 7 }, { -2, 1, 2, 4, 9 } }; printf ("Original matrix:\n"); displayMatrix (3, 5, sampleMatrix); scalarMultiply (3, 5, sampleMatrix, 2); printf ("\nMultiplied by 2:\n"); displayMatrix (3, 5, sampleMatrix); scalarMultiply (3, 5, sampleMatrix, -1); printf ("\nThen multiplied by -1:\n"); displayMatrix (3, 5, sampleMatrix); return 0; } // Function to multiply a matrix by a scalar void scalarMultiply (int nRows, int nCols, int matrix[nRows][nCols], int scalar) { int row, column; for ( row = 0; row < nRows; ++row ) for ( column = 0; column < nCols; ++column ) matrix[row][column] *= scalar; } void displayMatrix (int nRows, int nCols, int matrix[nRows][nCols]) { int row, column; for ( row = 0; row < nRows; ++row) { for ( column = 0; column < nCols; ++column ) printf ("%5i", matrix[row][column]); printf ("\n"); } } Output: Original matrix: Multiplied by 2: Then multiplied by -1:
28 Global Variables The distinguishing quality of a global variable declaration versus a local variable declaration is that the global variable declaration is made outside of any function. This indicates its global nature—it does not belong to any particular function. Any function in the program can then access the value of that variable and can change its value if desired. // Global and Local variables #include int A; int B; int Add() { return A + B; } int main() { int answer; A = 5; B = 7; answer = Add(); printf("%d\n",answer); return 0; } Global variables Local variable Changing global variables’ values inside the function Output: 12
29 Automatic and Static Variables When you normally declare a local variable inside a function, you are declaring automatic local variables. e.g. variables guess and epsilon in squareRoot function float squareRoot (float x) { const float epsilon =.00001; float guess = 1.0;... } Automatic local variables can be given initial values, as is done with the values of epsilon and guess. Automatic variable disappears after the function completes execution i.e. the value of that variable disappears along with it and does not exist when the function is called again. If you place the word static in front of a variable declaration, this means that it does not come and go as the function is called and returns. This implies that the value a static variable has upon leaving a function is the same value that variable will have the next time the function is called.
30 A static, local variable is initialized only once at the start of overall program execution—and not each time that the function is called. Furthermore, the initial value specified for a static variable must be a simple constant or constant expression. Static variables also have default initial values of zero, unlike automatic variables, which have no default initial value. Automatic and Static Variables // Program to illustrate static and automatic variables #include void auto_static (void) { int autoVar = 1; static int staticVar = 1; printf ("automatic = %i, static = %i\n", autoVar, staticVar); ++autoVar; ++staticVar; } int main (void) { int i; for ( i = 0; i < 5; ++i ) auto_static (); return 0; } Output: automatic = 1, static = 1 automatic = 1, static = 2 automatic = 1, static = 3 automatic = 1, static = 4 automatic = 1, static = 5 Automatic variable Static variable
31 Recursive Functions Recursive functions are commonly used in applications in which the solution to a problem can be expressed in terms of successively applying the same solution to subsets of the problem. Recall that the factorial of a positive integer n, written n!, is simply the product of the successive integers 1 through n. The factorial of 0 is a special case and is defined equal to 1. So 5! is calculated as follows: 5! = 5 x 4 x 3 x 2 x 1 = 120 and 6! = 6 x 5 x 4 x 3 x 2 x 1 = 720 Comparing the calculation of 6! to the calculation of 5!, observe that the former is equal to 6 times the latter; that is, 6! = 6 x 5!. In the general case, the factorial of any positive integer n greater than zero is equal to n multiplied by the factorial of n - 1: n! = n x (n - 1)!
32 #include int main (void) { unsigned int j; for ( j = 0; j < 11; ++j ) printf ("%u = %lu\n", j, factorial (j)); return 0; } // Recursive function to calculate the factorial of a positive integer unsigned long int factorial (unsigned int n) { unsigned long int result; if ( n == 0 ) result = 1; else result = n * factorial (n - 1); return result; } Output: 0! = 1 1! = 1 2! = 2 3! = 6 4! = 24 5! = 120 6! = 720 7! = ! = ! = ! = Recursive Functions
33 The fact that the factorial function includes a call to itself makes this function recursive. When the function is called to calculate the factorial of 3, the value of the formal parameter n is set to 3. Because this value is not zero, the following program statement result = n * factorial (n - 1); is executed, which, given the value of n, is evaluated as result = 3 * factorial (2); This expression specifies that the factorial function is to be called, this time to calculate the factorial of 2.Therefore, the multiplication of 3 by this value is left pending while factorial (2) is calculated. With the value of n equal to 2, the factorial function executes the statement result = n * factorial (n - 1); which is evaluated as result = 2 * factorial (1); Once again, the multiplication of 2 by the factorial of 1 is left pending while the factorial function is called to calculate the factorial of 1. With the value of n equal to 1, the factorial function once again executes the statement result = n * factorial (n - 1); which is evaluated as result = 1 * factorial (0);
34 When the factorial function is called to calculate the factorial of 0, the function sets the value of result to 1 and returns, thus initiating the evaluation of all of the pending expressions. So the value of factorial (0), or 1, is returned to the calling function (which happens to be the factorial function), multiplied by 1, and assigned to result and so on. In summary, the sequence of operations that is performed in the evaluation of factorial (3) can be conceptualized as follows: factorial (3) = 3 * factorial (2) = 3 * 2 * factorial (1) = 3 * 2 * 1 * factorial (0) = 3 * 2 * 1 * 1 = 6