C++ Pointers and Arrays

Download Report

Transcript C++ Pointers and Arrays

C++ Pointers and Arrays
CSCD 326
Variable Attributes
• Attributes of a “variable”:
– Contents - the value stored in the memory
location(s) used for the variable
– Address - each byte of memory has a unique
address which allows the CPU to access that
memory location
• Access to a named variable’s attributes:
– variable name - a reference to the value of the
variable
• e.g. x = x + 3
– &variable name - a reference to the address at
which the variable is stored
• e.g. &x
7/20/2015
CSCD 326
2
Pointers and Indirect References
• Pointers are variables used to store the
address of another memory location
• Pointers provide indirect access to a value
stored in memory
• Using the address stored in a pointer to
access a value stored in that address is
called dereferencing the pointer
Addresses
7/20/2015
Contents
10A0
2000
2000
5
CSCD 326
Pointer
3
C++ Pointer syntax
• Declaration of a pointer object (variable)
int *Ptr;
– this declares an object or variable called Ptr which
can contain the address of an integer object
• Pointer Assignment
int X = 5;
int Y = 7;
Ptr = &Y; //&Y is the address of Y
7/20/2015
Name
Ptr
X
Address
1000
1004
Y
1008
Contents
1008
5
7
CSCD 326
7
Ptr
Y
4
Dereferencing Operator
• Allows access to the value of the data whose
address is contained in a pointer for use in an
expression or assignment
– *Ptr evaluates to 7
– *Ptr = 15; -- assigns value 15 to the integer
whose address is contained in Ptr
Name
Ptr
X
Address
1000
1004
Y
1008
Contents
1008
5
15
15
Ptr
Y
• * is the opposite of & so: *(&X) is the same
as X
7/20/2015
CSCD 326
5
Pointer Example
#include <iostream.h>
#include <stdlib.h>
void
main()
{
int *ptr, i = 15;
// assignment of addresses to a pointer
variable
ptr = NULL;
ptr = (int *)0xfffe;
ptr = &i;
cout << "address of i: " << ptr << "\n";
cout << "contents of i: " << *ptr << "\n";
}
7/20/2015
CSCD 326
6
Pointer Example Output
address of i: 0x0012FF78
contents of i: 15
Press any key to continue
7/20/2015
CSCD 326
7
Pointer expressions
#include <stdlib.h>
#include <iostream.h>
void
main()
{
int i = 3, j = 5, k;
int *p = &i, *q = &j, *r;
*(r = &k) = *p * *q;
cout << "r: " << *r;
}
Output:
r: 15
7/20/2015
CSCD 326
8
Pointer expressions memory
i
j
k
p
q
r
7/20/2015
3
5
&i
&j
CSCD 326
9
Arrays and Pointers
int SmallArray[] = {1,3,5,7,9};
int *Iptr;
Iptr = SmallArray;
Name Address
SmallArray[0] 1000
SmallArray
1000
7/20/2015
1
SmallArray[1] 1004
SmallArray[2] 1008
SmallArray[3] 100C
SmallArray[4] 1010
3
5
Iptr
1000
CSCD 326
1014
7
9
10
Array address calculations
Name Address
SmallArray[0] 1000
SmallArray
1000
1
SmallArray[1] 1004
SmallArray[2] 1008
SmallArray[3] 100C
SmallArray[4] 1010
3
5
Iptr
1000
1014
7
9
• To determine the address of SmallArray[I]:
– compiler calculates - SmallArray + (I * 4)
– or 1000 + (I * 4)
7/20/2015
CSCD 326
11
Pointer Arithmetic
• Pointer arithmetic can be used in the same way
as array notation to access array members
• Recall from previous example:
–
–
–
–
Iptr = SmallArray;
the members of SmallArray can now be accessed as:
*(Iptr +1)
*(Iptr +2) etc.
or as *(SmallArray + 1) *(SmallArray + 2)
• Since both Iptr and SmallArray are pointers,
these expressions are pointer arithmetic
• *(Iptr + I) is evaluated as:
– Iptr + (I * sizeof(*Iptr)) or Iptr + (I * 4) in this case
• So - *(SmallArray + I) is the same as:
SmallArray[I]
7/20/2015
CSCD 326
12
Pointer Operators and precedence
• Shown below is the top of the C++ precedence
chart:
Category
Operator
Associativity Overloadable
Scoping
Postfix
Prefix
::(unary) ::(class)
() [] -> . ++ -sizeof * & ! ~ + ++ -- new delete
L to R
L to R
R to L
No
Yes, except .
Yes, except
sizeof
• consider the following expressions:
– int X[5], *Ptr = X;
– *Ptr++
++*Ptr
++X[0]
– ++X[2]
7/20/2015
CSCD 326
Ptr++[0]
13
Strings
• C++ has its own string type and can be
accessed via the standard template library
(STL).
• More specifically, you #include <string> and
follow it with the statement: using namespace
std;.
• The using namespace std; further requires
that all other C++ header files are included
without a .h.
• Furthermore, old C style libraries are included
by preceding the library name with a c (once
again the .h is left off)
• C type strings are still supported and we will
use them- you may CSCD
use326your own user7/20/2015
14
defined string classes in programs
C type Strings
• C strings are arrays of characters in which the
end of the string is indicated by a char
containing 0 (character constant ‘\0’)
• the string array must be large enough to
accommodate the extra terminal character
• C strings are of type char * or const char *
char astr[7];
int i;
astr[0]
astr[1]
astr[2]
astr[3]
astr[4]
astr[5]
astr[6]
7/20/2015
=
=
=
=
=
=
=
‘s’;
‘t’;
‘r’;
‘i’;
‘n’;
‘g’;
‘\0’;
OR
*(astr) = ‘s’;
*(astr + 1) = ‘t’;
*(astr + 2) = ‘r’;
*(astr + 3) = ‘i’;
*(astr + 4) = ‘n’;
*(astr + 5) = ‘g’;
*(astr + 6) = ‘\0’
CSCD 326
15
C String Functions
#include <string.h>
char * strcpy(char *, const char *);
char * strcat(char *, const char *);
int strcmp(const char *, const char *);
size_t strlen(const char *);
• strcpy- copies characters from its second
parameter to its first - returns the address of
the string copied to
• strcat - adds characters in second parameter
to the end of the first
7/20/2015
CSCD 326
16
C String Functions (cont)
• strcmp- compares characters from second
argument to those from first - return value
indicates either equality or which string is
larger
– return value:
• <0 - string1(first arg) less than string2
• 0 - the strings are identical
• > 0 - string1 is greater than string2
• strlen - counts characters in its argument - up
to but NOT including the terminal 0 and
returns this count
7/20/2015
CSCD 326
17
String Constants
• Specified with quotes -- “string”
• Placed into memory allocated by the compiler
with the nul terminator added
– thus “string” occupies 7 bytes of memory
• Uses of string constants:
– can be used anywhere both a string and a constant
can - e.g. as the second (but not first) parameter to
strcpy
– as array initializers: char str[10] = “string”; here
characters are copied from the constant to the array
– assignment to pointers: char *mystr = “string”;
here the address of the memory location of the
constant is assigned to mystr
7/20/2015
CSCD 326
18
Pointer Hopping
#include <stdio.h>
void
void
void
void
strcpy1(char
strcpy2(char
strcpy3(char
strcpy4(char
s[],char t[]);
*s,char *t);
*s,char *t);
*s,char *t);
void main(void)
{
char s1[50], *s2;
s2 = "this is a literal string";
printf("s1: %s\ns2: %s\n",s1,s2);
//cout << “s1:” << s1 << “\ns2: “ << s2 << “\n”;
strcpy1(s1,s2);
printf("s1: %s\ns2: %s\n",s1,s2);
}
7/20/2015
CSCD 326
19
Pointer Hopping (2)
void
strcpy1(char s[],char t[])
{
int i;
i = 0;
while((s[i] = t[i]) != '\0')
{
s++;
t++;
}
}
void
strcpy2(char *s, char *t)
{
while((*s = *t) != '\0')
{
s++;
t++;
}
}
7/20/2015
CSCD 326
20
Pointer Hopping (3)
void
strcpy3(char *s, char *t)
{
while((*s++ = *t++) != '\0')
;
}
void
strcpy4(char *s, char *t)
{
while(*s++ = *t++)
;
}
7/20/2015
CSCD 326
21
Dynamic Memory Allocation
• The new[ ] and delete [] operators can be used
to allocate variable sized blocks of memory for
classes, structures and arrays while a program
is running
• static allocation (at the start of a program or
function) often requires too much memory to be
allocated and wasted
• example of dynamic array allocation
char *str;
str = new char[5]; // allocates 5 bytes
Assert(str);
strcpy(str, “test”);
delete [ ] str;
str = NULL;
7/20/2015
CSCD 326
22
Memory Leaks
• Happen any time memory allocated with new
is not returned with delete
• Scope related example:
void
F( int i )
{
int A1[10];
int *A2 = new int [10];
…
G(A1);
G(A2);
}
• When scope is exited memory from automatic
array A1 is freed but not memory pointed by
A2 - 10 ints leak - delete [] A2 would fix
7/20/2015
CSCD 326
23
Extending Arrays
• The new and delete operators can be used to
reallocate arrays during program execution to
make them larger
• the following program reads an infinite
number of integers - until 0 is read - and
stores them in an extensible array
7/20/2015
CSCD 326
24
#include <iostream>
#include <cstdlib>
using namespace std;
// Read an unlimited number of ints.
// Return a pointer to the data, and set ItemsRead.
int *
GetInts( int & ItemsRead )
{
int ArraySize = 0;
int InputVal;
int *Array = 0;
// Initialize to NULL pointer
}
ItemsRead = 0;
cout << "Enter any number of integers: ";
while( cin >> InputVal )
{
if( ItemsRead == ArraySize )
{
// Array Doubling Code
int *Original = Array;
Array = new int[ ArraySize * 2 + 1 ];
for( int i = 0; i < ArraySize; i++ )
Array[ i ] = Original[ i ];
delete [ ] Original; // Safe if Original is NULL
ArraySize = ArraySize * 2 + 1;
}
Array[ ItemsRead++ ] = InputVal;
}
return Array;
7/20/2015
CSCD 326
25
#include <new> //allows us to handle memory exceptions
using namespace std;
main( )
{
int *Array;
int NumItems;
// The actual code
try
{
Array = GetInts( NumItems );
for( int i = 0; i < NumItems; i++ )
cout << Array[ i ] << '\n';
}
}
catch( bad_alloc exception )
{
cerr << "Out of memory!" << endl;
exit( 1 );
}
return 0;
7/20/2015
CSCD 326
26
Memory Exhaustion
• A mechanism is needed to report when
dynamically allocated memory (heap) is
exhausted
• C mechanism - new returns NULL pointer
• C++ exception mechanism
– VC++ 6.0 – must #include <new>, which allows new to
throw a C++ exception of type bad_alloc in the event
of an allocation failure
• in your code, you can use try/catch exception
handling constructs to detect and handle bad_alloc
exceptions
7/20/2015
CSCD 326
27
Reference Variables (& parameters)
• A reference type is a pointer constant which is
always dereferenced implicitly
• example:
int LongVariableName = 0;
int & Cnt = LongVariableName;
Cnt += 3;
• reference variables must be initialized - they
are constants
• reference variable names are implicitly
dereferenced unlike all other pointer types
• example of reference types as parameters:
7/20/2015
CSCD 326
28
Swap Functions
#include <iostream.h>
void SwapWrong( int A, int B );
void SwapPtr( int *A, int *B );
void SwapRef( int & A, int & B );
// Simple program to test various Swap routines
main( )
{
int X = 5;
int Y = 7;
SwapWrong( X, Y );
cout << "X=" << X << " Y=" << Y << '\n';
SwapPtr( &X, &Y );
cout << "X=" << X << " Y=" << Y << '\n';
SwapRef( X, Y );
cout << "X=" << X << " Y=" << Y << '\n';
}
return 0;
7/20/2015
CSCD 326
29
// Does not work
void
SwapWrong( int A, int B )
{
int Tmp = A;
A = B;
B = Tmp;
}
// C Style -- using pointers
void
SwapPtr( int *A, int *B )
{
int Tmp = *A;
*A = *B;
*B = Tmp;
}
// C++ style -- using references
void
SwapRef( int & A, int & B )
{
int Tmp = A;
A = B;
B = Tmp;
}
7/20/2015
CSCD 326
30
2D Arrays and Pointers (1)
#include <stdio.h>
void main(void)
{
int array[3][4],i,j,val=0;
for(i=0;i < 3; i++)
for(j=0; j < 4; j++)
{
array[i][j] = val++;
printf("array[%d][%d]: %d\n",i,j,array[i][j]);
}
printf("array: %x\n",array);
printf("array[0]: %x\n",array[0]);
printf("array[1]: %x\n",array[1]);
printf("*array[1]: %d\n",*array[1]);
printf("*array+1: %x\n",*array+1);
printf("*array[2]: %d\n",*array[2]);
printf("*array+2: %x\n",*array+2);
printf("**array+2: %d\n",**array+2);
printf("*(*(array+1)+2): %d\n",*(*(array+1)+2));
printf("*(array+1)+2: %x\n",*(array+1)+2);
printf("*array[3]: %x\n",*array[3]);
}
7/20/2015
CSCD 326
31
2D Arrays and Pointers (2)
array[0][0]:
array[0][1]:
array[0][2]:
array[0][3]:
array[1][0]:
array[1][1]:
array[1][2]:
array[1][3]:
array[2][0]:
array[2][1]:
array[2][2]:
array[2][3]:
7/20/2015
0
1
2
3
4
5
6
7
8
9
10
11
array: effff804
array[0]: effff804
array[1]: effff814
*array[1]: 4
*array+1: effff808
*array[2]: 8
*array+2: effff80c
**array+2: 2
*(*(array+1)+2): 6
*(array+1)+2: effff81c
*array[3]: 0
CSCD 326
32
2D Arrays and Pointers (3)
array: effff804
array[0]:
effff804
array[1]:
effff814
*array[1]: 4
*array+1:
effff808
*array[2]: 8
*array+2:
effff80c
**array+2: 2
*(*(array+1)+2):
6
*(array+1)+2:
effff81c
*array[3]: 0
7/20/2015
array -- effff804 (804)
each row contains 16 bytes
804 808 80c 810
array[0]
0 1 2 3
814 818 81c 820
array[1]
4 5 6 7
824 828 82c 830
array[2] 8 9 10 11
CSCD 326
33
Pointers and Structures
• Structures are an aggregate data type of
different types
struct Student
{
char FirstName[40];
char LastName[40];
int StudentNum;
double GradePointAvg;
}
Student S;
– declares and allocates an entire structure named
S
Student *Sptr = &S;
– declares, allocates and initializes a pointer Sptr
which points at S
7/20/2015
CSCD 326
34
Struct member access through
pointers
• One way to access the members of S through
Sptr is:
(*Sptr).GradePointAvg
• since this is awkward at best, an operator has
been provided which both dereferences and
provides member selection:
Sptr->GradePointAvg
– this has exactly the same meaning as the previous
expression
7/20/2015
CSCD 326
35
Structs as parameters
• Call by value prototype:
void PrintInfo( Student ThisStudent);
– results in a copy being made of the entire actual
parameter
• Call by reference prototype:
void PrintInfo( Student & ThisStudent );
– since only the address of the actual parameter is
passed no copy is made
• Call by constant reference parameter
void PrintInfo( const Student & ThisStudent);
– here no copy is made and no changes can be
made to the actual parameter
7/20/2015
CSCD 326
36
Exogenous vs. Indigenous Data
• The student struct as illustrated before
contains all indigenous data - All data is
contained inside the stuct
• Exogenous data - data allocated outside the
struct but pointed to by an internal pointer
• Example:
struct Student
{
char *FirstName;
char *LastName;
int StudentNum;
double GradePointAvg;
}
Student S;
S.FirstName = new char [40];
S.LastName = new char [40];
7/20/2015
CSCD 326
37
Problems with Exogenous Data
• In the previous example suppose we have:
Student S, T;
– if T has been initialized and had space allocated
for its strings then:
S = T;
– does a member by member copy of T into S which
means they have pointers to the same FirstName
and LastName strings - thus:
delete [] T.FirstName erases the string pointed
to by S.FirstName
• overriding the = operator and copying only
pointers is a shallow copy
• overriding the = operator and copying the
memory holding characters is a deep copy
7/20/2015
CSCD 326
38
Linked List Basics
• Arrays can be thought of as lists of objects
which occupy contiguous memory
• Using structures and pointers a list of objects
which are located in non-contiguous memory
can be built
– the basic structure for such a list is shown below:
struct Node
{
char Element;
Node *next;
}
7/20/2015
Diagram:
Element
CSCD 326
Next
39
Linked List Building
void main()
{
Node *head = NULL, *cur;
char c;
}
for(c = ‘a’; c <= ‘z’; c++)
{
if(!head)
{
head = cur = new Node;
head->Element = c;
}
else
{
cur->Next = new Node;
cur = cur->Next;
cur->Element = c;
}
}
cur->Next = NULL;
7/20/2015
CSCD 326
40