Reference Data Type-Introduction To Programming-Lecture Notes, Study notes of Computer Programming

A program is a precise sequence of steps to solve a particular problem. This course includes basic programming structure like loops, operator, memory allocation, reference, pointers etc. It teaches how to be a good programmer. This lecture handout is about: Reference, Data, Type, Pointers, Difference, Dangling, Synonym, Integer, Address, Operator, Initialized, Increment, Class, Temporary

Typology: Study notes

2011/2012

Uploaded on 08/06/2012

anchal
anchal 🇮🇳

4.6

(9)

95 documents

1 / 10

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
359
Lecture No. 30
Reading Material
Deitel & Deitel - C++ How to Program Chapter. 3
3.17
Summary
13) Reference data type
14) Example 1
15) Difference Between References and Pointers
16) Dangling References
17) Example 2
Reference data type
Out today’s topic is about references. This is a very important topic from the C++
prospective. Today we will see what is a reference, how can we use them. C++
defines a thing by which we can create an alias or synonym of any data type. That
synonym is called reference. How do we declare a reference? We declare it by using
& operator. Now it is little bit confusing. We have used & as address-of operator and
here we are using it for referencing. We will write as
int &i;
It means that i is a reference to an integer. Keep that statement very clear in your
mind. It is easier to read from right to left. A reference is a synonym. If we want to
give two names to same thing then we use reference. Reference has to be initialized
when it is declared. Suppose if we have an integer as i and we want to give it second
name. We will reference it with j as:
int &j = i;
We declared an integer reference and initialized it. Now j is another name for i. Does
it mean that it creates a new variable? No, its not creating a new variable. Its just a
new name for the variable which already exists. So if we try to manipulate i and j
individually, we will came to know that we have been manipulating the same number.
docsity.com
pf3
pf4
pf5
pf8
pf9
pfa

Partial preview of the text

Download Reference Data Type-Introduction To Programming-Lecture Notes and more Study notes Computer Programming in PDF only on Docsity!

Lecture No. 30

Reading Material

Deitel & Deitel - C++ How to Program Chapter. 3

Summary

  1. Reference data type
  2. Example 1
  3. Difference Between References and Pointers
  4. Dangling References
  5. Example 2

Reference data type

Out today’s topic is about references. This is a very important topic from the C++ prospective. Today we will see what is a reference, how can we use them. C++ defines a thing by which we can create an alias or synonym of any data type. That synonym is called reference. How do we declare a reference? We declare it by using & operator. Now it is little bit confusing. We have used & as address-of operator and here we are using it for referencing. We will write as

i nt &i;

It means that i is a reference to an integer. Keep that statement very clear in your mind. It is easier to read from right to left. A reference is a synonym. If we want to give two names to same thing then we use reference. Reference has to be initialized when it is declared. Suppose if we have an integer as i and we want to give it second name. We will reference it with j as:

int &j = i;

We declared an integer reference and initialized it. Now j is another name for i. Does it mean that it creates a new variable? No, its not creating a new variable. Its just a new name for the variable which already exists. So if we try to manipulate i and j individually, we will came to know that we have been manipulating the same number.

docsity.com

Lets take a look at a very simple example. In the main function we take an int variable i and then we write int &j = i; Now we assign some value (say 123) to i. Now display the value of i using cout. It will show its value as 123. Display the value of j using cout. We will not use & operator to display the value of j. We will only use it at the time of declaration and later we don’t need it. The & is not reference operator rather it acts as reference declarator. The value of j will be same as of i i.e. 123.

int i; int &j = i; i = 123; cout << “\n The value of i = “ << i; cout << “\n The value of j = “ << j;

Now what will happen if we increment i as i++; and print the values of i and j. You will note that the value of i and j both have been incremented. We have only incremented i but j is automatically incremented. The reason is that both are referring to the same location in the memory. j is just another name for i.

What is the benefit of reference and where can we use it? References are synonyms and they are not restricted to int’s, we can have reference of any data type. We can also take reference of a class. We wrote a function to show the use of pointers. That function is used to interchange two numbers. If we have two integers x and y. We want that x should contain the value of y and y should get the value of x. One way of doing this is in the main program i.e.

