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 studentsint sumOfStudentScores( int arr[], int n );// function prototypeint main() { int students[ArraySize] = { 55, 60, 60, 20, 30, 99, 100, 10 }; int sum = sumOfStudentScores( students, ArraySize );// calculate total scorecout << "Total score of students: " << sum << "\n"; return 0; }// function that returns the sum of an integer arrayint 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 charint 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 arraychar* wail = "ululate";// wail points to stringint 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 demonstratesif ( *str == ch )// a standard way to process the characterscount++;// in a stringstr++;// 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); // prototypeint 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 memoryps = buildStr( '+', 20);// reuse pointercout << ps << "-Done-" << ps << "\n"; delete[] ps;// free memoryreturn 0; } char * buildStr(char c, int n) { char * pstr = new char[ n + 1 ]; pstr[n] = '\0';// terminate stringwhile ( n-- > 0) pstr[n] = c;// fill rest of stringreturn 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 minday1.mins = 45; travelTime day2 = { 4, 55 };// 4 hrs, 55 mintravelTime trip = sumOfTimes( day1, day2 ); cout << "Two-day total: "; showTime( trip ); travelTime day3 = { 4, 32 };// 4 hrs, 32 mincout << "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