Supposing we had a class of students, and all of them took a test. Now you want to use an
array (an int
array ) to keep track of the score each student achieved. ( Each
array index corresponds to a student, and the value of the element corresponds to the score
each student achieved. ) Now supposing we wanted to find out the total class score, we can use
a loop to add all the array elements. But adding array elements is such a common task that it
makes sense to design a function, with the array of student scores passed into it,
to do just that. There are two ways in which we can write this function.
The first way is to write the argument array as int arr[]
.
Its shown in red
below.
int sumOfStudentScores(int arr[]
, int n )// where arr = array name, n = size
{ int total = 0; for ( int i=0; i<n; i++ ) total += arr[i]; return total; }
And the complete program looks like this:
// SumArrayOne.cpp -- Showing one way of passing an array into a function, // to calculate the sum of the scores of a class of students
#include <iostream> using namespace std; const int ArraySize = 8;// number of students
int sumOfStudentScores( int arr[], int n );// function prototype
int main() { int students[ArraySize] = { 55, 60, 60, 20, 30, 99, 100, 10 }; int sum = sumOfStudentScores( students, ArraySize );// calculate total score
cout << "Total score of students: " << sum << "\n"; return 0; }// function that returns the sum of an integer array
int sumOfStudentScores(int arr[]
, int n )// where arr = array name, n = size
{ int total = 0; for ( int i=0; i<n; i++ ) total += arr[i]; return total; }
And the output will look like this:
Total score of students: 434
There is a second way to pass an array into a function. It is written like this:
int sumOfStudentScores(Notice thatint * arr
, int n )// where arr = array name, n = size
{ int total = 0; for ( int i=0; i<n; i++ ) total += arr[i]; return total; }
int * arr
has replaced int array[]
in the previous
function heading in the first method. If you replace the SumArrayOne
program with
this version, it'll still work. The next part explains why using either int * arr
or int array[]
in a function heading works.
The truth is both headings are being passed a pointer. The key is that C++ ( and C ) in
most contexts treats the name of an array as if it were a pointer.
C++ interprets an array name as the address of its first element.
For example, if we had an array of robots
...
robots == &robots[0] //array name is address of first element
Notice that the SumArrayOne
program above makes this function call: int sum = sumOfStudentScores( students, ArraySize );
students
is being passed into the function, and students
is
actually the address of the first element, a pointer is actually being passed into the
function.
The truth is, to pass an array into a function, the address of its first element( its name, in other words)
is used. Hence, using int * arr
is correct.
Then why does using int arr[]
work too?
This is because in C++ the notations int * arr
and int arr[]
have the same
meaning when ( and only when ) used in a function heading
or function prototype.
In fact, you could use a function prototype with int * arr
and a function definition
with int arr[]
in the above program, and it'll still work! The same thing goes
if you use a function prototype with int arr[]
and a function definition
with int * arr
.
A summary:
typeName
arr[]
;typeName
* arr
;
arr
is a pointer to typeName
. In both cases
you can use arr
as if it were an array name in order to access elements:
arr[i]
.
const
int age = 39; const int * pt = &age;
pt
points to a const int
.
pt
to change that value. In other words,
the value *pt
is const
and cannot be modified.
age
directly to change its value, but you
can't change the value indirectly via the pt
pointer:
*pt = 20;// INVALID because pt points to a const int
*pt += 1;// INVALID because pt points to a const int
cin >> *pt;// INVALID for the same reason
age = 20;// VALID because age is not declared to be constant
int age = 39; const int * pt = &age;only prevent you from changing the value to which
pt
points,
which is 39. It doesn't prevent you from changing the value of pt
itself. That is, you can assign a new address to pt
:
int sage = 80;
pt = &sage; // a const pointer to int
But you still can't use pt
to change the value to which it points(now 80).
const
variable to a pointer-to-const
const
variable to a
pointer-to-const
. For example:
const float gEarth = 9.80;
const float * pe = &gEarth //VALID
gEarth
or
pe
to change the value 9.80.
const
variable to a regular pointer
const
variable to a regular pointer. For example:
const float gMoon = 1.63;
float * pm = &gMoon //INVALID
const int months[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; int sum( int arr[], int n);// should have been const int arr[]
... int j = sum( months, 12);// not allowed!
const
When You Can
const
allows a function to process both const
and non-const
actual arguments, whereas a function omitting
const
in the prototype can accept only non-const
data.
const
to make it impossible to change the value of the
pointer itself.
int * const finger = &sloth; // a const pointer to int
const
pointer to a const
object
const
pointer to a const
object:
double trouble = 2.0E30; const double * const stick = &trouble;Here
stick
can point only to trouble
, and stick
cannot be used to change the value of trouble
. In short, both
stick
and *stick
are const
.
If you want to pass a string as an argument to a function, you'll have three choices for representing the string:
char horses[20] = "galloping";
function("neighing")
char * str = "trotting"
All three choices are actually type pointer-to-char ( char *
).
You can use all three as arguments to string-processing functions:
int n1 = strlen(horses);You're really passing the address of the first character in the string. This implies that a string function prototype should use type// horses is &horses[0]
int n2 = strlen(str);// pointer to char
int n3 = strlen("neighing");// address of first character string
char *
as
the type for the formal parameter representing a string.
// stringfun.cpp -- functions with a string argument #includeOUTPUT:using namespace std; int charactersInString( const char * str, char ch ); int main() { char mmm[15] = "minimum"; // string in an array
char* wail = "ululate";// wail points to string
int ms = charactersInString( mmm, 'm' ); int us = charactersInString( wail, 'u'); cout << ms << " m characters in " << mmm << "\n"; cout << us << " u characters in " << wail << "\n"; return 0; } // this function counts the number of ch characters // in the string str int charactersInString( const char* str, char ch ) { int count = 0; while( *str )// quit when *str is '\0'
{// This while loop actually demonstrates
if ( *str == ch )// a standard way to process the characters
count++;// in a string
str++;// move pointer to next character
} return count; }
3 m characters in minimum 2 u characters in ululate
A function can't return a string. However it can return the address of a string.
// strgback.cpp -- a function returning a pointer to char #includeOutput:using namespace std; char * buildStr( char c, int n); // prototype
int main() { int times; char ch; cout << "Enter a character: "; cin >> ch; cout << "Enter an integer: "; cin >> times; char* ps = buildStr( ch, times ); cout << ps << "\n"; delete [] ps;// free memory
ps = buildStr( '+', 20);// reuse pointer
cout << ps << "-Done-" << ps << "\n"; delete[] ps;// free memory
return 0; } char * buildStr(char c, int n) { char * pstr = new char[ n + 1 ]; pstr[n] = '\0';// terminate string
while ( n-- > 0) pstr[n] = c;// fill rest of string
return pstr; }
Enter a character: 7 Enter an integer: 46 7777777777777777777777777777777777777777777777 ++++++++++++++++++++-Done-++++++++++++++++++++Note that the variable
pstr
is local to the buildStr
function, so when that function terminates, the memory used for pstr
(but not for the string) is freed. But because the function returns the value of
pstr
, the program is able to access the new string through the
ps
pointer in main()
.
Although structure variables resemble arrays in that both can hold several data items, structure variables behave like basic, single valued variables when it comes to functions. You can pass structures by value, and a function can return a structure.
There are three ways you can use structures with functions:
The first and most direct way is to treat them as you would treat the basic types. Just pass them as arguments and use them, if necessary, to return values. However, the disadvantage is that if the structure is large, the space and effort involved in making a copy of a structure can increase memory requirements and slow the system down.
Initially, C didn't allow the passing of structure by value, so many C programmers passed the address of a structure and then using a pointer to access the structure contents. This also avoids the disadvantage of copying a large structure.
C++ provides a third alternative, called passing by reference, that is not discussed here. Instead we'll see how to use the first and second ways.
The following example shows how to pass and return structures
directly in a function. The structure travelTime
represents time travelled during a journey.
The program has two functions. Function sumOfTimes
adds two travelTime
structures to find the total
time travelled between two journeys. Function
showTime
prints out the total time travelled.
// travel.cpp -- using structures with functions #includeusing namespace std; struct travelTime { int hours; int mins; } day1; const int minPerHour = 60; travelTime sumOfTimes( travelTime t1, travelTime t2 ); void showTime( travelTime t ); int main() { day1.hours = 5; // 5 hrs, 45 min
day1.mins = 45; travelTime day2 = { 4, 55 };// 4 hrs, 55 min
travelTime trip = sumOfTimes( day1, day2 ); cout << "Two-day total: "; showTime( trip ); travelTime day3 = { 4, 32 };// 4 hrs, 32 min
cout << "Three-day total: "; showTime( sumOfTimes( trip, day3) ); return 0; } travelTime sumOfTimes( travelTime t1, travelTime t2 ) { travelTime answer; answer.hours = (t1.hours + t2.hours) + (t1.mins + t2.mins)/minPerHour; answer.mins = (t1.mins + t2.mins)%minPerHour; return answer; } void showTime( travelTime t ) { cout << t.hours << " hours, "; cout << t.mins << " minutes\n"; }
Output:
Two-day total: 10 hours 40 minutes Three-day total: 15 hours 12 minutes
const
modifier.
We modify the above program to use structure addresses:
#includeusing namespace std; struct travelTime { int hours; int mins; }; const int minPerHour = 60; travelTime* sumOfTimes( travelTime* t1, travelTime* t2 ); void showTime( travelTime* t ); int main() { travelTime day1 = { 5, 45 }; travelTime day2 = { 4, 55 }; travelTime* pday1 = &day1; travelTime* trip = sumOfTimes( pday1, &day2 ); cout << "Two-day total: "; showTime( trip ); travelTime day3 = { 4, 32 }; // 4 hrs, 32 min cout << "Three-day total: "; showTime( sumOfTimes( trip, &day3) ); delete trip; return 0; } void showTime( travelTime* t ) { cout << t->hours << " hours "; cout << t->mins << " minutes\n"; } travelTime* sumOfTimes( travelTime* t1, travelTime* t2 ) { travelTime* answer = new travelTime; answer->hours = t1->hours + t2->hours + ( t1->mins + t2->mins )/minPerHour; answer->mins = (t1->mins + t2->mins)%minPerHour; return answer; }
The output is the same:
Output:
Two-day total: 10 hours 40 minutes Three-day total: 15 hours 12 minutes