






Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
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: Examples, Exercises, Assignment, Operator, Function, Overload, Multiplication, Addition, Insertion, Extraction, Variables, Pointers, Arrays, Loops
Typology: Exercises
1 / 11
This page cannot be seen from the preview
Don't miss anything!







Lecture 43 - Lecture 44
Example (continued) Assignment Operator Function Addition Operator Function Plus-equal Operator Function Overloaded Plus Operator Function Minus Operator Function Multiplication Operator Function Insertion and Extraction Operator Function exercise Rules for Programming Variables and Pointers Arrays Loops and decisions Classes and Object Garbage Collection Truth Table Structured Query Language
This is a sequel of the discussion on ‘matrix class’ made in the previous lectures.
Assignment Operator Function Before going into minute details, we will talk about the assignment operator of this class. This operator occupies very important place in the field of programming. When we want to write code like a = b; where a and b both are matrices, the assignment operator attains a critical role as our class does dynamic memory allocation. Here we don’t know whether the size of a and b will be the same or not. If these are of different size, then it will be better to reallocate the memory. So it warrants the existence of some checks and balances. At first, we look at the declaration line of the assignment operator, it is written below.
const Matrix & operator = (const Matrix &m);
The declaration line states that it must return a reference to a matrix. Why do we want to return a matrix? The return of the matrix is necessary to enable us write the statement i.e. a = b = c; We know, in C and C++ languages, every expression has a value of its own. Now if we write a = b ; it will mean that the whole action will have a value. This value itself will be a reference to a matrix. On the other hand, we have made it const. In other words, the reference that is being returned is a constant. Whenever we return a reference of a thing that thing can become on left-hand side of an assignment statement, which can lead to some very funny behavior. If we write (a = b) = c ; It will result in the execution of the statement, a = b. It will return a value that is a reference to a matrix. This reference will be assigned the value of c. this means that some minor things can take place. We will like to have parentheses only on right hand side. It is advisable not to do an assignment to the reference that is being returned. To avoid this, we write const with it. Thus, we get the efficiency as reference is being returned. We also enjoy safety due to the fact that no value can assign to this reference in the same statement. Due to the reference returned, we can write the statement like a = b = c ;
Let’s have a look on the next implication i.e. the size of the matrix. Whenever there is dynamic memory allocation in a class, we have to check against self-assignment. Self- assignment means statements like a = a ;. If we take ordinary variables, say integer, writing i = i ; is quiet right. But if we write something like a = a ; it will be possible to free the memory of object on the left hand side as it is doing some dynamic memory allocation. Now we can assign new memory and copy the right hand side in it. If we write a = a; it will lead to a very tricky situation. This means that we, at first, delete it (the left-hand side), as right hand side is the same object with same memory, so it is also deleted. Then, we try to copy the right hand side that has been deleted. So we must check against self-assignment. While dealing with the code of the assignment operator, we will first check whether it is for the self-assignment or not. To ascertain it, we will write the following line.
if( &m != this)
This way, the self-assignment check has been carried out. In case of not finding self- assignment, the programmer will have to do further process.. After checking the self-assignment, the program checks the size of both the matrices and sees whether these are the same or different. If their size is same, then it will copy the matrix of right hand side element-by-element in the matrix on left-hand side. But if their size is different in terms of number of rows or columns, then we have to create a new matrix for the left-hand side. This code is similar to the one that we wrote in the constructor. We free the memory and reallocate the memory of the correct size. This size is equal to the size of the matrix on right hand side. After re-allocating the memory, we readjust the number of rows and columns of the lef- hand side object. So we write it as
numerous = m.numRows ; numCols = m.numCols ;
While defining rows and columns, we execute a for loop and copy the elements of right hand side at corresponding positions on left hand side. This way, we define the assignment operator, which can be used in different functions. Here, we can write
docsity.com
efficiency. So this whole matrix will be copied on the stack and assigned wherever it is needed. If we have written c = a + b ; it will be assigned to c. The things where the reference or matrix is being returned, should be carried out carefully. It is important for us to know what thing should be returned to where, and what is its usage and behavior? The code of the addition operator function is written in the program as below.
Matrix Matrix::operator + ( Matrix &m ) const { // Check for conformability if(numRows == m.numRows && numCols == m.numCols) { Matrix temp(this); for (int i = 0; i < numRows; i++) { for (int j = 0; j < numCols; j++) { temp.elements[i][j] += m.elements[i][j]; } } return temp ; } Matrix temp(this); return temp; }
Plus-equal (+=) Operator Function Now we will discuss the += operator. Whenever a programmer writes a += b , he will come across a different scenario as compared to the one witnessed in the case of the addition operator. In a way, now ‘ a’ itself is being changed. So if a is going to change, we can return a reference to a. The conformability check remains the same as in ordinary addition. That means both matrices must have the same number of rows and columns. There is no need of creating a temporary matrix. Here we can return reference to left-hand side matrix. Here one finds that there is reuse and efficiency in the code. The += operator is defined as under.
const Matrix & Matrix::operator += (Matrix &m) { *this = *this + m; return *this; }
Overloaded plus Operator Function Next concept to be discussed the overloading of the overloaded plus (+) operator. It is very simple. If we want to add a double variable in a matrix, there will be no problem of conformability. All we need to do is add a value to every element. Here we are doing a + d ( a is a matrix while d is a double ). Here, a will not change. A new matrix will be returned by adding the value of d to the elements of a. So it is not returning a reference, but a matrix. If it is returning a matrix, it must return a matrix that is created inside this function. Thus, we can use copy constructor and write
docsity.com
Matrix temp (* this) ;
In this matrix temp, we add the value of d by a nested loop and return it. This way, the addition of a matrix with a double variable is defined. The code of it is given below.
Matrix Matrix::operator + ( double d ) const { Matrix temp(*this); for (int i = 0; i < numRows; i++) { for (int j = 0; j < numCols; j++) { temp.elements[i][j] += d; } } return temp ; }
Next function is d + a (i.e. double variable + matrix). There is a double variable and not a matrix on left hand side, leaving no option for having it as a member function. It is a friend function and defined outside the class. We don’t use the scope resolution operator (::) with it. It is defined as an ordinary stand-alone function. It still returns a matrix .So it is written as
Matrix operator + (double d, Matrix &m)
Two arguments are passed to it that are the variables on left and right side of the operator. The remaining code is almost the same as that of a + d , and is written as below.
Matrix operator + (double d, Matrix &m) { Matrix temp(m); for(int i=0; i< temp.numRows; i++) { for(int j=0; j<temp.numCols; j++) { temp.elements[i][j] += d; } } return temp; }
Minus Operator (-) Function The same discussion of plus (+) operator applies to the minus (-) operator as both are identical. We see the difference between these operators when we do a + d. In case of addition, it will be the same as that of d + a. However, while dealing with minus case, the result of a - d will be obviously different from the result of d - a.
docsity.com
extraction operator. The only difference is that we have to return a reference to the stream. Thus it is a two- line function and is a good example of code reuse. We have written the input function, which can be used here. Same thing applies if we have to take input from the file and put it into matrix m. We have declared these functions as friend functions and in the following their code is written
istream & operator >> ( istream & is, Matrix & m) { m.input(is); return is; }
We will now use the input function, written to take input from file.
ifstream & operator >> ( ifstream & is, Matrix & m) { m.input(is); return is; }
Similarly, the pair of output functions can be reused to overload the stream insertion operator.
ostream & operator << ( ostream & os, Matrix & m) { m.output(); return os; }
And for the file output the code is as follows.
ofstream & operator << ( ofstream & os, Matrix & m) { m.output(os); return os; }
Exercise Now you should study and understand this whole code of the class and use it. Its use is very simple. You can write the main function and in it write
Matrix m (3,3) ;
When you will execute it, a matrix of three rows and three columns will be created and values of it will be zero. To display this matrix on the screen, you can write
m.output ;
It will display a properly formatted matrix on the screen. Similarly you can define other matrices and can get their values from the keyboard. You can multiply them and
docsity.com
see that multiplication is done only if the matrices are conformable for multiplication. Similarly, addition will work only if the matrices are conformable for addition. You can write a little test program. You should also try to extend the class by adding new functions and features into it. In the code, there are not proper error messages. You can write code to do more error checking and to display proper error messages wherever an error encounters.
It is very simple to change the whole class from double to int. More complicated one would may be used to write a template for this class. In the class, wherever there is double , you will write
Review
Now we will review the different topics of the course briefly and some discussion in respect of languages and programming. In the beginning of the course, we came across a few programming guidelines. We have read about design recipe. Then we went on and developed the way of thinking. To begin with the review of the previously discussed subjects, we will now talk about the rules of programming.
Rules for Programming
We need simply three constructs to solve any problem.
Things should be executed sequentially. That means the statements are executed in a sequence i.e. the second statement follows the first and so on.
We need to have a decision. The decision means if something is true, the program executes it. Otherwise, it tries doing something else. So there is simple decision or if- else decision.
The third construct is loop, which is a repetition structure that performs the same task repeatedly with different values.
So the availability of sequences, decisions and loops can help us write any program. The code, we write, should be short and concise. It need to be self-contained and understandable. Comments should be placed liberally. The comments should explain the logic, not the mechanics. Try to avoid fancy programming. The indentation of the code has no means programmatically as it does not mean any thing at all. What actually matters is how you structure the code using braces and semicolons i.e. the structure of the language. Otherwise, C and C++ are free-format languages. We can write the whole code in a single line. But it will be very difficult to read. We format our code so that it could be read easily. So indentation is for us, not for the compiler. Similarly, any language does not dictate it. On the other hand, if we put our code inside braces and blocks, it will ensure a logical syntax.
Variables and Pointers
docsity.com
the data. The major advantage of data hiding and encapsulation is that it makes every thing tested, debugged and ready to use. When we come in the main program, which uses these classes or objects, our code becomes very simple. We can reuse this code repeatedly. When we put all of this together, the concept of doing object-oriented programming becomes clear. How can a class be made from another class? We will talk about polymorphism in the course of object oriented programming. It can determine what function is to call at the execution time of the program not at the compile time. These are very important and powerful methods. There will be whole idea of thinking objects. Here we only covered mechanics. When we were talking about mechanics, we have to understand how can we implement a member function and a member operator. We use the sequences, decisions and repetition structures while writing the member or friend functions. So we build on our previous knowledge and introduce the concepts of classes and objects.
Garbage Collection
The whole concept of using objects and their notation which is object.member , where member could be a data type or a function, that is what we have been exercising. We also mentioned that we could have pointers to objects. During the manipulation of the data variable or data member with pointers, we use the arrow (->) notation rather than the dot (.) notation. The concept of pointers is very important but quite limited to C and C++. The modern languages, for example JAVA, describe pointers as dangerous. We can go anywhere in the memory and can change a value. There is another problem with pointers, which is that these could be pointing to nowhere. For example, we allocate memory and de-allocate it there or in some other function, without reassigning a new memory to the pointer that was pointing to that memory. Thus, a dangling pointer is there that points to nothing. There is also reverse case of it that we assign a memory through a pointer where the pointer is destroyed, the memory remains allocated and is wasted. To address these things, there are only references in JAVA instead of pointers. JAVA gives the concept of garbage collection with the use of references. Due to this garbage collection, we are free from the headache of de- allocating the memory. We allocate and use the memory. When it is no longer in use, JAVA automatically deletes (frees) it through garbage collection. But in C and C++ languages, we have to take care of de-allocating the memory. In classes where we use dynamic memory, we have to provide destructors to free this memory. The languages keep evolving, new constructs will keep evolving in existing or new languages. So the foundations of our knowledge must be strong. We have to know what is programming. We have to know how can we take the essence of a problem by analyzing it. We should repeat the design recipe as many times as needed.
Truth Table
There are some areas where the decision structures become very complicated. Sometimes, we find it difficult to evaluate a complicated logical expression. Sometimes the logic becomes extremely complicated so that even writing it as a simple syntax statement in any language. It becomes complicated to determine what will be evaluated in what way. We know the concept of truth table. The truth tables are very important. These are still a tool available for analyzing logical expressions. We will read logic design in future, which is actually to do with chips and gates. How we put these things together. In logic design, there are certain techniques that are
docsity.com
known as minimization techniques. These are used to make a big circuit with the use of minimum chips. These minimization techniques deal with Boolean algebra i.e. logic. These techniques are also used in programming. So we should keep breadth in our vision while maintaining a horizontal integration. We should always think outside the box. There is a way of thinking for us as programmers. We always look at problems, slice and dice them and come up with solutions. Programming as a skill is infact important. It helps us think, from a logical perspective. How can we do it is something else. We can get it from the reference books of the language or from online help in the compiler. This part that how can we do is always changing. New languages will be evolved for our help. On the other hand, what is to be done depends on our logical skills and fundamental knowledge. We have to develop this thing. Structured Query Language In the business world, most of the programming is database-oriented. In today’s databases, like Oracle and SQL Server, a different kind of language is used. These are the languages that are called as structured query languages i.e. SQL. SQL, is so important that a standard has been developed for it. So there is an ANSI standard for this language. There is a major difference between SQL and the conventional language. The SQL by law says ‘tell me what do you want and I will determine how to do it’. Whereas in our conventional languages like C or C++, we have to tell the languages what we want to do and how to do it. These are differentiated in the terminology like third generation languages and fourth generation languages. There are optimizers built in those languages. Optimizers mean how a query or question can be executed more efficiently. In the same way, there are optimizers in our compilers. When we write the code, the compiler looks into it to determine how this code can be executed more efficiently. The modern compilers do a large optimization. Different software companies or computer manufacturers write the compilers. The standard is the same for writing compilers. The difference is that how much fast the executable version of a program executes and how much memory it uses, when compiled by different compilers. The speed and memory usage is the two yard sticks of output code.
The fundamentals are important. Keeping of a breadth of vision is also critically important. We have to constantly keep up with literature, keep up with new development, and experiment with more and more new tools. Talking about languages is not that important. However, talking about programming is critically more important. If we have a sound fundamental knowledge, no new language can frighten us. We will never feel over powered by any new language. The fundamentals can become strong only by practicing more and experimenting to the maximum.
docsity.com