int x = 10; int y = 20; int tmp; tmp = y; y = x; x = tmp;

The values of both x and y have been interchanged. We can also swap two numbers using a function. Suppose we have a swap function as swap(int x, int y) and we write the above code in it, what will happen? Nothing will be changed in the calling program. The reason is call by value. So when the main function calls the function swap(x, y). The values of x and y will be passed to the swap function. The swap function will get the copies of these variables. The changes made by the swap function have no effect on the original variables. Swap function does interchange the values but that change was local to the swap function. It did not effect anything in the main program. The values of x and y in the main program remains same.

We said that to execute actual swap function we have to call the function by reference. How we did that. We did not send x and y rather we sent the addresses of x and y. We used address operator to get the addresses. In the main function we call swap function as swap(&x, &y); In this case we passed the addresses of two integers. The prototype of the swap function is swap(int, int) which means that swap function is expecting pointers of two integers. Then we swap the values of i and j using the * notations. It works and in the main program, the values are interchanged. This was a clumsy way. We can use reference in this case with lot of ease. Let us see

docsity.com

left. If we think about it, it was a function call. We were doing some work, suddenly we call a function and stop that work and execution went to the function. When the execution of the function came to end, we came back to our calling function and continued with it. Computers do the same work with stack. So when the program comes back from the function it should know the point at which it lefts. We supposed here a word to look up, now consider that it was a paragraph or essay I am going to look up. Now to lookup that essay in other books I have to take the entire paragraph or essay with me to that book. Think about the stack. On the stack, the original condition of the program (state) has saved. Now we put our essay or paragraph on it and then opened the other book and searched the book for this essay. In this way, we want to explain that the thing we passed to the function from the main was itself a huge/large thing (as we resemble it with paragraph or essay). So there was a big overhead in writing that thing out into a temporary space in memory and then picking it up and looking it up.

We can make this process more efficient. The issue is that in this example we do not want to change the paragraph or essay which we are going to look up. We only want to look it up. We want only to use it but don’t want to change its words. Unfortunately the baggage that comes with doing this is that first make a copy of this (essay) then go with this copy and when the work with it ends, leave (through away) the copy and start the original work. This is inefficient.

But if we took the reference of that essay and passed the address of it and went to the function to look it up. There is a danger that comes with the address, that is while looking up that essay I underlined different words and when I came back to original book I saw that these line marks were also there. Thus we passed something by value rather we passed something by reference. By passing the reference, we actually pass the original. Think about it in another way. We go to a library and said the librarian to issue us a book, which we want to take home for study. Suppose, that book is the only one copy available in the library (or in the world). The librarian will not issue the book. Because it is the only copy available in the world. He does not want to issue this original book to someone as someone can marks different lines with a pen and thus can damage the original book. The librarian will do that he will take a photocopy of that book and issue it. Making a photocopy of the book and then take the book is a bothersome work.

Here we don’t want to damage the book. We just want to read it. But can I somehow take the original book? Put it in a special polythene bag and give it to you in such a way that you can read it without damaging it. By doing this we get efficiency but danger is still there. This is actually a call by reference. We have the reference (the original book). If we do something to the original book, the library book will be damaged. Can we somehow prevent this from happening? And also have the efficiency of not having to make a copy.

Now come back to the computer world. Suppose we have a data structure. There is a string of 1000 characters in it. We want to pass that data structure to a function. If we pass it by value which is sake, the original structure will not be affected. We first will copy that string of 1000 characters at some place, which is normally made on the stack. Then the function will be called. The function will take the copy of these 1000 characters and will manipulate it. Then it will give the control back to the caller

docsity.com

program and will destroy that copy of string. For efficiency, we want that instead of making a copy of this string, its reference should be written. We have been doing this with pointers and addresses. So we write there the address and pass it to the function. How we can prevent the side effects? There may be these side effects with references. So be very careful while using references with function calls.

