Download presentation
Presentation is loading. Please wait.
Published byJason Wilkinson Modified over 9 years ago
2
Using functions Writing functions Basics Prototypes Parameters Return types Functions and memory Pointer parameters
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
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
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
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
PPreviously I declared a pointer like this i i nt * p ; ▪T▪The spaces are not necessary YYou can do this i i nt *p ; OOr this i i nt* p ; OOr 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
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.