CS270 Colorado State University ======== Pointers ======== Ch. 16 ----------- Variables During execution of a program, a variable corresponds to a memory location. The address of that location replaces all symbolic references to the variable. A variable is a data container. int i; ... i = 6; // point x During execution i refers to some data location, and at point x this location holds the value 6. The type of the variable defines how the bits making up the data are to be interpreted. ------------ Types Example of how bits are interpreted: the char type. What is wrong (or, what will happen during execution) with: char i; for(i=0;i<256;i++) printf("%d\n",i); There are two issues here, the size and the value range of char: The char type can be implemented as a signed or an unsigned integer of size one byte, so its values can range from -127 to 128, or from 0 to 255. There is also an unsigned char type, that always ranges from 0 to 255. -------------- Pointers Pointer variables contain values that are the addresses of memory locations. The type of the pointer variable defines: 1. How to interpret the bits at the memory location 2. the size of the memory location the pointer refers to e.g. int *p; or int* p; Declares a pointer variable that interprets the word it refers to as an int. We can change the way a sequence of bits is interpreted by referring to it using a different pointer type. Check this out (also see endian.c, which is posted on the class schedule): So, we can point at a location in memory with different types of pointers. How do we get one type of pointer from another? By casting: We take the address of c, turn it into an address of an int by casting, and assign it to p. If we now write into memory using p: we write 4 bytes, and hence go beyond the boundary of c, which occupies 1 byte. What will happen is program and compiler dependent. ------------------------- Pointer-Related Operators We have used two address related operators * and & The declaration says "if you dereference p" ie access the memory location p point at you get a char. Ie p is a char pointer variable, c is a char variable now makes p point at c, so now makes c contain 'a'. There are four common ways pointers are set: Of these, number 3 is the most dangerous and source of most errors in C programs. We may dereference pointer values (eg. NULL) that do not really refer to a location in the program segment, or we may point out of the range of the composite structure (eg. array) we are traversing. Example with pointer usage -------------------------------- Implementing & and * in assembly ============== Dynamic Memory ============== Ch. 19 A program in execution consists of several memory segments to which its address space is mapped code static Heap RTS: run-time stack ---------- --------- --------------> <------------------- static has all global / static variables RTS has function activation frames, reflects all active calls top of the RTS is currently active function Local variables of called functions "disappear" from the RTS when the function terminates Heap has data that can outlive the function that created it. heap data is explicitly allocated and deallocated using calls to a memory manager, which has been linked and loaded with the program code. The memory manager keeps track of the top of the RTS, and administrates which heap blocks are dynamically allocated and which are not (free blocks). It's called a heap because it is usually organized in heap (type of binary tree) form to quickly allocate a block of a certain size. The C standard library (stlib) provides system functions to allocate and free heap blocks. Two of these functions are malloc() and free(). MALLOC() -------- A call to void* malloc(size_t size); returns either NULL, if the allocation failed or the address of the first byte of a newly allocated segment of size AT LEAST size (we can only count on size bytes though). There are no assumptions about the initial values in the data segment, the program is responsible for initializing it. FREE() ------ When the program does not need the malloc-ed data segment anymore it can give it back to the memory manager calling void free(void* ptr); The memory manager inserts the segment back into the heap of free blocks. Notice that ptr must point to a segment previously malloc-ed, otherwise unpredictable begavior results. Here is a big difference with Java, which has a garbage collector, so Java programs do not need explicit free() calls. ---------------------------------- Pointer and Dynamic Memory Example int * foo() { int a; return &a; } int baz(int p1) { return p1*p1; } void bar() { int * p = foo(); *p = 89; int x = baz(4); if (*p != 89) { printf ("Hey what happened?"); } } ====== Arrays ====== Ch. 16 One Dimensional Arrays and Strings. A local one-dimensional array is a CONSECUTIVE sequence of elements of the same type (and thus size), represented by a CONSTANT pointer to the first element. CONSECUTIVE: we can compute the address of element i: p+i*sizeof(elem) if p is the constant pointer to the array. CONSTANT: not a pointer variable, we cannot reassign to p, if p is the constant pointer to the array. see arrPtr.c for C examples of manipulating pointers to arrays. -------------- Array examples Local array allocated on stack int a= {1,2,3,4,5}; Dynamic allocation of array on heap int *p = malloc(5*sizeof(int)); The C compiler knows the type, and thus the size, so p is equivalent with *(p+i), which gets translated into There is NO AUTOMATIC BOUNDSCHECKING in C. This was a deliberate choice, efficiency is more important than safety in C. In Java every array access is bounds checked. Both Java and C have lowerbounds 0 in arrays, which simplifies array bounds checking. ---------------------------- Array Parameter Passing in C int A; fuzz(A); In fuzz(A) the value that gets passed to the function fuzz is A, the reference to the first element of the array. See arrPtr.c -------------- Dynamic arrays As opposed to staic arrays that live in global memory, or arays local to a function, that live on the run time stack, dynamic arrays live on the heap. They are created using malloc. Now a ponter variable is used to refer to the array elements. int *p = (int *) malloc(30*sizeof(int)); ------- Strings C has string literals: "hello" Strings are terminated by a zero char: '\0' Strings are allocated in a char array, that must be at least one larger than the string length, because of the delimiting '\0'. #include declares use of the string library, containing functions strlen, strcpy, and strcat. In strCpCat.c we redefine these functions to show their behavior. Check out: malloc.c mallocFree.c ============== Structures ============== LC3state from PA3 and PA4 was a structure datatype. sym_node_t from PA4 Structures can be allocated on the stack or dynamically. stack example heap example Bug avoidance: C compilers layout the fields for structures in order, but they might put in padding to improve alignment. Never do pointer arithmetic to access into structures. Check out: LL.c, which is a linked list example ------------------------ mstrout@cs.colostate.edu, 12/3/08 Much of these notes were written by Wim Bohm and then edited with permission. Dr. Bohm's source was the Frantisek Franek book on the C Memory Model.