pointers and memory allocation -l. grewe

Post on 19-Jan-2016

49 Views

Category:

Documents

3 Downloads

Preview:

Click to see full reader

DESCRIPTION

Pointers and Memory Allocation -L. Grewe. Objectives. Why and What are Pointers Create Pointers in C++ Memory Allocation Defined Memory Allocation/Deallocation in C++ Potential Problems with Pointers and Memory. What's the point of pointers?...why?. - PowerPoint PPT Presentation

TRANSCRIPT

Pointers and Memory Allocation-L. Grewe

Objectives

•Why and What are Pointers

•Create Pointers in C++

•Memory Allocation Defined

•Memory Allocation/Deallocation in C++

•Potential Problems with Pointers and Memory

What's the point of pointers?...why?• Pointers can be used as variable length

arrays.

• Pointers can be used for advanced data structures.

• Pointers can be "cheaper" to pass around a program.

• Can sometimes be difficult to program without them-

Motivating Example – for pointers and memory allocation

Bag class

– bag::CAPACITY constant determines the capacity of every bag

– wasteful (if too big) and hard to reuse (if too small)

• need to change source code and recompile

Solution:

– provide control over size in running time

– dynamic arrays

– pointers and dynamic memory

Pointers

Pointer is a variable that contains the address of a variable

– Low level representation of the hardware implementation

Typical machine has an array of memory cells (usually bytes (8-bits)) numbered (addressed) consecutively

A pointer is a group of cells that can hold an address

– On modern computers memory address requires 32 – 64 bits (4 – 8 bytes)

|| || || || ... ......CpC

pC = pointer to variable C

Pointer Variable

Let’s look at local variables

Q: What’s the value of i?

??900900

904904

908908

912912

916916

……

int i; ii

By this declaration, a cell By this declaration, a cell of 4 adjacent bytes (in of 4 adjacent bytes (in some machines) are some machines) are allocated in the local allocated in the local memory (called memory (called stack stack

memorymemory))Address 9## is just Address 9## is just

for illustration.for illustration.Real address may Real address may

have 64 bitshave 64 bits

Pointer Variable

Let’s assign a value to i

Q: How can we get the address?

4242900900

904904

908908

912912

916916

……

int i;

i = 42;

ii

The assignment put The assignment put number 42 in the cell. The number 42 in the cell. The memory address of the 1memory address of the 1stst byte is the byte is the address of the address of the

variablevariable i i

– – the the pointerpointer to i to i

Pointer Variable

First let’s have a look at local variables

Q: Where can we store &i?

4242900900

904904

908908

912912

916916

……

int i;

i = 42;

cout << &i;

ii

& (ampersand) operator& (ampersand) operator- “ “address of address of ” ” operatoroperator

- &i is 900 !&i is 900 !

-Note: two meanings of &Note: two meanings of &

A Pointer Variable

A pointer variable can store a memory address in this case to an int

Q: How can we point i_ptr to i?

4242

??

900900

904904

908908

912912

916916

……

int i=42;

int *i_ptr;

ii

i_ptri_ptr

1.1. the type of the data the type of the data that the pointer points that the pointer points

to: intto: int2.2. an asterisk (*)an asterisk (*)

3.3. the name of the newly the name of the newly declared pointer: i_ptrdeclared pointer: i_ptr

Pointer Variable

Assign the address of i to i_ptr

4242

??

900900

904904

908908

912912

916916

……

int i=42;

int *i_ptr;

i_ptr = &i;

ii

i_ptri_ptr

What are the results ofWhat are the results of- cout << i; cout << i;

- cout << i_ptr;cout << i_ptr;- cout << &i_ptr;cout << &i_ptr;

Pointer Variable

The i_ptr holds the address of an integer, not the integer itself

4242

900900

900900

904904

908908

912912

916916

……

int i=42;

int *i_ptr;

i_ptr = &i;

ii

i_ptri_ptr

Two ways to refer to iTwo ways to refer to i- cout << i; cout << i;

- cout << *i_ptr;cout << *i_ptr; - - dereferencing operatordereferencing operator * *

Use of & and * in C/C++

When is & used?

When is * used?

& "address (reference) operator" which gives or produces the memory address of a data variable

* “dereferencing operator" which provides the contents in the memory location specified by a pointer

&expr Evaluates to the address of the location expr evaluates to

*expr Evaluates to the value stored inthe address expr evaluates to

Address (reference) Operator

Operator of address or dereference (&)

– It is used as a variable prefix and can be translated as "address of“