Can we do something to prevent any changes? The way we do it is by using the const key word. When we write the const key word with the reference, it means that it is a reference to some thing but we cannot change it. Now we have an elegant mechanism. We can get the efficiency of call by reference instead of placing a string of 1000 characters on the stack, we just put the address of the string i.e. reference on the stack. In the prototype of the function, it is mentioned that it takes a const. This is a reference that may be to a char, int, double or whatever but it is a const. The function cannot change it. The function gets the address, does its work with it but cannot change the original value. Thus, we can have an efficiency of a call by reference and a safety of a call by value. To implement all this we could have used the key word const with an address operator or a pointer but we can use a reference that is an elegant way. There is no need in the function to dereference a reference by using * etc, they are used as ordinary variable names.

Example 1

Now let us have an example. Here we defined a structure bigone that has a string of 1000 characters. Now we want to call a function by three different ways to manipulate this string. The first way is the call by value, which is a default mechanism, second is the call by reference using pointers and the third way is call by reference using reference variables. We declared the prototypes of these functions. Here we declared three functions. The first function is valfunc which uses a call by value. We simply wrote the value of the structure. The function prototype is as under. void valfunc( bigone v1 ); The second function is ptrfunc in which we used call by reference using pointers. We passed a pointer to the structure to this function. The prototype of it is as follows. void ptrfunc( const bigone *p1 ); The third function is reffunc which uses the way of calling by reference using references. We wrote its prototype as void reffunc( const bigone &r1 ); Note that we wrote & sign with the name of the variable in the prototype of the function, we will not write it in the call of the function. In the main program, we called these function. The call to the valfunc is a simple one we just passed the name of the object of the structure i.e. v1. As the function is called by using the call by value the manipulation in the function will not affect the original value. We wrote it as: valfunc ( bo );

In this call a copy of bo is placed on the stack and the function uses that copy.

Next we called the function ptrfunc. We passed the address of the structure to ptrfunc by using the & operator. Here we are talking about the function call (not function prototype) and in function call we write ptrfunc ( &bo ) ; which means we passed the

docsity.com

cout << '\n' << p1->serno; // Pointer notation cout << '\n' << p1->text; } // Pass by reference void reffunc( const bigone &r1 ) { cout << '\n' << r1.serno; // Reference notation cout << '\n' << r1.text; }

Following is the output of the above program. 123 This is a BIG structure 123 This is a BIG structure 123 This is a BIG structure

Difference Between References and Pointers

The reference in a way keeps the address of the data entity. But it is not really an address it is a synonym, it is a different name for the entity. We have to initialize the reference when we declare it. It has to point to some existing data type or data value. In other words, a reference cannot be NULL. So immediately, when we define a reference, we have to declare it. This rule does not apply to functions. When we are writing the argument list of a function and say that it will get a reference argument, here it is not needed to initialize the reference. This reference will be passed by the calling function. But in the main program if we declare a reference then we have to initialize it. When a reference is initialized, we cannot reassign any other value to it. For example, we have ref that is a reference to an integer. In the program we write the line int &ref = j ;

Here j is an integer which has already been declared. So we have declared a reference and initialized it immediately. Suppose we have an other integer k. We cannot write in the program ahead as ref = k; Once a reference has defined, it always will refer to the same integer location as j. So it will always be pointing to the same memory location. We can prove this by printing out the address of the integer variable and the address of the reference that points to it.

In programming, normally we do not have a need to create a reference variable to point to another data member or data variable that exists, because creating synonym that means two names for the same thing, in a way is confusing. We don’t want that somewhere in the program we are using i (actual name of variable) and somewhere ref (reference variable) for manipulating the same data variable. The main usage of it is to implement the call by reference through an elegant and clean interface. So reference variables are mostly used in function calls.

docsity.com

The difference between pointers and references is that we can do arithmetic with pointers. We can increment, decrement and reassign a pointer. This cannot be done with references. We cannot increment, decrement or reassign references.

References as Return Values A function itself can return a reference. The syntax of declaration of such a function will be as under. datatype& function_name (parameter list) Suppose we have a function myfunc that returns the reference to an integer. The declaration of it will be as: int & myfunc() ;

Dangling Reference

