1 / 21

Chapter 11

Chapter 11. 8 bits = 1 byte. 0. 1. 0. 1. 0. 0. 1. 1. The first step in understanding pointers is visualizing what they represent at the machine level. In most modern computers, main memory is divided into bytes , with each byte is capable of storing eight bits of information:.

aaralyn
Download Presentation

Chapter 11

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Chapter 11 8 bits = 1 byte 0 1 0 1 0 0 1 1 The first step in understanding pointers is visualizing what they represent at the machine level. In most modern computers, main memory is divided into bytes, with each byte is capable of storing eight bits of information:

  2. Address Contents 0 1 2 3 4 n-1 1 byte 01010011 01110101 01110011 01100001 01101110 n bytes 01000011 A machine with 16 megabytes of main memory has 16,777,216bytes. Each byte has a unique address to distinguish it from other bytes in memory. If there are n bytes in memory, then addresses range from 0 to n – 1.

  3. variable address 2000 2001 i An executable program consists of both code (machine instructions corresponding to statements in the original C program) and data (variables in the original program). Each variable in the program occupies one or more bytes of memory; the address of the first byte is said to be the address of the variable. In the following figure, the variable i occupies the bytes at addresses 2000 and 2001, so i's address is 2000:

  4. variable address 2000 2001 i p i To indicate that a pointer variable p stores the address of a variable i, the contents of p is shown as an arrow directed toward i: Addresses are stored in special pointer variables. We store the address of a variable i in the pointer variable p, we say that p "points to" i. In other words, a pointer is nothing more than an address, and a pointer variable is just a variable that can store an address.

  5. Declaring Pointer Variables A pointer variable is declared in much the same way as an ordinary variable. The only difference is that the name of a pointer variable must be preceded by an asterisk: int *p; Pointer variables can appear in declarations along with other variables: int i, j, a[10], b[20] , *p, *q; In this example, i and j are ordinary integer variables, a and b are arrays of integers, and p and q are pointers to integer objects. C requires that every pointer variable point only to objects of a particular type (the referenced type): int *p; /* points only to integers */ float *q; /* points only to floats */ char *r; /* points only to characters */ There are no restrictions on what the referenced type may be. (A pointer variable can even point to another pointer.)

  6. C provides a pair of operators designed specifically for use with pointers. To find the address of a variable, we use the & (address) operator. If x is a variable, then &x is the address of x in memory. To gain access to the object that a pointer points to: use the * (indirection) operator. If p is a pointer, then *p represents the object to which p currently points. The Address Operator Declaring a pointer variable sets aside space for a pointer but does not make it point to an object: int *p; /* points nowhere in particular */

  7. p i ? Initialize ‘p’ before using it. One way to initialize a pointer variable is to assign it the address of some variable using the & operator: int i, *p; /* declare pointer variable ‘p’ */ p = &i; /* initialize ‘p’ by assigning the address of variable ‘i’ */ /* this statement makes ‘p’ point to ‘i’ */ The assignment of &i to p does not affect the value of i The address operator can appear in declarations, so it's possible to initialize a pointer at the time we declare it: int i ; int *p = &i; /* initialize & declare pointer */ We can even combine the declaration of i with the declaration of p, provided that i comes first: int i, *p = &i;

  8. Indirection Operator Once a pointer variable points to an object, we can use the * (indirection) operator to access what's stored in the object. If p points to i, for example, we can print the value of i as follows: printf("%d\n", *p) ; printf will display the value of i, not the address of i. * is the inverse of & Applying & to a variable produces a pointer to the variable Applying * to the pointer takes us back to the original variable j = *&i; /* same as j = i; */

  9. i p ? p p i i 2 1 p points to i, then *p is an alias for i. *p has the same value as i, but changing the value of *p also changes the value of i. The following example illustrates the equivalence of *p and i; p = &i; /* p points to i */ printf("%d\n", i) ; /* prints 1 */ printf("%d\n", *p) ; /* prints 1 */ i = 1; /* p points to i thus *p is an alias for i */ *p = 2 printf("%d\n", i) ; /* prints 2 */ printf("%d\n"/*p); /* prints 2 */ /* changing the value of *p also changes the value of i */

  10. Never apply the indirection operator to an uninitialized pointer variable. If a pointer variable p has not been initialized, the value of *p is undefined: int *p; printf("%d", *p); /* prints garbage */ Assigning a value to *p is even worse; p might point anywhere in memory, so the assignment modifies some unknown memory location: int *p ; *p=1; /*** WRONG ***/ The location modified by this assignment might belong to the program (perhaps causing it to behave erratically) or to the operating system (possibly causing a system crash).

  11. Pointer Assignment q = p; This statement copies the contents of p (the address of i) into q, in effect making q point to the same place as p: p i q ? C allows the use of the assignment operator to copy pointers, provided that they have the same type. int i, 3, *p, *q; These statements are examples of pointer assignment: the address of i is copied into p. p = &i;

  12. p i 1 q p i 2 q Both p and q now point to i, so we can change i by assigning a new value to either *p or *q: *p = 1; *q = 2; Any number of pointer variables may point to the same object. Be careful not to confuse q = p; with *q = *p;

  13. i p 1 q j ? i p 1 j q 1 The first statement is a pointer assignment; the second isn't, as the following example shows: p = &i; q = &j; i = 1; *q = *p; The assignment *q = *p copies the value that p points to (the value of i)into the location that q points to (the variable j).

  14. We saw in Section 9.3 that a variable supplied as an argument in a function call is protected against change, because C passes arguments by value. This property of C can be a nuisance if we want the function to be able to modify the variable. Pointers offer a solution to this problem: instead of passing a variable x as the argument to a function, we'll supply &x, a pointer to x. We'll declare the corresponding parameter p to be a pointer. When the function is called, p will have the value &x, hence *p (the object that p points to) will be an alias for x. Each appearance of *p in the body of the function will be an indirect referenceto x, allowing the function both to read x and to modify it.

  15. In the decompose function declare the parameters int_part and frac_part to be pointers. The definition of decompose will look like this: void decompose(float x, int *int_part, float *frac_part) { *int_part = (int) x; *frac_part =x - *int part; } The declaration or prototype for decompose could be either void decompose(float x, int *int_part, float *frac_part); or void decompose(float, int *, float *) ; We'll call decompose in the following way: decompose(3.14159, &i, &f);

  16. x 3.14159 i Int_part 1 frac_part f 1 We'll call decompose in the following way: decompose(3.14159, &i, &f); Because of the & operator in front of i and f, the arguments to decompose are pointers to i and f, not the values of i and f. When decompose is called, the value 3.14159 is copied into x, a pointer to i is stored in int_part, and a pointer to f is stored in frac__part:

  17. x 3.14159 i Int_part 3 frac_part f ? x 3.14159 i Int_part 3 frac_part f .14159 The first assignment in the body of decompose converts the value of x to type int and stores it into the location pointed to by int_part. Since int_part points to i, the assignment puts the value 3 in i: The second assignment fetches the value that int_part points to (the value of i), which is 3. This value is converted to type float and subtracted from x, giving .14159, which is then stored in the location that frac_part points to: When decompose returns, i and f will have the values 3 and .14159, just as we originally wanted.

  18. Using pointers as arguments to functions is actually nothing new; we've been doing it in calls of scan f since Chapter 2. int i; scanf("%d", &i) ; We must put the & operator in front of i so that scanf is given a pointer to i; that pointer tells scanf where to put the value that it reads. Without the &, scanf would be supplied with the value of i. It is not always true that every scanf argument needs the & operator. In the following example, scanf is passed a pointer variable: int i, *p; p = &i; scanf("%d", p); Since p contains the address of i, scanf will read an integer and store it in i. Using the & operator in the call would be wrong: scanf("%d", &p); /*** WRONG ***/ scanf would read an integer and store it in p instead of in i.

  19. Using const to Protect Arguments When we call a function and pass it a pointer to a variable, we normally assume that the function will modify the variable. f(&x); We expect f to change the value of x. It's possible, though, that f merely needs to examine the value of x, not change it. The reason for the pointer might be efficiency: passing the value of a variable can waste time and space if the variable requires a large amount of storage. We can use the word const to document that a function won't change an object whose pointer is passed to the function. void f(const int *p) { *p = 0; /* WRONG - p points to a constant integer, can not change it */ } This use of const indicates that p is a pointer to a "constant integer."Attempting to change *p will provoke a message from the compiler.

  20. Pointers as Return Values We can not only pass pointers to functions, but also write functions that return pointers. For example, we may want a function to return the location of an answer instead of returning its value. The following function, when given pointers to two integers, returns a pointer to whichever integer is larger: int *max(int *a, int *b) { if (*a > *b) return a; else return b; }

  21. When we call max, we will pass pointers to two int variables and store the result in a pointer variable: int *p, x, y; p = max(&x, &y) ; During the call of max, * a is an alias for x, while *b is an alias for y. If x has a larger value than y, max returns the address of x; otherwise, it returns the address of y. After the call, p points to either x or y. Although the max function returns one of the pointers passed to it as an argument, that's not the only thing a function can return. Some functions return a pointer to one element of an array passed as an argument, this is discussed in chapter 12 (optional).

More Related