Essential C++ 2_Procedural Programming

2.1 How to Write a Function

    Before a function can be called within our program, it must be declared. A function declaration allows the compiler to verify the correctness of its use � whether there are enough parameters, whether they are of the correct type, and so on. The function declaration specifies the return type, the name, and the parameter list but not the function body. This is called thefunction prototype.

// a declaration of our function 
int fibon_elem( int pos );

    A more reasonable choice is to change our return value to indicate whether fibon_elem() is able to calculate the value:

// revised function prototype 
bool fibon_elem( int pos, int &elem ); 

    A function can return only one value. In this case, the value returned is either true or false based on whether fibon_elem() can calculate the element's value. That leaves us with the problem of returning the element's actual value.In our revised function prototype, we solve that problem by adding a second parameter of type reference to int.     This allows us in effect to have  two values returned from the function.

Here is the final implementation of fibon_elem():

bool fibon_elem( int pos, int &elem ) 
{ 
   // check if invalid position ... 
   if ( pos <= 0 || pos > 1024 ) 
      { elem = 0; return false; } 

   // elem is 1 for positions 1 and 2 
   elem = 1; 
   int n_2 = 1, n_1 = 1; 

   for ( int ix = 3; ix <= pos; ++ix ) 
   { 
         elem = n_2 + n_1; 
         n_2 = n_1; n_1 = elem; 
   } 

   return true; 
} 
The following small program exercises fibon_elem():

#include <iostream> 
using namespace std; 

// forward declaration of fibon_elem() 
// makes function known to compiler ... 
bool fibon_elem( int, int& ); 

int main() 
{ 
   int pos; 
   cout << "Please enter a position: "; 
   cin >> pos; 

   int elem; 
   if ( fibon_elem( pos, elem )) 
        cout << "element # " << pos 
             << " is " << elem << endl; 
   else cout << "Sorry. Could not calculate element # " 
             << pos << endl; 
 } 
    In our example, the declaration of fibon_elem() does not provide names for its two parameters. This is OK. The name of a parameter is necessary only if we need access to the parameter within the function.


2.2 Invoking a Function

    In this section we implement a function to sort a vector of integer values so that we can explore the behavior ofpassing parameters both by reference and by value. The sorting algorithm is a simple bubble sort implemented by two nested for loops. 

void display( vector<int> vec ) 
{ 
   for ( int ix = 0; ix < vec.size(); ++ix ) 
         cout << vec[ix] << ' '; 
   cout << endl; 
} 

void swap( int val1, int val2 )
{ 
   int temp = val1; 
   val1 = val2; 
   val2 = temp; 
}
void bubble_sort( vector<int> vec ) 
{ 
   for ( int ix = 0; ix < vec.size(); ++ix ) 
         for ( int jx = ix+1; jx < vec.size(); ++jx ) 
               if ( vec[ ix ] > vec[ jx ] ) 
                    swap( vec[ix], vec[jx] ); 
} 

int main() 
{ 
   int ia[ 8 ] = { 8, 34, 3, 13, 1, 21, 5, 2 }; 
   vector<int> vec( ia, ia+8 );

   cout << "vector before sort: "; 
   display( vec ); 

   bubble_sort( vec ); 

   cout << "vector after sort:  "; 
   display( vec ); 
} 

    When this program is compiled and executed, the following output is generated, showing that the vector defined within main() is not sorted:

vector before sort: 8 34 3 13 1 21 5 2 
vector after sort:  8 34 3 13 1 21 5 2 
     It explains why even though we swap the values, the change is not reflected in the vector. In effect, the objects passed to  swap() are copied, and there is no relationship between the two pairs of objects.  

    When we invoke a function, a special area of memory is set up on what is called theprogram stack. Within this special area of memory there is space to hold the value of each function parameter. (It also holds the memory associated with each object defined within the function � we call these local objects.) When the function completes, this area of memory is discarded. (We say that it is popped from the program stack.)

    By default, when we pass an object to a function, such as vec[ix], its value is copied to the local definition of the parameter. (This is called pass by value semantics.) There is no connection between the objects manipulated withinswap() and the objects passed to it within bubble_sort(). That is why our program fails.

    For our program to work, we must somehow bind the swap() parameters to the actual objects being passed in. (This is calledpass by reference semantics.) The simplest way of doing this is to declare the parameters as references:

/* 
 * OK: by declaring val1 and val2 as references 
 *     changes to the two parameters within swap() 
 *     are reflected in the objects passed to swap() 
 */ 
void swap( int & val1, int & val2 ) 
{ 
    /* 
     * note that our code within swap() 
     * does not change -- only the relationship 
     * between the parameters of swap() and the 
     * objects passed to swap() changes 
     */ 
    int temp = val1; 
    val1 = val2; 
    val2 = temp; 
} 

    Changing vec to be a reference is the final correction to our program:

void bubble_sort( vector<int> &vec ){ /* ... */ } 

To confirm that, let's recompile and execute:

vector before sort: 8 34 3 13 1 21 5 2 
vector after sort:  1 2 3 5 8 13 21 34 
Pass by Reference Semantics

    A reference serves as an indirect handle to an object. We declare a reference by sandwiching an ampersand (&) between the type's name and the name of the reference:

int ival = 1024;  // an object of type int 
int *pi  = &ival; // a pointer to an object of type int 
int &rval = ival; // a reference to an object of type int

    When we write

int jval = 4096; 
rval = ival; 

    we assign ival, the object rval refers to, the value stored byjval. We do not causerval to now refer tojval. A reference cannot be reassigned to refer to another object. When we write

pi = &rval; 

    we assign pi the address of ival, the objectrval refers to. We do not causepi to point torval. All manipulation of a reference acts on the object the reference refers to. This is also true when the reference is a function parameter.

    When we assign val1 with val2 within swap(),

void swap( int &val1, int &val2 ) 
{ 
    // the actual arguments are modified ... 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值