COP 3223H meeting -*- Outline -*- * Syntax and Smantics of Pointers in C Draw pictures! ** Overview *** Concept of Pointers ------------------------------------------ THE POINTER CONCEPT A pointer in C is Think of memory as char memory[HUGE]; int i = 20; memory[i] = 'U'; printf("memory[%d] is '%c'\n", i, memory[i]); // same thing with pointers Pointer operators: dereference: address of: printf("*(memory + %d) is '%c'\n", i, *ptc); printf("memory + i is %lx\n", (uintptr_t)(memory + i)); printf("&memory[i] is %lx\n", (uintptr_t)(&memory[i])); Basic principle: each address is ------------------------------------------ ... a memory address like "a URL for storage" ... a big array (of bytes on an x86 machine) and each index is an address ... char *ptc = memory + 20; *ptc = 'U'; ... *, which is like array subscripting ... &, which is like the array index into the computer's memory (See the code in memory.c) -- the uintptr_t is the type of pointers that have been cast to unsigned ints in whatever the compiler is. ... unique *** Uses of Pointers ------------------------------------------ USES OF POINTERS - Provides indirect addressing - Allows access to - Can represent - Efficient passing - Can modularize ------------------------------------------ ... like machine code (efficiently) ... large amounts of data (dynamically allocated) ... graph-like structures directly ... of large data without copying it ... patterns of code that involve assignments (mutation) of parameters (example later) ** Syntax *** Pointer Types ------------------------------------------ POINTER TYPES Expressions related to pointer types: ::= ... | * | & Pointer type syntax: ::= ... | * Pointer variable declaration syntax: * ; Examples: int *ptoi; char *ptc; int **ptpti; Pointer types may combine with other types: char *argv[10]; is such that argv[3] has type char * so it is an ------------------------------------------ array of pointers to chars (perhaps an array of C strings) (the array typing has precedence over the pointer typing, so it's like char *(argv[10]); *** constant variables and pointers ------------------------------------------ CONST The type qualifier const can be used to declare Examples: const int seven = 7; const char nc = '\0'; const int *pto7 = &seven; illegal with the above: seven = 8; // illegal! seven++; // illegal! *pto7 = 8; // illegal! *pto7 -= 1; // illegal! ------------------------------------------ ... a variable that shouldn't be modified Note that one can't split const declarations into 2 parts: const int seven; seven = 7; // illegal! Note that for the last one, when you do *pto7, you get a const int, think of the form of the declaration: pto7 has type const int * *pto7 has type const int ------------------------------------------ POINTERS CAN ALSO BE CONST POINTERS TO CONSTs vs. CONST POINTERS const int seven = 7; int eight = 8; const int *pto7 = &seven; int *const cpto8 = &eight; Here pto7 is and cpto8 is Allowed or illegal? *pto7 = 9; pto7 = &eight; *cpto8 = 9; cpto8 = &seven; ------------------------------------------ ... a pointer to a const int ... a const pointer to an int ... *pto7 = 9; is illegal, as the type of *pto7 is const int pto7 = &eight is legal, as the pointer variable can be assigned *cpto8 = 9 is legal, as the type of *cpto8 is int cpto8 = &seven is illegal, as the pointer varaible can't be assigned ** semantics ------------------------------------------ ABSTRACT MODEL OF POINTERS IN C 1. The program's memory is like 2. A pointer identifies 3. If p has type (T *), then *p, of type T, 4. If x has type T, then &x, of type (T *), 5. If p has type (T *), then p+1 is ------------------------------------------ ... several big arrays of different element sizes (chars = 1, ints = 4, ...) all occupying the same space [ | | | | ... [ | | ... [ | ... ... a place in that array (an address) ... is the the contents of memory at index p in the array for sizeof(T) ... is the address of the memory where x is located, i.e., the index into the array for sizeof(T). ... the address of the next element in the array for sizeof(T), i.e., p+sizeof(T) in the char array in general p+k = p + (k*sizeof(T)) in terms of char indexes ------------------------------------------ THE VIEW FROM THE MACHINE 1. The computer's memory is a big array of chars 2. A pointer is an index into that array = an address 3. *p is the contents of the memory at that address (load indirect or store indirect) 4. &x is the address of x 5. p+1 adds sizeof(typeof(*p)) to address p ------------------------------------------ This is the view that low level programming uses *** parameter passing in C ------------------------------------------ PARAMETER PASSING IN C Arguments to functions are always Expression of type Value is ================================== int an int char a char float a double double a double T [] T * Arrays are passed ------------------------------------------ ... passed by value ... int, char, double, etc. ... a pointer to T (of type T *) a pointer to T (of type T *) ... by passing their pointer value Note: people will tell you that in C some things are "passed by reference", but that is wrong! Arrays are passed by value in C, the value is a pointer (which some people call a reference) ------------------------------------------ RETURN TYPES Can't return an array in C, char [] f() { ... } // illegal! Must return the pointer equivalent char * f() { ... } // type is ok ------------------------------------------ Thus only values can be returned *** pointers into arrays ------------------------------------------ TECHNICAL RESTRICTION ON BOUNDS - If you have a pointer into an array of type T elements T a[10]; T *p = a; // equivalently &a[0] then p is only However, ------------------------------------------ ... allowed to point to elements of a ... this is not checked in C! Writing past the end of an array is the cause of multiple security problems in C programs (e.g. in Operating Systems) ------------------------------------------ DANGLING POINTERS def: a *dangling pointer* is a pointer that points to memory that is Example: #include #include // Causes a dangling pointer, bad code! int * getspace() { int x = 7; return &x; // wrong! creates dangling pointer } // Demonstrates the effect of dangling pointers int main() { int *ptoi = getspace(); // now disaster ensures... printf("*ptoi is %d\n", *ptoi); *ptoi = 8; return EXIT_SUCCESS; } ------------------------------------------ ... not (or no longer) allocated Maybe these should be called zombie pointers? The program, in dangling.c, gives a segmentation fault Draw a picture of the stack ------------------------------------------ TO AVOID DANGLING POINTERS 1. Never return a pointer 2. Use malloc to allocate long-lived data #include #include // return space for an int on the heap int * getspace() { int *ptoi = malloc(sizeof(int)); return ptoi; } // Demonstrates the use of malloc int main() { int *ptoi = getspace(); // now things are okay *ptoi = 8; printf("*ptoi is %d\n", *ptoi); return EXIT_SUCCESS; } ------------------------------------------ ... to locally-declared space (don't pass pointers up the stack, but it's okay to pass them down the stack) See fixed_dangling.c And draw a picture!