Você está na página 1de 18

CPSC 211 Data Structures & Implementations

Pointers in C
Pointer is a variable (data object) which has as a value an address of
another variable.
P
12333
12333 (address)
Variable of type
Object Type

Pointers are used to:


• create more complex data types as lists, queues, stacks or trees.
• pass complex structures to a function (it corresponds to calling by
reference which does not exist in C).
• process arrays.
• return structured variables from a function (call by reference).
• return an allocated block of memory.

c Teresa Leyk
° Slide 1 Pointers
CPSC 211 Data Structures & Implementations

To define a pointer variable we use the same rules as defining an ordinary


variable. The only difference is that the asterisk is added in front of the
name of the pointer variable.
int i = 1; /* allocates space for integer i and
returns address to the integer */
int *iptr; /* allocates space for a
pointer to an integer */
iptr = &i; /* address of iptr is the same as
address of i */
*iptr = 2; /* stores a value (2) for a variable
pointed by iptr */
*iptr = *iptr + 1; /* the new value is 3 */

&i is the address-of operator.


The asterisk in *ptr is also called dereferencing (or indirection)
operator.

c Teresa Leyk
° Slide 2 Pointers
CPSC 211 Data Structures & Implementations

Pointers can point to nothing (NULL) or allocate storage by using


malloc or calloc functions:
typedef struct Student {
int ID
double GPA;
} Student
P = (Student *) malloc(sizeof(Student));

Before After
Allocate memory ?? ??
P P
?? for an object
Before After
ID G ID G
?? ?? Set values 12 5.5
P P

Before After
ID G
12 5.5 Free object
P P
??

P->ID = 12; P->GPA = 3.5; /* initialize */


free(P); /* release memory */

c Teresa Leyk
° Slide 3 Pointers
CPSC 211 Data Structures & Implementations

Computer memory is a one-dimensional array of bytes. Each variable is


stored in a sequence of bytes. The address of a variable is the address of
the first byte in the array of bytes.
Let *ptr = num. Then iptr value 1232 refers to the location of the
integer variable num and *iptr has the value 2.

128 1232 address


1232 ... 2 ... data
int *iptr int num variable type

c Teresa Leyk
° Slide 4 Pointers
CPSC 211 Data Structures & Implementations

Examples

Consider the block of storage referenced by int pointers pa and pb. The
assignments: *pa = 5; and *pb = 10; are correct. But the
instruction pa = 17 is incorrect because there is mismatch of types
(type pointer to int and int are not the same). The instruction *pa =
*pb copies the value in the storage pointed by pb to the storage pointed
by pa. If we have pa = pb; then both the pointer variables reference to
the same storage (which contains 10 in this case). They are called aliases.
The block of storage such that no pointer references to it becomes
inaccessible. The function free(pa); returns the block of storage
referenced by pa to the pool of available storage. In C, there is no
automatic garbage collection. Recycling of storage must be managed by
the programmer. If we have the situation: pa = pb; and free(pb);
then pa is a dangling pointer, that is, a pointer which references to an
inaccessible block of storage. This is a source of difficult-to-find bugs.

c Teresa Leyk
° Slide 5 Pointers
CPSC 211 Data Structures & Implementations

Indirection and Address-Of Operators

Indirection: * is applied only to a pointer variable, to refer the location


whose address is held by the pointer variable.
Address-of: & can be applied to non-pointer and pointer variables.
int *iptr;
int i = 2;
*iptr = 17; /* correct */
iptr = &i; /* correct */
iptr = &17; /* wrong, you can’t apply
& to a literal (number) */
i = iptr; /* wrong, incompatible types */
i = *iptr; /* correct */
iptr = i; /* wrong, incompatible types */

c Teresa Leyk
° Slide 6 Pointers
CPSC 211 Data Structures & Implementations

Passing Pointer Variables as Parameters

We can use pointers as formal parameters of a function.


void printID(Student *sr) {
printf("Student ID is %d\n", sr->ID);
}

Example 1. We can call the function printID as follows:


Student sr = {67890, 3.4};
printID(&sr); /* & is necessary here */

Example 2. This is another way:


Student *sr; /* not initialized */
sr = (Student *) malloc(sizeof(Student));
sr->ID = 67890;
sr->GPA = 3.4;
printID(sr);

c Teresa Leyk
° Slide 7 Pointers
CPSC 211 Data Structures & Implementations

Passing Parameters to a Function


In C, call by value is the only way to pass parameters to a function. But
when a pointer to a variable is used as a formal parameter and then this
variable is changed inside the function then it is also changed in the actual
parameter. Example:
void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
}

A space for the variables a, b, temp is allocated statically in this function


and this space is automatically released after its execution. Therefore, if
you call
int a = 2, b = 3;
swap(a, b);

the swap function does not swap the values of a and b.

c Teresa Leyk
° Slide 8 Pointers
CPSC 211 Data Structures & Implementations

To use swap correctly you must use another approach.


void swap(int *a, int *b)
{
int temp;
temp = *a;
*a = *b;
*b = tmp;
}

int main()
{
int a = 2, b = 3;
printf("before: a = %d, b = %d\n", a, b);
swap(&a, &b); /* & is necessary here */
printf("after: a = %d, b = %d\n", a, b);
}

c Teresa Leyk
° Slide 9 Pointers
CPSC 211 Data Structures & Implementations

Memory Allocation

To allocate memory dynamically the function malloc is used. It returns


