To save content items to your account,
please confirm that you agree to abide by our usage policies.
If this is the first time you use this feature, you will be asked to authorise Cambridge Core to connect with your account.
Find out more about saving content to .
To save content items to your Kindle, first ensure no-reply@cambridge.org
is added to your Approved Personal Document E-mail List under your Personal Document Settings
on the Manage Your Content and Devices page of your Amazon account. Then enter the ‘name’ part
of your Kindle email address below.
Find out more about saving to your Kindle.
Note you can select to save to either the @free.kindle.com or @kindle.com variations.
‘@free.kindle.com’ emails are free but can only be saved to your device when it is connected to wi-fi.
‘@kindle.com’ emails can be delivered even when you are not connected to wi-fi, but note that service fees apply.
A program is a set of instructions, which are followed by the machine so as to generate a desired output. This means that writing a computer program is giving instructions to a processor, so as to delegate a particular job to the hardware of the computer system. Every instruction is a command given to the computer hardware to perform a specific job. Computer hardware is a digital system (collection of functional switches) and hence every instruction must be converted into the form of 0's and 1's (where a symbol 0 represents open switch and a symbol 1 represents closed switch). As an example, let us assume that we want the computer system to perform the addition of two numbers say 15 and 25. The instruction to perform addition of two numbers could be written in the machine language as shown below:
10000011 00001111 00011001
In this case, the first eight bits represent the code informing the hardware that the addition of the two numbers is to be performed. This is called as an opcode (operational code) of the instruction. Different instructions would have different opcodes and their purpose is to convey the meaning of the instruction to the internal hardware circuitry. In this case, we have assumed an arbitrary opcode of ADD instruction as 10000011. Different processors have different decoders and internal designs, hence the length and format of the opcode will certainly differ from processor to processor. Some processors have eight bit opcodes (e.g., intel 8085), some have 16 bit opcodes (e.g., intel 8086). Today's generation processors have 32 bit/64 bit opcodes or even 128 bit opcodes. We need not look into the hardware configurations and designs at this stage, but the key point to understand is that every instruction has an opcode and in this case, we just assume an arbitrary opcode of 8 bits as 10000011, which represents ADD operation. A different combination of 8 bits, say 11001010, may represent subtraction and so on. In theory, the variety of instructions any processor can offer is indirectly dependent on the length of its opcode. A processor with an opcode length of 8 bits can just offer 28 = 256 distinct instructions whereas a processor with an opcode length of 16 bits can offer 216 = 65536 distinct instructions.
C++ is an extension of C. This means that all the features of C are also available in C++. Furthermore, C++ has certain additional features of object-oriented programming, which makes it superior to the conventional C language. The details of object orientation and other features of C++ are covered in the later chapters of this text book.
In this chapter, we will study some fundamentals, which build the foundation to understand the advanced features of C and various object-oriented features supported by C++.
The First C/C++ Program
Recall from Chapter 1 that every C/C++ program has to be compiled and linked so as to convert the high-level language into the machine code. All the instructions written in the program are executed one-by-one by the processor in a sequence as they appear in the program file. Therefore, it is the job of the programmer to inform the processor about the exact starting point from which the execution of the program should begin. The main() function in C/C++ is used to represent the start and end points of the program execution. Hence, every program must have exactly one main() function, which is shown in Figure 2.1.
CPU will execute all the instructions where we write inside the body of the main()function in a sequence as they appear. The presence of empty round parenthesis after a special word main() informs the compiler that the function main() does not take any arguments. By default, every function in C/C++ is expected to return a value to the one who invokes the function. We can use a keyword void if we do not want to return any value to the calling function. The complete details of functions with arguments and return values are discussed in Chapter 7 of this text book and hence the details about ‘function arguments’ and ‘return types’ can be ignored at this point of time.
At this stage, we need to understand that a main() function is to be created using a template shown in Figure 2.1.
Creation and maintenance of the program becomes difficult when the lines of code in the program increase. As the size of the program increases, the code becomes more prone to errors and the debugging of the program becomes difficult. The line of code (LOC) is considered as one of the metrics to determine the logical complexity of the program in the software development life cycle. Any program is a sequence of instructions and there can be a situation where a subsequence needs to be repeatedly executed at different places in the program. Repeating the subsequence at each place will not only increase the LOC but also make the program bulky and hamper its readability, thereby making change management cumbersome. Imagine a situation wherein a certain operation (say performing addition) is repeatedly written in the program at 100 different places, and suddenly you realize that you need to perform subtractions instead of additions. Making this change is going to be difficult because you need to ensure that all the addition operations at 100 different places need to change to subtraction. And what if you miss one of them to change? Or what if you change something else by mistake in a rush to make these 100 changes? The problem is that there is a lot of duplication of code (redundancy of code), and hence making one change requires making multiple changes.
In C/C++, it is possible to split a large program into multiple independent pieces. Each independent piece is called a function or a method. A function can define a single operation or a sequence of operations. You can invoke a function whenever you need to execute the operations it defines. Hence, the idea is to define an operation only once within the function and invoke the same function at multiple places where you need to perform the operation. A function can have multiple inputs (called arguments) and generate a single output (called return value) as shown in Figure 7.1.
Structure is a template used to create a user-defined data type. This means that, as we create the variables of built-in data types, such as int, float, and double, we can now, also create the variables of user-defined data types, provided that the template for this data type are defined by creating a structure in the program. Structure is a way to combine the logically related data elements into a single unit. Each of the data elements defined inside the structure, are called the members of a structure. The members defined inside the structure can be of a same or different data types. Hence, a structure can be defined as a template which is created for storing heterogeneous values in physically adjacent memory locations.
What is a “user-defined” data type?
C/C++ has a built-in set of primitive data types like int, float, char, double etc, which we can be directly used in the program. We can create variables of built-in types and perform operations with the values stored in these variables. Along with using built-in data types, we can also create customized data types in a program. “User-defined data type” is a “customized” data type that the programmer can create as per the requirements to store data in computer memory.
Structures are used to create user-defined data types.
What is the need to create user-defined data types in the program?
Let us assume that you need to store data about the vehicles assembled in an automobile industry. The relevant information that you wish to maintain for each vehicle is “colour”, “no of seats”, “type of fuel” and “mileage” of the vehicle. As and when a new car is assembled you will need to create 4 different variables to store its information in computer memory. Instead, it would be easy if the programmer has an ability to create a variable of type Car using the statement,
Car c1;
where cl stores all the required information about the car in a real world. The variable cl can internally store the 4 attributes “colour”, “no of seats”, “type of fuel” and “mileage” of the vehicle.
A computer program is a set of instructions which is followed by a machine to generate the required output. The language in which a computer program is written is called a computer programming language. Several computer programming languages are in use in the IT industry today, for developing diverse software applications.
The study of C and C++ is considered an important step towards mastering computer programming fundamentals. Hence, C and C++ are included in the syllabus of any computer science course.
This textbook provides in-depth explanations of C and C++ programming languages along with the fundamentals of the object oriented programming paradigm.
About the Book
This book will be of use to anyone who is a beginner and aspires to learn the fundamentals of computer programming using C and C++. It has been primarily written for students of academic courses which include the study of C, C++ and object oriented programming paradigm. Simple and lucid language has been used to facilitate easy comprehension of complex topics.
Salient Features
• Example-driven approach illustrates application of theoretical concepts
• Theme of a conversation interspersed in the text, elucidate essential themes of the subject
• Each program includes necessary comments to explain the logic used to implement a particular functionality
• Several line diagrams and flow charts facilitate easy comprehension of theoretical concepts
• Student-friendly pedagogical features include:
✓ Error Finding Exercise
✓ Solved Problems
✓ Objective Questions
✓ Review Questions
Chapter Organization
This book comprises 17 chapters. Chapter 1 gives an overview of computer organization and architecture. It also explains the C/C++ development environment. Chapters 2 to 5 discuss the basic features of C/C++ including data types, variables and different control statements which are supported by the language. Chapter 6 describes the creation of multivalued data types (also referred to as collection types) using arrays in C/C++. Chapter 7 explains modular programming using functions. Chapter 8 elucidates the fundamentals of memory management using pointers in C/C++. Chapter 9 discusses the creation of composite data types using structures and unions in C/C++. Chapter 10 explains the principles of memory management and Dynamic memory allocations in C++ style. Chapters 11 to 17 provide in-depth coverage of object oriented features supported by C++.
Templates in C++ are used to facilitate generic programming by giving the programmer an ability to create generic classes/functions in the program. A component of the program is said to be generic if its functionality remains the same irrespective of data type of the values it operates on. A generic function is a function that can work with arguments of any data type, whereas a generic class is a class that can work with members of any data type. In this chapter, we will learn creation of generic functions using function templates and creation of generic classes using class templates.
NOTES
The objective of templates is to create generic components in the program, which can work with different data types. This saves programmers effort to define the same component multiple times and replicating same logic for different type of data values.
Function Templates
Function templates in C++ enable the programmer to create generic functions. These functions are adaptable to multiple data types and can execute in the same way immaterial of the data type of the values passed to it.
The functions we have written so far in the previous chapters are strictly bonded to specific types. For example, consider the function add() as shown below:
int add(int a,int b)
﹛
int c = a+b;
return c;
﹜
The function takes two arguments of type integer and returns the resultant integer, which gives addition of two numbers. This function works well if integer values are passed to it, however the function will not produce correct results if any other type of values are passed to it.
For instance, if we call the function add() by passing float values
float k = add(10.2,11.5);
the value returned in variable k will not be correct rather truncated. As per the default behaviour of C++, value in variable k will be 21.00 and not 21.7. This means that the function has performed truncation of the resultant value resulting in loss of data. And hence, the function cannot work for float type values.
At times, it is required to implement the same logic for multiple type of values. In such cases, you can use function templates in C++.
All the operators in C++ are designed to operate with the basic data types only. For example, an arithmetic operator + can be used to perform addition of integers, floats, doubles etc. but cannot be used to perform addition of user-defined objects. Let's say if we create a class Point to represent points in Cartesian coordinate system, we are not able to perform addition of two Point objects using operator + like we do it for primitive types. Recall from Chapter 11 section 11.10 that addition of Point objects P1 and P2 is performed using a function add() defined inside the class. We performed the addition of two points P1 and P2 by making a call to add() as follows:
P3=P1.add(P2);
The function is invoked by P1 passing P2 is passed as an argument, the result of addition is stored in object P3, which gives the x and y coordinate values of the resultant point. The addition of Point objects is performed using a member function add(), merely because the arithmetic operator + cannot be used to perform addition of user-defined objects. The basic principle of operator overloading is to extend the capability of C++ operators in order to use them with user-defined types in the same way and with the same syntax as with basic types. When we say that classes are used to create user-defined data types, it is a fair expectation that the operation with user-defined objects should be performed in the same way as they are performed with primitive types.
If we overload operator + in class Point, we will be able to perform addition of Point objects as follows:
P3=P1+P2;
Making use of operator + to add Point objects makes the statement very easy to read and understand when compared to the former statement. Operator overloading is essentially used by the programmers to create programs with a friendly syntax. Clearly it is not a necessity, but it provides great luxury to the programmers to read and maintain the program.
We understand from Chapters 1 and 2 that instructions in a program are executed in a sequence in which we write them in the main() function. Such an execution is called a sequential execution. In many cases it is required to change the sequence of executing instructions based on some condition. The statements that can be used to alter the sequence of executing instructions at run time of the program are called branching or decision making control statements.
C/C++ supports a following branching/decision making control statements:
1. if – else statement
2. else-if ladder
3. switch statement
4. Ternary operator (?:)
5. goto statement
In this chapter we discuss the syntax and working of each of the above decision making control statements supported by C/C++.
if else Statement
The if-else statement is used to change the sequence of execution by evaluating a specified condition at run time of the program. The condition to be evaluated must be specified in round parenthesis when defining the if block as shown in Figure 4.1. The if-else statement defines two blocks, the first block is called if block and the second block is called else block. The control of execution is transferred inside the if block if the condition specified in the parentheses is evaluated as true, whereas the control of execution is transferred inside the else block if the condition specified is evaluated as false.
A condition is generally written using relational operators and hence an evaluation of a condition can result into two possible outcomes as ‘true’ or ‘false’. Therefore, it will be correct to say that, in any of the given scenario the control of execution will always be transferred to at least one of the two blocks (if block or the else block). Also, the control of execution will be transferred to exactly one of the two blocks (if block in case the condition is evaluated as true or it can be a else block in case the condition is evaluated as ‘false’).
C/C++ has a dedicated set of special characters which can be used to perform operations on the data items. Each of these special characters represent as a specific operation to be performed to the compiler. For example, a symbol + is used to perform addition, and the symbol * is used to perform multiplication and so on. There are two properties associated with each of the operators so as to define the approach used for its evaluation:
1. Priority of the operator
2. Associativity of the operator
A Priority of the operator is a precedence associated with the operator. Every Operator is assigned a specific priority using which an operator must be resolved, so as to generate the result of the expression. Assigning priority to an operator helps in avoiding the ambiguity that may arise in the order of evaluation when a given expression consists of multiple operators. So as to understand the exact meaning of operator precedence, let us consider the expression below:
int p=10,q=5,r=2,s;
s=p+q*r;
After substituting the values of variables p, q, and r the expression that calculates the value of variable s can be rewritten as shown below:
s=10+5*2;
In the absence of operator precedence, the compiler will have two different options to generate the result of the above expression.
Option 1: Perform addition before multiplication (wrong option)
First perform the addition of two numbers 10 and 5, and then perform multiplication of the result with value 2. Hence, we will get the result of the expression as 30 as shown in Figure 3.1. Note that, this is a case where,we have evaluated the result of ‘addition’ before evaluating the result of ‘multiplication’. The order of evaluation is as shown in Figure 3.1.
Option 2: Perform multiplication before addition (correct option)
As a second option to generate the result of the expression, we could first perform multiplication of two numbers 5 and 2 and then perform addition of the result with value 10. Hence, we will get the result of the expression as 20 as shown in Figure 3.2. Note that, this is a case where, we have evaluated the result of ‘multiplication’ before evaluating the result of ‘addition’. The order of evaluation is as shown in Figure 3.2.
Any software system to be developed (using any of the programming languages) must go through a series of steps before the system is deployed and released on to the production environment. The software development life cycle (SDLC) defines the stages involved in the software development process, so as to develop a particular application. One of the models that are followed in the development of a software application is called as a ‘waterfall’ model, which is shown in Figure A3.1.
The figure shows a series of steps that we must follow in the software development process. The meaning of each of the phases is as explained below:
Analysis: This is a phase in software development where the software engineer understands the exact requirements of the software to be developed. The requirements of the application to be developed are captured from the end users of the application and a ‘Business requirements document’ is prepared, which describes the answers to the following questions:
1. What are the inputs to the system to be developed?
2. What is the processing to be performed by the system to be developed?
3. What are the outputs of the system to be developed?
‘Analysis’ is the detailed study of the requirements that are received from the business users for a particular software system to be developed under a given set of constraints.
Design: Software ‘design’ is a process to create ‘model’ of the system to be developed thereby finalizing the complete approach of development. The models created during the ‘design’ phase should define the following attributes:
1. The detailed software architecture of the system to be developed.
2. The detailed procedure/algorithm of each functionality which is required to implement the solution.
3. The specifications of the data models to be implemented for the system to be developed.
4. Other software system and integrity constraints.
The ‘feasibility study’ is also done in the design process so as to determine if the requirements are possible to be implemented under a given set of constraints. If any of the requirements is found to be unfeasible, the development process may be reiterated from the analysis phase where the requirements for the system are redefined.
This paper is a continuation of Amidei, Pianigiani, San Mauro, Simi, & Sorbi (2016), where we have introduced the quasidialectical systems, which are abstract deductive systems designed to provide, in line with Lakatos’ views, a formalization of trial and error mathematics more adherent to the real mathematical practice of revision than Magari’s original dialectical systems. In this paper we prove that the two models of deductive systems (dialectical systems and quasidialectical systems) have in some sense the same information content, in that they represent two classes of sets (the dialectical sets and the quasidialectical sets, respectively), which have the same Turing degrees (namely, the computably enumerable Turing degrees), and the same enumeration degrees (namely, the ${\rm{\Pi }}_1^0$ enumeration degrees). Nonetheless, dialectical sets and quasidialectical sets do not coincide. Even restricting our attention to the so-called loopless quasidialectical sets, we show that the quasidialectical sets properly extend the dialectical sets. As both classes consist of ${\rm{\Delta }}_2^0$ sets, the extent to which the two classes differ is conveniently measured using the Ershov hierarchy: indeed, the dialectical sets are ω-computably enumerable (close inspection also shows that there are dialectical sets which do not lie in any finite level; and in every finite level n ≥ 2 of the Ershov hierarchy there is a dialectical set which does not lie in the previous level); on the other hand, the quasidialectical sets spread out throughout all classes of the hierarchy (close inspection shows that for every ordinal notation a of a nonzero computable ordinal, there is a quasidialectical set lying in ${\rm{\Sigma }}_a^{ - 1}$, but in none of the preceding levels).
Ibn Sīnā (11th century, greater Persia) proposed an analysis of arguments by reductio ad absurdum. His analysis contains, perhaps for the first time, a workable method for handling the making and discharging of assumptions in a formal proof. We translate the relevant text of Ibn Sīnā and put his analysis into the context of his general approach to logic.
It’s well known that it’s possible to extract, from Frege’s Grudgesetze, an interpretation of second-order Peano Arithmetic in the theory $H{P^2}$, whose sole axiom is Hume’s principle. What’s less well known is that, in Die Grundlagen Der Arithmetic §82–83 Boolos (2011), George Boolos provided a converse interpretation of $H{P^2}$ in $P{A^2}$. Boolos’ interpretation can be used to show that the Frege’s construction allows for any model of $P{A^2}$ to be recovered from some model of $H{P^2}$. So the space of possible arithmetical universes is precisely characterized by Hume’s principle.
In this paper, I show that a large class of second-order theories admit characterization by an abstraction principle in this sense. The proof makes use of structural abstraction principles, a class of abstraction principles of considerable intrinsic interest, and categories of interpretations in the sense of Visser (2003).
In this paper, design, analysis and real-time trajectory tracking control of a 6-degree of freedom revolute spherical-spherical type parallel manipulator, actuated by six hybrid stepper motors, has been studied. Two different control approaches have been used to improve the trajectory tracking performance of the designed manipulator. The first approach considered a single input-single output (SISO) linear quadratic regulator (LQR) for trajectory tracking control of the manipulator. Another controller type based on a nonlinear sliding mode controller method has been utilized to take decoupled dynamic approximation model of the manipulator into account and to improve tracking performance of the manipulator. Real-time experimental results for the two different control techniques have been verified. Finally, according to the results, the nonlinear sliding mode controller method has improved the tracking performance of the designed manipulator.