Presentation is loading. Please wait.

Presentation is loading. Please wait.

 Using functions  Writing functions  Basics  Prototypes  Parameters  Return types  Functions and memory  Pointer parameters.

Similar presentations


Presentation on theme: " Using functions  Writing functions  Basics  Prototypes  Parameters  Return types  Functions and memory  Pointer parameters."— Presentation transcript:

1

2  Using functions  Writing functions  Basics  Prototypes  Parameters  Return types  Functions and memory  Pointer parameters

3

4  Using library functions  Writing functions  Parameter lists  Return types

5  Library functions are often used in C  For example, the math.h library contains mathematical functions ▪ Such as sqrt and pow  When a function is called in a program the function code is executed  And the return value of the function (if any) replaces the function call (or invocation)

6 // Prints the area of a circle #include "stdio.h" #include "math.h" // Define Pi #define PI 3.14159265; // Main program – next slide! int main(){ //... }

7 int main(){ float radius; float area; // Get keyboard input printf("Please enter the radius: "); scanf("%f", &radius); // Calculate area area = PI * pow(radius, 2); printf("The area of the circle is %.2f", area); return 0; }

8 area = PI * pow(radius, 2); function name arguments to the function the function executes, and it is replaced by the result that it returns

9  Function calls in statements have precedence over most other operations  Such as arithmetic or comparisons  A function is executed and its result returned before other operations are performed

10  Many functions need input  Data passed to a function are referred to as arguments  The number and type of arguments must match what is expected by the function  Failing to give appropriate arguments results in a compilation error

11 area = PI * pow("fred", 2); error: incompatible type for argument 1 of ‘pow’

12  When a function is called, program execution switches to the function  Each line of code in the function is executed in turn until ▪ The last line is reached, or ▪ A return statement is processed  Execution then returns to the line of code where the function was called from  The function call is replaced by the return value

13

14  As well as using functions, we can write our own functions  This is very useful as it increases the modularity of programs  Functions can be written and tested in isolation  It is good programming style to write many small functions

15 int mySquare(int x) { int sq = x * x; return sq; } function body return type parameter list function name function header return statement

16  Functions have two parts  A header (or declaration) ▪ Return type of the function ▪ Function name ▪ Function parameter list  A body (or definition) ▪ The executable statements or implementation of the function ▪ The value in the return statement (if any) must be the same type as the function's return type

17  Function's names are identifiers, so must follow identifier rules  Only contain a to z, A to Z, _, 0-9  Must start with a to z, A to Z  By convention function names should  Start with a lower case letter ▪ They can be distinguished from variables by their parameter lists (brackets)  Have meaningful names

18  Not all functions need to return a value  For example a function to print instructions  Functions that return nothing should be given a return type of void  A function that returns nothing (void) cannot be used in an assignment statement  Void functions are often used for output

19  Every function must have a parameter list  The parameter list consists of ()s which follow the function name  Parameter lists contain function input  A parameter list can be empty, but the brackets are still required when the function is defined  Whenever a function is called (used) it must be followed by brackets  Again, even if they are empty

20 #include "stdio.h" void hi(){ printf("hello world"); } int main (){ hi(); return 0; }

21  A function that is written in a.c file can be used in that file  Just like a library function  The function must be declared before it is used, either by  Defining the function, or  Writing a forward declaration, and defining it later ▪ Also referred to as a function prototype

22 #include "stdio.h" #include "math.h" const float PI = 3.14159; int main() { float r = 3; printf("radius %.2f, volume = %.2f", r, sphere_volume(r)); return 0; } double sphere_volume(double radius) { return PI * pow(radius, 3) * 4.0/3; } error: conflicting types for ‘sphere_volume’ that's kind of an odd error message to get when the function hasn't been defined, here is an earlier warning the compiler processes the file one line at a time starting from the top, so when it reaches sphere_volume it doesn't recognize the name warning: format ‘%f’ expects argument of type ‘double’, but argument 3 has type ‘int’

23 #include "stdio.h" #include "math.h" const float PI = 3.14159; // Function Prototypes double sphere_volume(double radius); int main() { float r = 3; printf("radius %.2f, volume = %.2f", r, sphere_volume(r)); return 0; } double sphere_volume(double radius) { return PI * pow(radius, 3) * 4.0/3; } fix by inserting a function prototype before main (or by moving the function definition) it is usually preferable to use function prototypes rather than defining all of the functions above main

24  The compiler compiles a program one line at a time  Starting at the top of the file  If the compiler encounters an undefined identifier it will be unable to continue  Functions can be declared before being used and defined later on in the file  A function prototype consists of the function header (followed by a semi-colon)

25  Many functions require data to perform operations on (i.e. input)  Such data can be given to functions in a number of ways  The function can obtain the data itself ▪ By getting input from the user  Data can be provided via global variables ▪ Which are visible throughout the file  Values can be passed to parameters

26  A global variable is a variable that is declared outside any function  Including the main function  Variables declared inside a function are referred to as local variables  Global variables can be used by any function  In the same file (and possibly other files)  Avoid global variables ▪ With a few exceptions, such as constants

27  They make programs harder to understand  Functions that rely on global variables cannot be considered in isolation  They make programs harder to modify  It is relatively straightforward to change a function that is self-contained  They make programs less portable  If functions depend on global variables they cannot easily be used by other files

28  Parameter lists are the preferred method of data input to a function  Parameters are special variables that can be passed values from calling code  A function's parameters are given the value of variables passed to a function ▪ Variables passed to functions are called arguments

29 void print_int_division(int dividend, int divisor) { int quotient = dividend / divisor; int remainder = dividend % divisor; printf("%d/%d = %d remainder %d\n", dividend, divisor, quotient, remainder); } //... main function scanf("%d", &x); //... scanf("%d", &y); //... print_int_division(x, y); //prints result of x/y //... main function scanf("%d", &x); //... scanf("%d", &y); //... print_int_division(x, y); //prints result of x/y formal parameters arguments

30  Parameters and arguments are different variables  They refer to different main memory locations  Parameters are given the values of arguments  They may even have the same name but still refer to different variables  It is also possible to pass a function the address of a variable  As we've seen with scanf – more on this later

31  Many functions return values  The function performs a calculation  And sends the result back to calling code ▪ e.g. sqrt, pow  Values are returned by a return statement  The type of the value in a return statement must match the return type of the function

32 int mySquare(int x) { int sq = x * x; return sq; } As soon as any return statement is reached the function execution ends and the value is returned to the calling code

33  Whenever we want to perform an action or a calculation we should write a function  Functions organize other programming constructs  Functions often need input (arguments) and often return values  The return type of a function specifies the type of information that it returns  Note that a function with a return type of void returns nothing

34  A function that specifies a return type must contain a return statement  Or an error results  The compiler may not check that all paths within a function contain a return value  Such as nested if statements, or  If, else if,..., else statements  Some compilers may give warnings about this, but others may not

35  Is it possible to return from a function that does not return a value (i.e. is void)?  Yes!  Just use return with no value  This allows us to return from any function before reaching the end of the function  For example, in a branch of an if statement

36  Functions should perform one task  In particular, functions that calculate values should not be responsible for output ▪ Such values should be returned not printed  Functions should be self contained  Input should be passed via parameters  Results should be returned using a return statement

37  A function prototype should consist of the function header  Return type, name, parameter types ▪ e.g. int foo(int, int); ▪ The parameter names do not have to be specified, but may be if desired  Older C compilers did not require parameters in function prototypes  This applies to the Visual Studio C compiler

38

39  Recall that two variables cannot have the same name  More accurately, two variables can have the same name as long as they have different scope  The scope of a variable is the block in which it is declared  So variables with different scope may have different names

40 void f(){ int x = 99; printf("%d\n", x); } int main() { int x = 1; if (x == 1){ int x = 2; printf("%d\n", x); } printf("%d\n", x); f(); printf("\n\n"); return 0; } x's scope

41  The scope of any variable declared inside a function is local to that function  This includes a function's parameters ▪ So a parameter of a function may not have the same name as a variable declared inside that function ▪ Unless the variable has a more limited scope  Functions cannot be defined inside functions  The scope of two different functions therefore does not overlap

42  The example shown previously had two variables called x in the main function  One variable declared in if (if-x) and one declared in main (main-x)  The scope of main-x encompassed the entire main function and overlapped with if-x  In such cases only the variable with the least scope is visible

43

44  Let's expand our memory model to cover functions  Which includes the main function  It's not going to be very different from our original model  Main memory is a long sequence of binary digits  Variables are allocated in sequence  A system table allows us to find variables ▪ But we are not going to go into much detail about it

45 data22313 address20482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073... data223TheDude\013 address20482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073... Let’s look at an example of memory allocation in a main function int x = 223; char name[10]; int y = 13; This function, defined in string.h copies the second argument into the first argument variabletypeaddress xint2048 namechar*2052 yint2062 This area of memory is referred to as the call stack, and it is used for memory associated with function calls symbol table (also in main memory) strcpy(name, “The Dude”); next free byte

46 variabletypeaddress xint2048 namechar*2052 yint2062 variabletypeaddress xint2048 namechar*2052 yint2062 aint2066 bint2070 data223TheDude\013 address20482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073... data223TheDude\01322313 address20482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073... Now add some function calls to a function called sum2 int x = 223; char name[10]; int y = 13; During the call to sum2 memory is allocated (in sequence) to the parameters of sum2 (and its other variables if it had any) strcpy(name, “The Dude”); x = sum2(x, y); int sum2(int a, int b) { return a + b; } int sum2(int a, int b) { return a + b; } sum2’s memory next free byte

47 data223TheDude\01322313 address20482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073... data236TheDude\01322313 address20482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073... Now add some function calls to a function called sum2 int x = 223; char name[10]; int y = 13; After the call to sum2, x has changed and the next free byte is 2066, since the memory allocated to sum2 is no longer needed strcpy(name, “The Dude”); x = sum2(x, y); variabletypeaddress xint2048 namechar*2052 yint2062 int sum2(int a, int b) { return a + b; } int sum2(int a, int b) { return a + b; } next free byte

48 variabletypeaddress xint2048 namechar*2052 yint2062 variabletypeaddress xint2048 namechar*2052 yint2062 aint2066 bint2070 data236TheDude\01322313 address20482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073... data236TheDude\013236 address20482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073... Now add some function calls to a function called sum2 int x = 223; char name[10]; int y = 13; Note that the two calls to sum2 reuse the same eight bytes of the stack since they happen one after the other strcpy(name, “The Dude”); x = sum2(x, y); int sum2(int a, int b) { return a + b; } int sum2(int a, int b) { return a + b; } y = sum2(x, x) + sum2(y, y);

49 data236TheDude\013236 address20482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073... Now add some function calls to a function called sum2 int x = 223; char name[10]; int y = 13; Note that the two calls to sum2 reuse the same eight bytes of the stack since they happen one after the other strcpy(name, “The Dude”); x = sum2(x, y); variabletypeaddress xint2048 namechar*2052 yint2062 int sum2(int a, int b) { return a + b; } int sum2(int a, int b) { return a + b; } y = sum2(x, x) + sum2(y, y);

50 variabletypeaddress xint2048 namechar*2052 yint2062 variabletypeaddress xint2048 namechar*2052 yint2062 aint2066 bint2070 data236TheDude\013236 address20482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073... data236TheDude\013 address20482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073... Now add some function calls to a function called sum2 int x = 223; char name[10]; int y = 13; Note that the two calls to sum2 reuse the same eight bytes of the stack since they happen one after the other strcpy(name, “The Dude”); x = sum2(x, y); int sum2(int a, int b) { return a + b; } int sum2(int a, int b) { return a + b; } y = sum2(x, x) + sum2(y, y);

51 data236TheDude\013 address20482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073... data236TheDude\049813 address20482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073... Now add some function calls to a function called sum2 int x = 223; char name[10]; int y = 13; Note that the two calls to sum2 reuse the same eight bytes of the stack since they happen one after the other strcpy(name, “The Dude”); x = sum2(x, y); variabletypeaddress xint2048 namechar*2052 yint2062 int sum2(int a, int b) { return a + b; } int sum2(int a, int b) { return a + b; } y = sum2(x, x) + sum2(y, y);

52  The area of main memory used for function calls is called the call stack  A stack is a simple data structure where items are inserted and removed at the same end  Usually referred to as the top of the stack  A stack is a LIFO (Last In First Out) structure  The call stack behaves like a stack  Since the last function to be called  Is the first function to be removed (de-allocated)

53  The process for allocating main memory on the stack is simple  Always allocate memory in sequence  A few things have to be recorded  The address of the next free byte  The starting address for each function’s memory  The line number of each function call in the calling function

54  Their is one disadvantage of using stack memory  The size of a variable cannot change  The value of variables can change but more space cannot be allocated to an existing variable  Since it would overwrite the next variable on the stack  It might be useful to change the size of array variables...

55 Introduction to Pointers

56  We have mostly used pass-by-value to give information to functions  The data passed to a function is copied into the function’s parameters  This requires time to make a copy of the passed value ▪ Trivial if we are passing an integer ▪ Less trivial if we are passing a 100MB image

57  Let's say we want to write a function to swap the values in two variables  Here is a first attempt void swap(int x, int y) { int temp = x; x = y; y = temp; } void swap(int x, int y) { int temp = x; x = y; y = temp; } Does this work?

58 void swap(int x, int y) { int temp = x; x = y; y = temp; } void swap(int x, int y) { int temp = x; x = y; y = temp; } // Calling code (in main) int a = 23; int b = 37; swap(a, b); // Calling code (in main) int a = 23; int b = 37; swap(a, b); 23 a 37 b x and y are parameters of the swap function so have their own space in main memory 23 x 37 y

59 23372337 void swap(int x, int y) { int temp = x; x = y; y = temp; } void swap(int x, int y) { int temp = x; x = y; y = temp; } // Calling code (in main) int a = 23; int b = 37; swap(a, b); // Calling code (in main) int a = 23; int b = 37; swap(a, b); 23 tempabxy 2337

60 swap has completed its execution so its memory is released 37 x 23 y temp note that neither a nor b's values have changed, so the swap function achieved nothing! void swap(int x, int y) { int temp = x; x = y; y = temp; } void swap(int x, int y) { int temp = x; x = y; y = temp; } // Calling code (in main) int a = 23; int b = 37; swap(a, b); // Calling code (in main) int a = 23; int b = 37; swap(a, b); ab 2337

61  Remember that scanf accepts the address of a variable as an argument  And that the value of the variable is changed once scanf has finished its execution  This is often referred to as pass by reference  We can specify an address using &  A function definition also needs to specify that it expects an address ▪ Note that the address of a float is not the same as a float

62 void swap(int* x, int* y) { int temp = *x; *x = *y; *y = temp; } void swap(int* x, int* y) { int temp = *x; *x = *y; *y = temp; } // Calling code int a = 23; int b = 37; swap(&a, &b); // Calling code int a = 23; int b = 37; swap(&a, &b); 23 a 37 b the x and y parameters contain the addresses of a and b, not their values x y

63 23 37 23 x y temp a b void swap(int* x, int* y) { int temp = *x; *x = *y; *y = temp; } void swap(int* x, int* y) { int temp = *x; *x = *y; *y = temp; } // Calling code int a = 23; int b = 37; swap(&a, &b); // Calling code int a = 23; int b = 37; swap(&a, &b);

64 37 23 a b x y temp swap has completed its execution so its memory is released Because swap's parameters are passed addresses a and b have changed void swap(int* x, int* y) { int temp = *x; *x = *y; *y = temp; } void swap(int* x, int* y) { int temp = *x; *x = *y; *y = temp; } // Calling code int a = 23; int b = 37; swap(&a, &b); // Calling code int a = 23; int b = 37; swap(&a, &b);

65  The * is used to mean a number of different things, dependent on the context  Multiplication  Declaration of a pointer variable, when used after a type name ▪ int * p; declares a pointer called p that will store the address of an int  Dereferencing of a pointer to access the variable that it points to ▪ *p = 7; assigns 7 to the int that p points to

66  A pointer is a special type of variable  That stores an address rather than a value  They are called pointers as they can be considered to point to a variable  It is necessary to record the type of data that a pointer variable points to  So that the appropriate operations can be performed on the value it points to

67  Pointers store addresses  Addresses are always the same size on the same system  So why do we have to say what type of data is going to be pointed to?  To reserve enough space for the data and  To ensure that the appropriate operations are used with the data

68  Pointer variable are identified by an * that follows the type in the declaration  int * p;  This declares a variable called p that will point to (or refer to) an integer  Note that the type of a pointer is not the same as the type it points to  p is a pointer to an int, and not an int

69 PPreviously I declared a pointer like this  i i nt * p ; ▪T▪The spaces are not necessary YYou can do this  i i nt *p ; OOr this  i i nt* p ; OOr even this  i i nt*p ; But this is kind of ugly!

70  The operation shown below is unsafe  int x = 12;  int *p = x;  Remember that the type of p is an address (to an int), and not an int  Addresses are actually whole numbers but assigning arbitrary numbers to them is a bad idea  Since a programmer is unlikely to know what is stored at a particular memory address This is not a good thing to do and will result in a compiler warning or error

71  Pointers can be assigned the address of an existing variable  Using the address operator, &  In this way it is possible to make a pointer refer to a variable

72 02 12 2 20 -1 23 02 12 2 20 -1 2 12 23 02 12 2 20 -102 12 2 20 -1 23 int x = 23; int* p = &x; p contains the address of x & is the address of operator

73  Pointers can be used to access variables  But only after they have been assigned the address of a variable  To change the value of a variable a pointer points to the pointer has to be dereferenced  Using the * operator which can be thought of meaning the variable pointed to

74 int x = 5; int *p = &x; /*assign p the address of x*/ /*Use p to assign 23 to x*/ *p = 9; /*dereferences p*/ printf("value in x = %x\n", x); printf("address of x = %x\n", &x); printf("value in p = %x\n", p); printf("address of p = %x\n", &p); printf("value in *p = %x\n\n", *p);

75 int x = 12; int y = 77; int *p1 = &x; //assign p1 the address of x int *p2 = &y; //assign p2 the address of y p1 p2 12 77 x x y y

76 int x = 12; int y = 77; int *p1 = &x; //assign p1 the address of x int *p2 = &y; //assign p2 the address of y p1 = p2; //assigns the address in p2 to p1 p1 p2 12 77 x x y y

77 12 77 int x = 12; int y = 77; int *p1 = &x; //assign p1 the address of x int *p2 = &y; //assign p2 the address of y *p1 = *p2; p1 p2 77 x x y y

78  In practice we don't often use pointers like the preceding examples  Pointers can be used to allow functions to change the value of their arguments  They are also key to managing memory for objects that change size during run-time  Such objects are allocated space in another area of main memory – in dynamic memory


Download ppt " Using functions  Writing functions  Basics  Prototypes  Parameters  Return types  Functions and memory  Pointer parameters."

Similar presentations


Ads by Google