C++, like a number of other languages, is powerful enough so one can use it to code any task. But in a lot of cases, it's more convenient to code a task in a language that's specifically designed for that task. The situation is analogous to the automobile world: why doesn't everybody drive the same kind of automobile? Because off-road driving is best handled by a four-wheel-drive vehicle, hauling a team of Little Leaguers is best handled in a minivan, etc.
In the first version of FORTRAN, statements could be assigned numbers (instead of labels) and changes in control flow were performed by the IF and GO TO statements.
IF(NUMBER) 20, 30, 40would send control to statement 20 if NUMBER < 0, to statement 30 if NUMBER = 0, or to statement 40 if NUMBER > 0.
GO TO 50would always send control to statement 50. A while-loop in C++ like:
while(Number >= 0)
{
.
.
.
cin >> Number ;
}
was coded in FORTRAN like:
10 IF(NUMBER) 20, 5, 5
5 .
.
.
READ(*,*) NUMBER
GO TO 10
20 ...
Statement numbers could be in any order so following the flow of control
could be a nightmare: "spaghetti code" was a common term applied to many
FORTRAN programs.
Later versions of FORTRAN (FORTRAN II, FORTRAN IV, FORTRAN 77, Fortran 90, and High Performance Fortran) have incorporated more data types and new statements to direct the flow of control.
sum = a + b;a COBOL programmer would write:
ADD A TO B GIVING SUM.Back in the fifties and sixties, 80-column punched cards were used for many databases. To conserve card columns, COBOL used only six digits for a date (two for the month, two for the day of the month, and two for the year): some now blame the Y2K problem on COBOL.
Like other high-order languages a C program doesn't need to specify the locations of variables in memory, but this is necessary in some system programs so C also has some low-level constructs.
For example, if Number is a variable in a C program then &Number refers to the memory address of Number. If Number is stored in memory location 1000 and has a value of 234 then Number is 234 and &Number is 1000.
| Identifier | Address | Value |
|---|---|---|
| Number | 1000 | 234 |
Another low-level construct in C is the pointer data type for variables that contain memory addresses. For example,
int* intPointer ;
declares intPointer to be a variable that contains the memory
address of an integer and the assignment statement:
intPointer = (int*) 800 ;
sets intPointer to point to the memory address 800 as shown in Fig. 9.3(a) - intPointer itself is assigned some memory location
by the C compiler.
The memory location that intPointer points to is identified by *intPointer so the assignment statement:
*intPointer = 3 ;
sets the value stored in memory location 800 to 3 as shown in
Fig. 9.3(b).
These low-level constructs were put in C so system programs like UNIX can read/write certain specific memory locations used by I/O devices. They are also a source of bugs in non-system programs - for example, location 800 in the C code above may already have some other purpose in this program or in some other program (like the operating system.)
The C++ language we studied in Chapter 8 is a superset of C that was also developed at AT&T Labs - a C++ programmer doesn't need to use the pointer data type and be concerned with all the bugs it might create.
Portability is achieved by compiling the source program into a low-level language called Java bytecode which is easily translated into the machine language of any computer.
The Microsoft .NET Framework is a very large collection of tools for software development in C# and other programming languages.
SELECT NAME
FROM VENDOR
WHERE ZIP = 95082;
is an SQL statement asking a database for the names of all vendors in the 95082
Zip-code area.
Any computer program transforms the values of its input data into the values of its outputs. If it produces more than one output, one can group them into a single list containing all the output values. Thus, one can think of any computer program as a mathematical function transforming the values of its arguments (input data) into a corresponding resulting value (a list of all output values.)
In a functional programming language (like Scheme) certain primitive functions are defined as part of the language and the programmer can use these primitives to build other functions.
For example, the tripling function, f (x ) = 3x transforms its argument into a result with three times the value so f (4) = 12 and f (12) = 36. In Scheme one can define this function and give it the name triple with:
(define (triple x)
(* 3 x))
One can then use the triple function by entering something like
(triple 4) and Scheme will display the answer, 12.
As another example, the squaring function, g (x ) = x2 can be defined in Scheme and given the name square with:
(define (square x)
(* x x))
Once a function is defined one can use it to define other functions.
For example, h (x ) = 3x2 can be defined
in Scheme and given the name foo with:
(define (foo x)
(triple (square x)))
If a user enters (foo 4) then Scheme displays 48.
Scheme has four primitives that manipulate lists:
(list 5 6 7)creates the 3-element list: (5 6 7)
(car (list 5 6 7))produces 5.
(cdr (list 5 6 7))produces (6 7).
(define (adder input-list)
(cond ((null? input-list) 0)
(else (+ (car input-list)
(adder (cdr input-list))))))
The definition of adder uses a conditional construct in Scheme:
A program written in a procedural language specifies the exact order in which its steps are performed: a program written in a functional language doesn't specify this order. The only restriction on the order of function evaluations is that a function can't be evaluated until all its arguments have been evaluated.
president(lincoln, gettysburg_address) .
president(lincoln, civil_war) .
president(nixon, first_moon_landing) .
president(jefferson, lewis_and_clark) .
president(kennedy, cuban_missile_crisis) .
president(fdr, world_war_II) .
The following facts show the chronology of the terms of office of these presidents:
before(jefferson, lincoln) .
before(lincoln, fdr) .
before(fdr, kennedy) .
before(kennedy, nixon) .
If given the query:
?-before(lincoln, fdr) .then Prolog responds with a Yes because that is a fact in the program. The following query:
?-president(lincoln,civil_war),before(lincoln,fdr)asks if Lincoln was president during the civil war AND if Lincoln was before FDR. Since both facts are in the program, Prolog responds with a Yes. One can also use variables (beginning with capital letters) in a query. For example, the query:
?-president(lincoln,X).is answered with the following responses:
X = gettysburg_address
X = civil_war
There is a problem with the before relation. For example, Lincoln
was president before Kennedy but the query:
?-before(lincoln,kennedy) will get a No response. To correct
this problem one can define another relation, precedes:
precedes(X,Y) :- before(X,Y) . precedes(X,Y) :- before(X,Z),precedes(Z,Y) .The first line of this definition says that X precedes Y if X comes before Y. The second line says that X precedes Y if X comes before some third president, Z, who precedes Y. With this definition, the query: ?-precedes(lincoln,kennedy) will now get a Yes response.
One can now define another relation to show the time order of events, earlier:
earlier(X,Y) :- president(R,X),president(S,Y),precedes(R,S) .The query: ?-earlier(world_war_II,X) will now get the following responses:
X = first_moon_landing
X = cuban_missile_crisis
Prolog is a declarative language instead of an imperative
language because a Prolog program has no commands to perform any
operations. As shown in Fig. 9.11, there is an Inference engine
inside the Prolog interpreter or compiler which reads each query and
determines how best to answer it.
Programs for SIMD machines usually have large data arrays. For example, one might declare three data arrays, A, B, and C, with 1000 elements in each array and the statement A = B + C would perform 1000 additions simultaneously to add elements of array B to elements of array C and stores the sums in elements of array A.
A program for a MIMD machine usually uses the divide-and-conquer approach to break a task up into a number of subtasks and then assign each subtask to a separate processor.