a generic pointer of type void*. In order to obtain a correct type we
must change the generic pointer type to a type we need using a cast (for
instance, (int*)). The obtained pointer indicates the beginning of the
allocated space. If malloc fails to allocate memory it returns NULL.
int *a;
a = (int *) malloc(sizeof(int));
if (a == NULL) { printf("malloc failed\n"); }
*a = 120;

Usually, we do not allocate space for variables of primitive type at run


time. Typically, malloc is used to allocate space for a structure or an
array.

c Teresa Leyk
° Slide 10 Pointers
CPSC 211 Data Structures & Implementations

Examples
typedef struct {
int ID;
double GPA; /* grade */
} Student;
Student *sptr;
sptr = (Student *) malloc(sizeof(Student));
sptr->ID = 2310;
sptr->GPA = 3.4;

To allocate an array dynamically, we multiply sizeof(type) by the


required number of elements of the array.
int i;
Student *p; /* p is an array */
p = (Student *) malloc(35*sizeof(Student));
for (i = 0; i < 35; i++) {
p[i].ID = 120 + i;
p[i].GPA = 0.0;
}

c Teresa Leyk
° Slide 11 Pointers
CPSC 211 Data Structures & Implementations

Memory Deallocation
The allocated memory remains in use until the program has finished or
memory is released using the function free.
Example of a memory leak:
void section() {
Student *p;
p = (Student *) malloc(35*sizeof(Student));
return; /* wrong! */
}

After executing the function section the pointer p is removed from the
stack but the allocated memory is not released and it cannot be accessed.
To access the array outside section a pointer to an array must be
returned.
Student *section() {
Student *p;
p = (Student *) malloc(35*sizeof(Student));
return p; }

c Teresa Leyk
° Slide 12 Pointers
CPSC 211 Data Structures & Implementations

Operations on Pointers
&i address of a referenced location
*p contents of a referenced location
p++ value of the pointer p incremented by one unit of base type size (p
= p + sizeof(base type))
++p increments the pointer p = p + sizeof(base type) then
gets the value of p
p = &i assigns a memory location to the pointer
type *p declares a pointer and its base type

*(p++) or *p++ increments p and than gets a value of *p


(*p)++ is not equivalent to *p++

*(++p) or *++p preincrements p, then gets the value


++(*p) increments the value pointed to by p

c Teresa Leyk
° Slide 13 Pointers
CPSC 211 Data Structures & Implementations

Arrays
A pointer can be treated as just a memory address of a block of storage.
But this interpretation of a pointer is not always useful, and we will treat
pointers in a more abstract way. A very useful interpretation is to see a
pointer as a generalization of an index of a vector (array). Especially in C
you can easily notice this relation between pointers and vector indices.
double A[100]; /* elements start from 0,
that is, A[0],A[1],...,A[99] */
double *pa = &A[3]; /* pa points to the 4th
element of A */
double *pa1 = &A[5]; /* the same can be done as
follows: */
pa = A + 3; /* pointer arithmetic is involved here! */
/* here we get that the distance between
pa1 and pa is 2 = 5-3 */
printf("distance between pointers pa"
" and pa1 is = %d\n", pa1 - pa);

c Teresa Leyk
° Slide 14 Pointers
CPSC 211 Data Structures & Implementations

The name of an array is a pointer to the first element of the array. The
array name is a constant pointer, it cannot be changed by performing
pointer arithmetic. Note that C compiler does not check bounds of an
array.
There is no pointer arithmetics in Pascal and Java.
In languages where pointers are unavailable (as for instance Fortran77)
we can still use vector indices to emulate pointers but we lose their
dynamical feature (the possibility of changing the size of a data structure
during runtime).

c Teresa Leyk
° Slide 15 Pointers
CPSC 211 Data Structures & Implementations

More about Pointers


Pointers are very useful in dynamically created data structures. They are
used in many data structures we are going to discuss (for instance, in
linked representations of data structures).
typedef struct {
int ID;
double GPA;
} Student;
int main() {
Student *P, *Q;
P = (Student *) malloc(sizeof(Student));
P->ID = 99999999;
P->GPA = 3.4;
Q = P; /* Q is an alias */
...
free(P); /* deallocate memory pointed by P */
P = Q = NULL; /* otherwise P and Q
are dangling pointers */
... }

c Teresa Leyk
° Slide 16 Pointers
CPSC 211 Data Structures & Implementations

An address is always a positive integer. Therefore the address 0 represents


a special value meaning that no address is available. Often this 0 is
denoted by NULL.
Exercise
/* Checking sizes of objects in C.
The results are obtained on a 32-bit machine
where pointers are 4-byte long */
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char A[10];
char (*B)[10];
char *C[10];
char *D;
printf("sizeof(A) = %d\n", sizeof(A));

c Teresa Leyk
° Slide 17 Pointers
CPSC 211 Data Structures & Implementations

printf("sizeof(*A) = %d\n", sizeof(*A));

printf("sizeof(B) = %d\n", sizeof(B));

printf("sizeof(*B) = %d\n", sizeof(*B));

printf("sizeof(C) = %d\n", sizeof(C));

printf("sizeof(*C) = %d\n", sizeof(*C));

/* dynamic memory allocation */


D = malloc(10*sizeof(char));
printf("sizeof(D) = %d\n", sizeof(D));

printf("sizeof(*D) = %d\n", sizeof(*D));

return 0;
}

c Teresa Leyk
° Slide 18 Pointers

Você também pode gostar