420 likes | 436 Views
Pointers. *, &, array similarities, functions, sizeof. Review of Variables. Since variables are used to hold a value which can change, the compiler uses the computer’s memory as the storage area.
E N D
Pointers *, &, array similarities, functions, sizeof
Review of Variables • Since variables are used to hold a value which can change, the compiler uses the computer’s memory as the storage area. • When the variable is declared, the compiler allocates enough space in the memory for the data type and the variable name is used to refer to the contents of the memory.
Review of Variables • The type in the declaration statement tells the compiler how much memory to allocate to the variable. The char data typerequires 1 byte, all other data types require more than 1 byte. eg • Here the compiler reads int and allocates 2 bytes in the memory for the integer. • The variable name in the declaration is used as a reference to the contents of the memory just allocated. • Since the variable is created in the memory, it must have an address associated with it. If the variable requires more than one byte in the memory then the address used is the address of the first data byte. • Whenever the variable is used, the program goes to the address of the variable and accesses the contents. • The addressing is handled automatically by the compiler. As far as the programmer is concerned the variable’s name is the value of the variable.
Review of Variables • A variable has an address and contents. They are usually drawn with the address on the left and the variable contents in a box on the right, as shown below. lvaluervalue • The variable’s address is called the lvalue because it appears on the left hand side. • The variable contents is called the rvalue because it appears on the right hand side. Note GCC uses lvalue and rvalue in its compiler errors and warnings. • variable address variable value
Address Operator (&) • The address operator is &. • & means the address of. • The address of a variable can be found by using the address operator (&) in front of the variable’s name. eg &counter means the address of counter. This is the address of the memory allocated to the variable counter. • If the variable is not a char, then the address is the address of the first byte allocated. An int requires 4 bytes, the address of an int is the address of the first byte in the memory.
Variables that hold addresses (pointers) • The address of a variable is just data. Data can be stored in the memory. Therefore it is possible to have a special variable that just holds addresses. • A special variable called a pointer is used to hold addresses. It is called a pointer because it holds a value which points to a memory address. • A pointer is a variable that is used to store the address of other variables. • A pointer is always associated with a data type. This is because an address just refers to the memory, it does not give an indication of how many bytes to access. The data type tells the compiler how many bytes to read or write starting at the address held in the pointer.
Declaring pointers • Like any variable pointers must be declared before they are used. • All pointers are declared with a * in front of the variable name. syntax type*pointer_name; where • type is the data type of the value to which the pointer points. • * means the variable is a pointer. • pointer_name is the name of the pointer variable.
Declaring pointers • Examples of declaring pointers int *p ; This declares a variable (pointer) called p which will hold an address. char *c, *ch ; float *v ;
Using Pointers & Address of operator (address of variable) * Contents of address pointed to (read/write memory) • The & operator gets the address of a variable. • The * operator means access the variable whose address is held in the pointer. • The * operator gets the address held in the pointer and accesses the memory location pointed to by the address.
Using Pointers • The * operator on the left hand side of an equate (=) means write to the variable whose address is held in the pointer. For example *p = 23 ; /* write 23 to the memory given by the address in p */ • The * operator on the right hand side of an equate (=) means read from the variable whose address is held in the pointer. For example b = *p ; /* read the contents of memory given by the address in p and assigns it to b */
Using Pointers • Example to illustrate pointers. This sets a to 5 and b to 5. int main(void) { int a, b ; /* declare variables */ int *p1, *p2 ; /* declare pointers */ a = 77 ; /* assign a to be 77 */ b = 222 ; /* assign b to be 222 */ p1 = &a ; /* set p1 to the address of variable a */ p2 = &b ; /* set p2 to the address of variable b */ // set contents of the memory referred to by p1 to 5 ( ie a) *p1=5; // set b to the contents of the memory referred to by p1 ( ie b) b = *p1 ; }
Using PointersExample Explained • Code: int a, b; /* variables */ int *p1,*p2 ; /* pointers */ • Memory: • Comments The variables are declared, which means that they are allocated space in the memory. Assume that the compiler allocates the addresses shown.
Using PointersExample Explained • Code: a = 77 ; /* assign a to 77 */ b = 222 ; /* assign b to 222 */ • Memory • Comment: The values are written to the variables. The contents of memory location 1000 is 77 because the memory allocated for a is at address 1000.
Using PointersExample Explained • Code: p1 = &a ; /* set p1 to the address of variable a */ p2 = &b ; /* set p2 to the address of variable b */ • Memory: • Comment: The pointer p1 gets the address of a. The address of a is 1000, which means that 1000 is stored in p1. The pointer p2 gets the address of b. The address of b is 1002, which means that 1002 is stored in p2.
Using PointersExample Explained • Code: *p1 = 5 ; • Memory: • Comment: The * means access the variable pointed to by the pointer p1. The pointer holds address 1000. The pointer type is an int which means that address 1000 is treated like it is an integer variable. Therefore the value 5 is written to the integer at address 1000. (i.e the two bytes forming the integer at address 1000 and 1001 are written to).
Using PointersExample Explained • Code: b = *p1 ; • Memory: • Comment: The variable b is a normal variable and is expecting the result of *p1. The * means access the variable pointed to by the pointer p1. The pointer holds address 1000. The pointer type is an int which means that address 1000 is treated like it is an integer variable. Therefore the value of the integer at address 1000 is read and placed into b. Since the contents of 1000 is 5 then b is set to 5.
NULL pointer • The NULL pointer is a pointer that contains the value NULL. The value of NULL is 0 and the word NULL is a #define in <stdio.h>. • A NULL pointer is used to indicates that a variable does not point to any valid data or that an error has occurred in a function that returns a pointer. • Do not use the * pointer operator with NULL. This will access address 0. This can cause the program to crash.
Call By Reference • The most common use of pointers is to pass a variable into a function to allow that function to manipulate the data in the variable. • A function is made up of the function name and the parameter list. i.e type function_name(parameter_list). The parameter_list consists of a list of the variables being passed to the function.
Call By Reference • In a normal operation, the function receives values from its calling function, stores these values as its own local variables, performs the action of the function, and then returns a single value. Changing the value of the variable does not affect the calling variable. This is called call by value because only the values (contents) of the variables are being passed to the function. For example y = sin(x) ; The sin() function reads the value of x, performs an algorithm to find out the sine of the value, and returns the sine value back. The value of x is not changed.
Call By Reference • To alter one of the variables in the parameter list when we call the function, the address of the variable must be used. The function receives the address from the calling function, stores this in its own local variable and performs the action of the function. • Since we have the address of the parameter used when calling the function, we can change the contents of that variable directly. • This means that the function has direct access to the variable that referred to when calling the function. • This is called call by reference because we are referring to the memory location of the variables by its address.
Call By Reference void fn(int *) ; int main(void) { int a ; fn(&a) ; return 0 ; } void fn( int *val) { *val = 5 ; } Variable a is given a memory location eg 0x5000 Passing the address of variable a. ie 0x5000 val is set to the address of variable a. ie 0x5000 This changes the contents of the memory pointed to by val to be 5. ie changes contents of a to be 5 since val points to the memory address that is used for a
Call By ReferenceAn Example scanf("%i",&x) ; • scanf() is a function. • The values in the parenthesis are the parameters passed to the function. • Here we want the scanf() function to read in an integer from the keyboard and place the result into the variable x. • A normal function cannot alter the x variable, therefore the x has to be passed as an address. • Since the address of the x variable is passed to the scanf() function then the function has direct access to the memory location used to store the contents of x. • When the function reads in an integer from the keyboard, it writes the value to the memory at the address given, which alters the x variable.
Pointers and Arrays • Pointers refer to the address of a variable. • Arrays consist of consecutive elements of the same type for example int numbers[3] consists of three integers. Assuming ints are two bytes in this example. The array in the memory, showing the consecutive elements and their addresses. Base Address
Pointers and Arrays • Each element in the array appears like a variable of the given data type except that each element in the array is referred to using an index. • For example in the array int numbers[3] ; numbers[0] is an integer variable and can be used wherever and in the same way that an int is used. eg numbers[0]++ ; numbers[0] % 2 ; scanf(“%i”,&numbers[0]) ;
Pointers and Arrays • Pointers can be used to refer to the address of array elements. For example &numbers[i] ; is the address of the ith element of numbers • The base address of an array is the starting address of the array i.e. &array[0]. • The name of the array without any [ ] refers to the base address of the array. In the numbers example, the base address is &numbers[0] which is address 1000. • The address of the ith element is address = base + i * sizeof(data_type) where sizeof(data_type) is the number of bytes required to store the data type of the array. (char = 1, int = 4, float = 4, double = 8)
Pointers and ArraysExample • In an array declared as intnumbers[3] ; • The address of • element 0: 1000 + (0 * 2) = 1000 • element 1: 1000 + (1 * 2) = 1002 • element 2: 1000 + (2 * 2) = 1004 Base Address
Pointers and Arrays • The contents of the pointer can be accessed using the * Example int numbers[3] = {5, 99, -1024} ; /* declare array */ int *p ; /* declare pointer */ p = numbers ; /* point to start of array */ p = p + 2;/* point to element 2 */ /* see pointer arithmetic later in slides */ printf("%i",*p) ; /* print out element */ p is pointing to element 2 in the array. ie p = &numbers[2]. The value printed out will be -1024.
Passing arrays to functions • To pass an array to a function, you pass the base address of the array. • For example char string1[80] = “hello”, string2[80] ; strcpy(string1, string2) ; float prices[10] ; total(prices) ; Passing String string1 into function strcpy. Passing String string2 into functionstrcpy. Passing Array prices into function total.
Function prototypes using arrays • The array being passed is a pointer to the first element of the array. • In the function definitions, the array can be declared in the parameter list in two ways void search(int array[ ], int search_value) ; void search(int *array, int search_value) ; • The two methods are the same. Both pass the array through to the function and the array can be accessed in the same way.
Pointer Arithmetic • The process of applying addition and subtraction to pointers is called pointer arithmetic. • p +k is always &array[k]. when p = pointer containing the base address of the array. k = integer representing the number of elements. • p -k is always &array[-k]. when p = pointer containing the base address of the array. k = integer representing the number of elements.
p+0 p p+1 p+2 Pointer Addition • Adding k is the same as moving k elements forwards in the array • Assuming the elements in the following array are short int then
Pointer Addition • If you add an integer k to the base address of an array then the resultant address is the address of the element at index k in the array. eg int numbers[3] ;// declare the array int *p ;// declare the pointer p = numbers ;// set the pointer to the start of the array p = p + 2 ; // pointer is now at &numbers[2] • The numbers array is declared, for example given earlier the base address is 1000. p is set to point to the base address of numbers. p = 1000 p = p + 2 gives 1000 + (2 x sizeof(short int) ) 1000 + (2 x 2) 1004 Now p is at the address of numbers[2]. ie p = &numbers[2].
q-2 q-1 q q+0 Pointer Subtraction • Subtracting k is the same as moving k elements backwards in the array • Assuming the elements in the following array are short int then
Pointer Subtraction • If you subtract an integer k from an address of an array element (p) then the resultant address is the address of the element located k elements before p . eg int numbers[3] ;// declare the array int *p ;// declare the pointer p = &numbers[2] ;// set the pointer to the 3rd element p = p - 2 ; // pointer is now at &numbers[0] • The numbers array is declared, for example given earlier the base address is 1000. p is set to point to the 3rd element . p = 1004 p = p - 2 gives 1004 - (2 x sizeof(short int) ) 1004 - (2 x 2) 1000 Now p is at the address of numbers[0]. ie p = &numbers[0].
Pointer Increment and Decrement • The increment operator ++ and decrement operator -- can be used on pointers. These just move the pointer up or down by one element. • This is the same as adding 1 to the pointer and subtracting 1 from the pointer. • The postfix form for the operator is *p++ ; • This means read the contents of the address pointed to by p, and then add 1 to p. • The prefix form for the operator is *++p ; • This means add 1 to p, and then read the contents of the address pointed to by p.
PointersCommon Mistakes • The most common mistake in using pointers is to declare a pointer but not set its value to point to a variable already declared. • When you declare a variable, the compiler allocates enough space for the variable. When you declare a pointer, then the compiler allocates enough space to hold an address. Therefore, if you use a pointer without initialising it to the address of a variable that has already been declared (allocated space by the compiler), then you will be trying to access unallocated memory. This can result in the data being destroyed. • Declaring the pointer does not allocate the space for the memory you are trying to access.
SIZEOF operator • The sizeof operator evaluates to the size of the data type used as the operand. syntax: sizeof(expression) where • expression is a valid variable, or data type. • Examples sizeof(char) will return the size in bytes of a char. (1) sizeof(int) will return the size in bytes of an int (4) sizeof(x) will return the size in bytes of variable x. sizeof(char [3]) will return the size in bytes of the array. (3 x 1) sizeof(string)will return the size in bytes of the char array.
SIZEOF operator Note: sizeof() is nota function, it is an operator with a high precedence. The precedence is the same as ++, --, !, ~, & (address), * (dereference).
Example ProgramsExample 1 • Program to swap two floating point numbers #include <stdio.h> #include <stdlib.h> /* prototype */ void swapfloats(float *, float *) ; int main(void) { float first=2, second=1; swapfloats(&first,&second);// Note the 'address-of' operators printf("%g %g\n", first, second); }
Example ProgramsExample 1 (continued) /* function to swap two floats */ void swapfloats(float *a, float *b) { float temp; // This is still float, because we are swapping floats temp = *a; /* Note the '*'s - get the float pointed to by a. */ /* Copy the float b points at into the variable a points at*/ *a = *b; /* Copy the float in temp into the variable b points at. */ *b = temp; }
Example ProgramsExample 2 • Program to print out the characters in a string. #include <stdio.h> #include <stdlib.h> /* prototype */ void print_str(char *) ; int main(void) { char string[20] = "Hello" ; /* Note: string is the address of the start of the array */ print_str(string); }
Example ProgramsExample 2 (Continued) Str originally points to the start of the string. /* function to print out the string */ void print_str(char *str) { /* read through each char until end of string ‘\0’ */ while ( *str != ‘\0’) { /* print out the character */ putchar(*str) ; /* move to next element */ str++ ; } } Value at the location that str points to is checked. The character at the location that str refers to is printed. str now points to the next location. The next character in the string.