– &variable1 can be read as "address of variable1"

Example:

c = 13;

b = &c; // b = 1ef

a = *b; // a = 13

1efb:

13c(1ef): 13

a:

Dereference Operator

Using a pointer we can directly access the value stored in the variable pointed by it

– precede the pointer identifier with the dereference operator (*)

– that can be literally translated to "value pointed by".

Example:

a = *b;

– a is equal to value pointed by b. 1efb:

131ef: 13

a:

Concept of Address and PointersMemory can be

conceptualized as a linear set of data locations.

Variables reference the contents of a locations

Pointers have a value of the address of a given location

Contents1

Contents11

Contents16

ADDR1ADDR2ADDR3ADDR4ADDR5ADDR6

***

ADDR11

**

ADDR16

Terminology – How to make a pointer in C/C++

Declaring a variable

int num = 5;

Declaring a pointer

int *nptr = 0;

Assigning an address to a pointer

nptr = &num;

Dereferencing a pointer

printf("%d",*nptr);

Declaring Multiple Pointers

How to declare two pointers in a line

char *c1_ptr, *c2_ptr;

– instead of

char* c1_ptr, c2_ptr;

TIP: naming convention: for clarity, use _ptr or cursor for pointer variables

Assignment Operators with Pointers

p2 = p1

int i = 42;

int *p1, *p2;

p1 = &i;

p2 = p1;

4242 ii900900

address value name address value name

??904904 ??908908

Both p1 and p2 point to the same integerBoth p1 and p2 point to the same integer

900900 p1p1904904 900900 p2p2

4242

??

??

900900

904904

908908

912912

916916

……

ii

p1p1

p2p2

900900

900900

Assignment Operators with Pointers

*p2 = *p1

int i = 42;

int *p1, *p2;

p1 = &i;

*p2 = *p1;

4242 ii900900

address value name address value name

??904904 ?? p2p2908908

p2 doesn’t point to anywhere, so p2 doesn’t point to anywhere, so assigning value to *p2 will cause a assigning value to *p2 will cause a

running time error!running time error!

900900 p1p1904904

4242

??

??

900900

904904

908908

912912

916916

……

ii

p1p1

p2p2

900900

XX

POINTERSExamples of pointer declarations:

FILE *fptr;

int *a;

float *b;

char *c;

The asterisk, when used as above in the declaration, tells the compiler that the variable is to be a pointer, and the type of data that the pointer points to, but NOT the name of the variable pointed to.

An Example

Lets look at some code

POINTERS

Consider the statements:

#include <stdio.h>

int main ( )

{

FILE *fptr1 , *fptr2 ; /* Declare two file pointers */

int *aptr ; /* Declare a pointer to an int */

float *bptr ; /* Declare a pointer to a float */

int a ; /* Declare an int variable */

float b ; /* Declare a float variable */

POINTERS

/* Then consider the statements: */

aptr = &a ;

bptr = &b ;

fptr2 = fopen ( "my_out_file.dat" , "w" ) ;

fptr1 = fopen ( "my_in_file.dat" , "r" ) ;

if ( fptr1 != NULL )

{

fscanf ( fptr1, "%d%f" , aptr , bptr ) ;

POINTERS

fprintf ( fptr2, "%d %d\n" , aptr , bptr ) ;

fprintf ( fptr2, "%d %f\n" , *aptr , *bptr ) ;

fprintf ( fptr2, "%d %f\n" , a , b ) ;

fprintf ( fptr2, "%d %d\n" , &a , &b ) ;

return 0 ;

}

Assuming that the above is part of a program that runs without error and the input file does open, what would be printed to the file

By the first fprintf? By the second fprintf?

By the third fprintf? By the fourth fprintf?

3 92.66

my_in_file.dat

POINTERS

fprintf ( fptr2, "%d %d\n" , aptr , bptr ) ;

fprintf ( fptr2, "%d %f\n" , *aptr , *bptr ) ;

fprintf ( fptr2, "%d %f\n" , a , b ) ;

fprintf ( fptr2, "%d %d\n" , &a , &b ) ;

return 0 ;

}

Assuming that the above is part of a program that runs without error and the input file does open, what would be printed to the file

By the first fprintf? By the second fprintf?

By the third fprintf? By the fourth fprintf?

3 92.66

my_in_file.dat

Address_a Address_b392.663 92.66Address_a Address_b

my_out_file.dat

Arrays and Pointers

Arrays and Pointers

The name of an array is the pointer to the address containing the first element in the array.