The functions that return reference have danger with it. The danger is that when we return a value from such a function, that value will be reference to some memory location. Suppose that memory location was a local variable in the function which means we declare a variable like int x; in the function and then returns its reference. Now when the function returns, x dies (i.e. goes out of scope). It does not exist outside the function. But we have sent the reference of that dead variable to the calling function. In other words, the calling program now has a reference variable that points to nowhere, as the thing (data variable) to which it points does not exist. This is called a dangling reference. So be careful while using a function that returns a reference. To prevent dangling reference the functions returning reference should be used with global variables. The function will return a reference to the global variable that exists throughout the program and thus there will be no danger of dangling reference. It can be used with static variables too. Once the static variables are created, they exist for the life of the program. They do not die. So returning their reference is all right.

So, never return a reference to a local variable otherwise, there will be a dangling reference. Some compilers will catch it but the most will not. The reason is that the function that is returning a reference has defined separately. It does not know whether the reference is to a global or local variable, because we can do many manipulations in it and then return it. But normally compilers will catch this type of error.

Example 2

Let us look at an example of functions returning references. First, we declare a global variable that is an integer called myNum and say it is zero. Then we declare a function num that returns a reference to an integer. This function returns myNum , the global variable, in the form of reference. So now when there will be a function call, the return of the function will be a reference to the global variable called myNum. Now we can write the main function. Here we write myNum = 100 ; This assigns a value 100 to the global variable. Next we write int i ; i = num () ; Now a reference to myNum is returned. We would want to assign a reference to a reference but we can use it as an ordinary variable. Thus that value is assigned to i.

docsity.com

value of b is assigned to a and the value of a becomes the value of the entire statement. Therefore when we write a = b = c ; first b = c executes and the value of c is assigned to b. Since b = c is a statement and this statement has the value of b. Now a takes the value of this statement (which happened to be b ). So a = b also works. Similarly a + b + c also works in the same way that the value of c is added to b and then this result is added to a.

What happens when we write cout << “The value of integer is ” << i << endl ; Here first extreme right part will be executed and then the next one and so on or the other way. On the screen the “The value of integer is“ displayed first and then the value of the i and in the end new line. So it is moving from left to right. When cout gets the first part i.e. “The value of integer is”, this is a C statement. When this will be executed, the sentence “The value of integer is” is displayed on the screen. But what will be its value? That has to do something with the next << part and is needed with this << sign. We know that we need cout on the left side of << sign. So actually what happened is when the first part of the statement is executed. When the statement cout << “ The value of integer is” executed cout is returned. The next part is << i and it becomes cout << i; the value of i is printed and as a result of the statement cout is returned again which encounters with << endl; and a new line is inserted on the screen and cout is returned as a result of the statement execution. The return of the complete statement remains cout. The cout is stream, it does not have value per se. The reference to the stream is returned. The same reference which we have discussed today. The same thing applies to operators like +, -, *, /. This will also apply to = (assignment operator) and so on. We will be using lot of reference variables there.

Summary We have learned a new data type i.e. reference data type. We said that reference is synonym or alias for another type of data. Take int’s synonym or double’s synonym. In other words, it’s the second name of a variable. Then we talk about some do’s and dont’s. Normally we do not use two names for the same variable. It’s a bad idea and leads to confusing the programmer. Then we found the most useful part of using a reference. If we have to implement call by reference with function then using the prototype of the function which is expecting references and it leads to clean programming. You use the names of the arguments without using any dereferencing operator like *. The most useful part is implementing the call by reference. Then we looked at the difference of pointers and references. We cannot increment the reference variable. Arithmetic is not allowed with references but most importantly, reference variables must be initialized when they are declared. This is import. We can declare pointers and later can assign it some value. The use of reference with classes will be covered later. We have also seen a preview of the usage of references. In that preview we have learned new things that every statement itself has some value and that value is returned. Use it or not it’s a different issue. We call a function on a single line like f(x); may be f(x) returns some value and we did not use it. Not a problem. Similarly if we say a = b; this statement itself have some value whether we use it or not. Then we see how the cout statement is executed. Every part of the statement returns some value which is the reference to cout itself. It becomes the reference to the stream. How these references will be declared and used? We will cover this with operator overloading. Try to write some programs using references and implement call by reference using references instead of pointers.

docsity.com