Download presentation
Presentation is loading. Please wait.
Published byFarida Hadiman Modified over 5 years ago
1
Pointers The C programming language gives us the ability to directly manipulate the contents of memory addresses via pointers. Unfortunately, this power brings with it the freedom to screw things up spectacularly as simple errors can corrupt the state of your program in ways that make debugging difficult. The goal of these slides is to make sure that you understand exactly what you're doing when you use pointers in your code. The iconic clay figure depicted in this slide is Binky of the claymation Pointer Fun with Binky.
2
Memory 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xA 0xB
Code and data for your program are stored in random-access memory (RAM), which is basically a huge array of 1 byte (8 bits) blocks. Each block is associated with a hexadecimal number that represents its memory address. Just as ints are variables that store integers and floats are variables that store floating-point values, a pointer is a variable that stores memory addresses. In the appliance (a 32-bit operating), a memory address is 4 bytes, so it makes sense that a pointer is also 4 bytes. 0x8 0x9 0xA 0xB
3
You should now be able to understand this comic!
4
<type>* <variable name>
Creating Pointers Here's how to declare a pointer in C. Remember that a pointer's value is a memory address. Its type then describes the data located at that address. So in the first example, int* x declares a pointer to 4 bytes of memory that will contain an integer. Declaring pointers: <type>* <variable name> Examples: int* x; char* y; float* z;
5
Referencing and Dereferencing
& is the reference, or address-of, operator. It returns the address in memory at which a variable is stored. * is the dereference operator. A pointer's value is a memory address. When the dereference operator is applied to a pointer, it returns the data stored at that memory address. Referencing: &<variable name> Dereferencing: *<pointer name>
6
Under the hood... Variable Address Value x 0x04 5 ptr 0x08 copy 0x0C
int x = 5; int* ptr = &x; int copy = *ptr; Here are examples of the referencing and dereferencing operators in use. Let's think carefully about what's going on under the hood as each line executes. The first line declares an integer called x. 4 bytes are allotted for x at memory address 0x04, and the value 5 is stored there. The second line declares an int pointer called ptr. 4 bytes are allotted for ptr at memory address 0x08, and the address of x is stored there. The third line declares an integer called copy. 4 bytes are allotted for copy at memory address 0x0C, and the value of the integer that ptr is pointing to is stored there.
7
Track the values x ptr 5 &x 35 int x = 5; int* ptr = &x; *ptr = 35;
Let's track the values of these variables as each line executes: In the first line, x is initialized to 5. In the second line, ptr is assigned x's memory address. x remains 5. In the third line, we dereference ptr (aka, go to the value it is pointing to) and change that value to 35.
8
Test Yourself a b c pa pb pc a = b * c; a *= c; b = *pa; pc = pa;
*pb = b * c; c = (*pa) * (*pc); *pc = a * (*pb); int a = 3, b = 4, c = 5; int* pa = &a, *pb = &b, *pc = &c; Test yourself by tracking the values of these variables just as we did in the previous slide.
9
Answers a b c pa pb pc a = b * c; a *= c; b = *pa; pc = pa;
20 4 5 &a &b &c 100 500 10000 50000 a = b * c; a *= c; b = *pa; pc = pa; *pb = b * c; c = (*pa) * (*pc); *pc = a * (*pb); int a = 3, b = 4, c = 5; int* pa = &a, *pb = &b, *pc = &c; Answers to last slide's exercise!
10
Pointer Arithmetic Adding/subtracting n adjusts the pointer by
n * sizeof(<type of the pointer>) bytes x y 5 0x04 0x08 You can adjust pointers by adding or subtracting an integer. Adding or subtracting n adjusts the pointer by n * sizeof(<pointer type>) bytes. For example, in the code on this slide, y is a pointer to an int called x, which is stored at 0x04. Therefore, adding 1 to y shifts the value of y by 1 * sizeof(int) or 4 bytes. int x = 5; int* y = &x; y += 1;
11
What will print? int main(void) { char* str = "happy cat";
int counter = 0; for (char* ptr = str; *ptr != '\0'; ptr++) counter++; } printf("%d\n", counter); Pay close attention to the syntax of this for loop. ptr starts out pointing to the first character of the string. Incrementing ptr shifts the pointer by 1 * sizeof(char)or 1 byte, moving ptr to the next character in the string. After the loop executes, the length of the string will be printed.
12
1 2 3 Pointers and Arrays 1 2 int array[3]; *array = 1;
1 2 int array[3]; *array = 1; *(array + 1) = 2; *(array + 2) = 3; Under the hood, an array is treated like a pointer to its first element, so standard pointer arithmetic applies: *array is equivalent to array[0] *(array+1) is equivalent to array[1] *(array + 2) is equivalent to array[2].
13
Dynamic Memory Allocation
In this diagram of a program’s memory, the heap is a pool of available memory that can be allocated dynamically while your program is running. Whereas a function's local (i.e. stack) variables disappear when the function returns, memory allocated from the heap will persist until it is explicitly given back to the operating system.
14
A call to malloc() prototype: void* malloc(size in bytes); example:
The C library provides a function called malloc() (short for memory allocation) that allocates a block of memory from the heap and returns a pointer to it. Whenever your program needs fresh storage at run time that must outlast the current function, it can call malloc(), passing it the number of bytes needed. Since the sizes of data types vary from system to system, C provides the sizeof() operator for determining the size of a particular type. In this example, sizeof(int) * 10 evaluates to 40 bytes on the appliance, so we are asking the OS for a pointer to 40 bytes of memory. **** Note that sizeof() is considered an operator not a function because it takes any kind of data type and returns the appropriate size, whereas a function must specify what type of argument it takes. **** prototype: void* malloc(size in bytes); example: int* ptr = malloc(sizeof(int) * 10);
15
Check for NULL! int* ptr = malloc(sizeof(int) * 10); if (ptr == NULL)
Normally malloc() returns a pointer to a block of newly allocated memory from the heap. However, if there is an error, or the heap has been exhausted, malloc() returns NULL. For this reason, ALWAYS CHECK THE POINTER RETURNED BY MALLOC!! If the returned pointer is NULL, you must handle this case by signaling an error. Programs that don't perform this check can dereference NULL, which results in a segmentation fault. int* ptr = malloc(sizeof(int) * 10); if (ptr == NULL) { printf("Error -- out of memory.\n"); return 1; }
16
A call to free() prototype: void free(pointer to heap memory);
When a program has finished using heap memory, it should release the storage by calling free() on the pointer that was originally produced by malloc(). All memory that is malloc'd must later be free'd (but only once), and only memory that was produced by malloc() should be free'd. prototype: void free(pointer to heap memory); example: free(ptr);
17
#include <stdio.h> #include <cs50.h> int main(void) {
int* ptr = malloc(sizeof(int)); if (ptr == NULL) printf("Error -- out of memory.\n"); return 1; } *ptr = GetInt(); printf("You entered %d.\n", *ptr); free(ptr); Let's walk through this program: First, we ask the OS for a pointer to 4 bytes of memory in the heap. Next, we check to make sure malloc() did not return NULL. We then get an integer from the user, store it in the memory that malloc() gave us, and print the integer. Finally, we free the malloc'd memory.
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.