Let’s look at how arrays and pointers interact

27

Arrays and Pointers

int scores[50];

int * p = scores;

*p = 99;

cout << scores[0]; // "99"

p++; // ok

scores++; // error: scores is const

An array name is assignment-compatible with a pointer to the array's first element. In the following example, *p refers to scores[0].

Traversing an Array

int scores[50];

int * p = scores;

for( int i = 0; i < 50; i++)

{

cout << *p << endl;

p++; // increment the pointer

}

C and C++ programmers often use pointers to traverse arrays. At one time, such code ran more efficiently, but recent optimizing compilers make array subscripts just as efficient.

Array Example

char s[6];s[0] = ‘h’;s[1] = ‘e’;s[2]= ‘l’;s[3] = ‘l’;s[4] = ‘o’;s[5] = ‘\0’;

printf (“s: %s\n”, s);

s: hello

expr1[expr2] in C is just syntactic sugar for*(expr1 + expr2)

Array Example 2 – access via pointers

char s[6];*s = ‘h’;

*(s + 1) = ‘e’;2[s] = ‘l’;3[s] = ‘l’;

*(s + 4) = ‘o’;5[s] = ‘\0’;

printf (“s: %s\n”, s);s: hello

expr1[expr2] in C is just syntactic sugar for*(expr1 + expr2)

Multidimensional Arrays

Declaring

int myIntArray2D[20][30];

Orint** myIntArray2D;

myIntArray2D = new int*[10];

for (int i=0; i<10; i++)

myIntArray2D[i] = new int[10];

Accessing an element

int x = myIntArray2D[2][6]; // row 3, col 7

Destroying 2D array

for (int i=0; i<10; i++)

delete [] myIntArray2D[i];

delete [] myIntArray2D;

NOTE: More dimensions -> more loops!

MultiDemensional Array concept via 1D Array

A solution: use single dimension array instead:

int* myIntArray2D = new int[100];

int x = myIntArray2D[2*10 + 6]; // row 3, col 7

• Possible advantage:

Can be faster access because of simplified memory structure

Functions and Pointers

Pointers and Functions

Pointers can be used to pass addresses of variables to functions, thus allowing the called function to alter the values stored there.

Pointers and Functions

If instead of passing the values of the variables to the called function, we pass their addresses, so that the called function can change the values stored in the calling routine. This is known as "call by reference" since we are referencing the variables.

The following shows the swap function modified from a "call by value" to a "call by reference". Note that the values are now actually swapped when the control is returned to main function.

Pointers with Functions (example)

#include <stdio.h>

void swap ( int *a, int *b ) ;

int main ( )

{

int a = 5, b = 6;

printf("a=%d b=%d\n",a,b) ;

swap (&a, &b) ;

printf("a=%d b=%d\n",a,b) ;

return 0 ;

}

void swap( int *a, int *b )

{

int temp;

temp= *a; *a= *b; *b = temp ;

printf ("a=%d b=%d\n", *a, *b);

}

Results:

a=5 b=6

a=6 b=5

a=6 b=5

Function Returning an Address

Student * MakeStudent()

{

Student * pS = new Student;

return pS;

}

A function can return the address of an object that was created on the heap. In this example, the function's return type is pointer to Student.

(more)

Receiving a Pointer

Student * pS;

pS = MakeStudent();

// now pS points to a Student

(continued)...

The caller of the function can receive the address and store it in a pointer variable. As long as the pointer remains active, the Student object is accessible.

Pointers and Classes

41

Pointers in Classes

class Student {

public:

Student();

~Student();

private:

string * courses; // array of course names

int count; // number of courses

};

// more...

Pointers are effective when encapsulated in classes, because you can control the pointers' lifetimes.

Pointers in Classes

Student::Student()

{

courses = new string[50];

count = 0;

}

Student::~Student()

{

delete [] courses;

}

The constructor creates the array, and the destructor deletes it. Very little can go wrong,...

STL – Collections

• i.e. vector - Automatic memory management when adding and deleting elements

#include <vector>

void main() {

std::vector<int> intList;

intList.push_back(10);

intList.push_back(12);

std::cout << intList[1] << std::endl;

intList.clear();

}

More Pointer Manipulation

Assigning Pointers to Pointers

Must be of the same type

If not, must use a cast operator

Exception is type void

– Generic pointer

– Can be assigned to any pointer type

– Any pointer type can be assigned to it

– Cannot be dereferenced (must cast it first)

Assigning Pointers to Pointersint num = 1234567890; /*0x499602D2*/

