pointers and memory allocation -l. grewe. objectives why and what are pointers create pointers in...
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 = #
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 = #
char *cptr = &ch;
iptr = (int *)cptr;
/*cast char pointer to integer pointer*/
printf("*iptr=%c\n",*iptr);
/* *iptr=A (no data lost)*/
iptr = #
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 = #
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 © 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.