Pointers PassByReference Dynamic Memory Allocation CommandLine Arguments Pointers
Pointers Pass-By-Reference Dynamic Memory Allocation Command-Line Arguments
Pointers
Overview • Working directly with memory locations is beneficial. In C, pointers allow you to: − change values passed as arguments to functions (simulate call-by-reference) − work directly with memory that has been dynamically allocated − efficiently work with complex data types such as large structures, linked lists, and arrays.
Introduction to pointers • Definition: A pointer is a variable whose content is the address of a value in memory. • On our current Intel x 86 machines, the amount of space required to hold a pointer variable is 8 bytes and is not related to the size of the entity to which it points.
Introduction to Pointers To declare a pointer in a program, just use the type it points to followed by *. <type> *variable_name; Examples: int short unsigned double *a; *b; char *c; *d = NULL;
Introduction to Pointers We designate a pointer with an arrow ( char a; a char *p; int n; 10 int *q; float x; 7. 5 float *r; double y; 15. 2 double *t; )
Introduction to Pointers • You can declare a pointer and have it point to (make its value be) that location in memory for the variable called x as follows: int x = 7; // variable x of type integer int *ptr; // a pointer to an integer variable ptr = &x; // pointer points to memory location x • The asterisk (*) in the declaration denotes that ptr is to be a pointer and the int indicates the type of data to which ptr will point. • The address operator (&) in the third line refers to the address of x.
Introduction to Pointers What is physically going in RAM? int x = 7; int *ptr = &x; address 20000 address 7 x 90000 20000 ptr 7 * x ptr
Dereferencing a pointer • If you want to change the value that ptr is pointing to, you can write the following: *ptr = 25; same effect as, x = 25; • In either case, the value at that memory location (x) was changed to 25.
Pointers int int int a; b; c; *p; *q; *r; a = 5; b = 3; p = &b; q = p; r = &c; a b c p q r a 5 p a p b 3 q 5 b q c r 3 c r
Pointers p = &a; *q = 15; a 5 p *r = *p; a *r = a + *q p 15 q 5 p a b b r 15 q 5 b q c c 5 r 15 c r 20
Dereferencing a pointer • The direct value is the address of another memory location. – A direct assignment to a pointer variable will change the address of the pointer, not the value at the address that it is pointing to. • The indirect value is the value at that other memory location. – A pointer directly refers to an address , and the * operator on the pointer will allow you to change the value at that memory location via dereferencing (indirection).
Initialization of pointers • Like all variables, pointers must be initialized before they are used. ? int *ptr; ? ? ? pointer to unknown location – in this case, ptr may contain a value that is interpreted as a memory address. – if the memory address does not exist, you will get a run-time error (segmentation fault). – if the memory address is valid, you will either get a run-time error OR
Initialization of pointers /* Example of a common error: failure to initialize a pointer before using it. This program is is FATALLY flawed. . */ int main() { int* ptr; *ptr = 99; // ptr has not been initialized printf("val of *ptr = %d and ptr is %p n", *ptr, ptr); return 0; }
Initialization of pointers The program may appear to work at times, if the address stored in ptr just happens to be a legal address in the address space of this program. Unfortunately, it may be the address of some other variable whose value is now 99!!! This situation is commonly referred to as a loose pointer and bugs such as these may be very hard to find.
Minimizing latent loose pointer problems Never declare a pointer without initializing it in the declaration. int x; int *xptr = &x; int *ptr = NULL;
Correct use of the pointer int main(void) { int y = 12; int * ptr = &y; printf("y is %dn", y); *ptr = 99; printf("now y is %dnn", y); printf("address of y is: %pn", &y); printf("contents of ptr is: %pn", ptr); printf("address of ptr is: %pn", &ptr); return 0; }
Correct use of the pointer gcc -Wall -o ptr. Ex pointer. Ex 1. c. /ptr. Ex y is 12 now y is 99 address of y is: 0 x 7 ffc 8 f 8 db 98 c contents of ptr is: 0 x 7 ffc 8 f 8 db 98 c address of ptr is: 0 x 7 ffc 8 f 8 db 990
Correct use of the pointer In C, regular local variables that are declared within any basic block are allocated on the runtime stack. /* pointer example with static variable */ #include <stdio. h> int main(void) { int y = 12; int * ptr; static int a; // not stored on the stack ptr = &y; printf("y is %dn", y); *ptr = 99; printf("now y is %dnn", y); printf("address of a is: %pn", &a); printf("address of y is: %pn", &y); printf("contents of ptr is: %pn", ptr); printf("address of ptr is: %pn", &ptr); return 0; }
Correct use of the pointer gcc -Wall -o ptr. Ex pointer. Ex 1. c. /ptr. Ex y is 12 now y is 99 address of a is: 0 x 601044 address of y is: 0 x 7 ffc 8 f 8 db 98 c contents of ptr is: 0 x 7 ffc 8 f 8 db 98 c address of ptr is: 0 x 7 ffc 8 f 8 db 990 Note that a is a heap resident variable and has an address far removed from the stack resident y and ptr.
void pointer • a void * is a generic type that is not associated with any type. i. e. , it is not the address of a character, an integer, a float, a double, or any other type. void *vptr; // pointer to void type int *iptr = NULL; // Null pointer of type int • you cannot dereference a void pointer. int a = 55; void *vpter = &a; *vptr = 100; // invalid // cannot dereference vptr
Pointer compatibility • pointers have a type associated with them • not just pointer types, but pointers to a specific type • the size of all pointers is the same (each holds the address on a memory location) • the size of the variable that the pointer points to can be different • except for a pointer to void, it is invalid to assign a pointer of one type to a pointer of another type • a void * can be assigned to a pointer to any type and a pointer to any type can be assigned to a void *
Pointer compatibility Examples: int i = 55; int j = 132; float y = 83. 7; void *vptr; int *p; int *q = &j; float *fptr; Valid assignments: vptr = q; p = vptr; // a void pointer being assigned to a pointer of some type vptr = fptr; // assigning a pointer of some type to a void pointer fptr = &y;
Pointer compatibility Examples: int i = 55; int j = 132; float y = 83. 7; void *vptr; int *p; int *q = &j; float *fptr; vptr = &i; Invalid assignments: p = fptr; // invalid to assign a float pointer to an int pointer fptr = &i; // invalid to assign a float pointer to point to an int *vptr = 112; // cannot dereference a void pointer
Pointer compatibility Can solve the incompatibility problem by type casting, i. e. you can “tell” the compiler the type of the data that “ptr” is pointing to, . int x; char c; char *pc; void *vptr; vptr = (int *)&x; pc = (char *)&x;
Pointers & Arrays • Given – Notice that a. Ptr is assigned to a and not &a – why? ? • If an array name is used without a subscript, the meaning is “the address of the first element of the array – What happens after the third line of code above? ?
Pointers & Arrays • Given the following array declaration: • Assume we also declare an integer pointer to point to the array: (What is another way to write this? ) • Then we can imagine it looking like this: • What does the following mean: *(a. Ptr + 3) • Which is the same as writing what? ? • What happens with the following: a. Ptr = a. Ptr + 1;
Pointers & Arrays • The name of an array and the address of the first element in the array represent the same thing • The name of an array is a pointer constant to the first element of the array • So, we could also use :
Pointer Arithmetic & Arrays • If score. Ptr is pointing to a specific element in the array and n is an integer, score. Ptr + n is the pointer value n elements away • We can access elements of the array either using the array notation or pointer notation – If score. Ptr points to the first element, the following two expressions are equivalent: scores[n] Array notation *(score. Ptr + n) Pointer notation
Simulating Pass-By-Reference
First, Pass-By-Value. What’s wrong with this? void swap(int first, int second) { // declare a temp integer and swap the // two parameters int temp; temp = first; first = *second; second = temp; printf("first is %d and second is %dn", *first, *second); } Function call: swap(a, b);
Pass-By-Reference void swap(int *first, int *second) { // declare a temp integer and swap the // two parameters int temp; temp = *first; *first = *second; *second = temp; printf("first is %d and second is %dn", *first, *second); } Function call: swap(&a, &b);
Dynamic Memory Allocation
Pointers and Dynamic Allocation of Memory • So far, we have always allocated memory for regular variables that are located on the stack – Size of such variables must be known at compile time • Sometimes convenient to allocate memory at run time – System maintains a second storage area called the heap – Functions calloc and mallocate memory as needed of size needed
Pointers and Dynamic Allocation of Memory: calloc • calloc – Used to dynamically create an array in the heap – Contiguous allocation • Initialized to binary zeros – Must – Takes two arguments 1. Number of array elements 2. Amount of memory required for one element – Use sizeof operator – Returns • Void pointer if successful • NULL if unsuccessful
Pointers and Dynamic Allocation of Memory: calloc
Pointers and Dynamic Allocation of Memory: malloc • malloc – Used to dynamically get memory from heap – Contiguous allocation • No initialization – Must – Takes one argument • Total amount of memory required – Returns • Void pointer if successful • NULL if unsuccessful
Pointers and Dynamic Allocation of Memory: malloc
Pointers and Dynamic Allocation of Memory: free • free Used to dynamically release memory back to heap Contiguous deallocation Must Takes one argument • Pointer to beginning of allocated memory – Good idea to also NULL pointer if reusing – –
Pointers and Dynamic Allocation of Memory: free
Command-Line Arguments
Command-Line Arguments • Arguments passed to a program upon execution are called command-line arguments. • The main() function signature changes from int main(void) to int main(int argc, char *argv[]) • The first argument argc holds the number of items types at the command prompt, including the executable name. • The second argument char *argv[] is an array of character pointers, each pointer pointing to the arguments typed in at the command-line.
Command-Line Arguments • With the reverse_echo program, if you type. /a. out testing 1 2 3 at the command-prompt, argc would have the value 5, and argv[] would look like this:
sscanf() • We have used scanf() to scan input from the keyboard. • sscanf() scans an array (or string) already in memory and reads each item into a pointer that points to the address (just like scanf()) int sscanf( buffer, format(s), arg(s) ) where buffer is the given array, or string (the source) format is the format specifier (%d, %f, %s, etc) arg is the pointer(s) to the address of each argument (destinations)
sscanf() • Example 1: int number. Of. Args = 0; number. Of. Args = sscanf(my. Int. Array, “%d, %d”, &num 1, &num 2, &num 3); • Example 2: if sample run is. /a. out John 7 12 printf(“Hello %s. n”, argv[1]); sscanf(argv[2], “%d”, &birth. Month); sscanf(argv[3], “%d”, &birth. Day);
- Slides: 45