char ch = 'A';

int *iptr = &num;

char *cptr = &ch;

iptr = (int *)cptr;

/*cast char pointer to integer pointer*/

printf("*iptr=%c\n",*iptr);

/* *iptr=A (no data lost)*/

iptr = &num;

cptr = (char *)iptr;

/*cast integer pointer to char pointer*/

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

/* *cptr=-46 (loss of data)*/

/*0x499602D2 => D2 => 1101 0010 => -46*/

We can also have pointers to pointers:

Pointers to pointers (different than previous slide

which was about assigning a pointer to another pointer)

int number= 5;int *ptrtonumber;int **ptrtoptrtonumber;ptrtonumber= &number;*ptrtoptrtonumber= &ptrtonumber;*(*ptrtoptrtonumber)= 6;

5

ptrtonumber

ptrtoptrtonumber

number

Generic Pointer - void *int num = 1234567890;

char ch = 'A';

int *iptr = &num;

char *cptr = &ch;

void *vptr = NULL;

vptr = iptr;

printf(“*vptr=%d\n",*((int *)vptr));

/* *vptr=1234567890 */

/* cast void to int pointer*/

vptr = cptr;

printf(“*vptr=%c\n",*((char *)vptr));

/* *vptr=A */

/* cast void to a char pointer*/

Arithmetic and Logical Operations on Pointers

A pointer may be incremented or decremented

An integer may be added to or subtracted from a pointer.

Pointer variables may be subtracted from one another.

Pointer variables can be used in comparisons, but usually only in a comparison to NULL.

Arithmetic Operations on Pointers

When an integer is added to or subtracted from a pointer, the new pointer value is changed by the integer times the number of bytes in the data variable the pointer is pointing to.

For example, if the pointer valptr contains the address of a double precision variable and that address is 234567870, then the statement:

valptr = valptr + 2;

would change valptr to 234567886

Problems with Pointers(part 1)

52

Memory leaksIf we allocate memory but don't free it this

is a "memory leak"void my_function (void){ int *a; a= malloc(100*sizeof(int)); /* Do something with a*/ /* Oops – forgot to free a */}

Every time we call this function it "steals" 100 ints worthof memory. As we call this function more the computersmemory will fill up.

Rogue pointers

Rogue pointers are pointers to unassigned memory. If we try to

access rogue pointers we will be writing to unassigned memory

int *calc_array (void){ int *a; int b[100]; /* Calculate stuff to go in b */ a= b; /* Make a point to the start of b*/ return a; /* Ooops – this isn't good */}

Dangling Pointers

double * pD = new double;

*pD = 3.523;

.

.

delete pD; // pD is dangling...

.

.

*pD = 4.2; // error!

A dangling pointer is created when you delete its storage and then try to use the pointer. It no longer points to valid storage and may corrupt the program's data.

Avoid Dangling Pointers

delete pD;

pD = NULL;

.

.

if( pD != NULL ) // check it first...

*pD = 4.2;

To avoid using a dangling pointer, assign NULL to a pointer immediately after it is deleted.

And, of course, check for NULL before using the pointer.

Another possible problem with Pointers

class Student {

public:

Student();

~Student();

private:

string * courses; // array of course names

int count; // number of courses

};

// more...

When you try to copy a Class that has a pointer for a variable. RECALL ----

Lets make an instance of our class &copy it

Student X;

Student Y(X); // construct a copy

X.AddCourse("cop 3337");

cout << Y.GetCourse(0); // "cop 3337"

...except when making a copy of a Student object. The default copy constructor used by C++ leads to problems. In the following example, a course assigned to student X AFTER THE COPY ends up in the list of courses for student Y.

Pointers in Classes

Student::Student(const Student & S2)

{

count = S2.count;

courses = new string[count];

for(int i = 0; i < count; i++)

courses[i] = S2.courses[i];

}

To prevent this sort of problem, we create a copy constructor that performs a so-called deep copy of the array from one student to another.

Pointers in Classes

Student & Student::operator =(const Student & S2)

{

delete [] courses; // delete existing array

count = S2.count;

for(int i = 0; i < count; i++)

courses[i] = S2.courses[i];

return *this;

}

For the same reason, we have to overload the assignment operator.

C++ Containers in Classes

class Student {

public:

Student();

private:

vector<string> courses;

};

When you use Standard C++ containers such as lists and vectors in classes, there is no problem with the default copy constructor in C++. All containers are experts at allocating and copying themselves.

top related