0% found this document useful (0 votes)
11 views31 pages

Importance of Studying Programming Languages

Uploaded by

soujanya565
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views31 pages

Importance of Studying Programming Languages

Uploaded by

soujanya565
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

Why study programming languages?

♦ Toimprove the ability to develop effective algorithms.


♦ Toimprove the use of familiar languages.
♦ Toincrease the vocabulary of useful programming constructs.
♦ Toallow a better choice of programming language.
♦ Tomakeit easier to learn a new language.
♦ Tomakeit easier to design a new language.
♦ Tosimulate useful features in languages that lack them.
♦ Tomakebetter use of language technology wherever it appears.

Programming Domains
 Scientific applications
– Large number of floating point computations
– Fortran
 Business applications
– Produce reports, use decimal numbers and characters
– COBOL
 Artificial intelligence
– Symbols rather than numbers manipulated
– LISP
 Systems programming
– Need efficiency because of continuous use
– C
 Web Software
– Eclectic collection of languages: markup (e.g., XHTML), scripting (e.g.,
PHP), general-purpose (e.g., Java)
Language Evaluation Criteria –

 Readability : the ease with which programs can be read and understood
 Writability : the ease with which a language can be used to create programs
 Reliability : conformance to specifications (i.e., performs to its specifications)
 Cost : the ultimate total cost

Readability
 Overall simplicity
– A manageable set of features and constructs
– Few feature multiplicity (means of doing the same operation)
– Minimal operator overloading
 Orthogonality
– A relatively small set of primitive constructs can be combined in a relatively
small number of ways
– Every possible combination is legal
 Control statements
– The presence of well-known control structures (e.g., while statement)
 Data types and structures
– The presence of adequate facilities for defining data structures
 Syntax considerations
– Identifier forms: flexible composition
– Special words and methods of forming compound statements
– Form and meaning: self-descriptive constructs, meaningful keywords
Writability
 Simplicity and Orthogonality
– Few constructs, a small number of primitives, a small set of rules for
combining them
 Support for abstraction
– The ability to define and use complex structures or operations in ways that allow
details to be ignored
 Expressivity
– A set of relatively convenient ways of specifying operations
– Example: the inclusion of for statement in many modern languages
Reliability
 Type checking
– Testing for type errors
 Exception handling
– Intercept run-time errors and take corrective measures
 Aliasing
– Presence of two or more distinct referencing methods for the same memory
location
 Readability and writability
– A language that does not support “natural” ways of expressing an algorithm will
necessarily use “unnatural” approaches, and hence reduced reliability
Cost
 Training programmers to use language
 Writing programs (closeness to particular applications)
 Compiling programs
 Executing programs
 Language implementation system: availability of free compilers
 Reliability: poor reliability leads to high costs
 Maintaining programs
Others
 Portability
– The ease with which programs can be moved from one implementation to
another
 Generality
– The applicability to a wide range of applications
 Well-definedness
– The completeness and precision of the language‘s official definition
Influences on Language Design
 Computer Architecture
– Languages are developed around the prevalent computer architecture, known as
the von Neumann architecture
 Programming Methodologies
– New software development methodologies (e.g., object-oriented software
development) led to new programming paradigms and by extension, new
programming languages

Computer Architecture
 Well-known computer architecture: Von Neumann
 Imperative languages, most dominant, because of von Neumann computers
– Data and programs stored in memory
– Memory is separate from CPU
– Instructions and data are piped from memory to CPU
– Basis for imperative languages
 Variables model memory cells
 Assignment statements model piping
 Iteration is efficient

Figure 1.1 The von Neumann Computer Architecture

Programming Methodologies
 1950s and early 1960s: Simple applications; worry about machine efficiency
 Late 1960s: People efficiency became important; readability, better control
structures
– structured programming
– top-down design and step-wise refinement
 Late 1970s: Process-oriented to data-oriented
– data abstraction
 Middle 1980s: Object-oriented programming
– Data abstraction + inheritance + polymorphism
Language Categories –
 Imperative
– Central features are variables, assignment statements, and iteration
– Examples: C, Pascal
 Functional
– Main means of making computations is by applying functions to given
parameters
– Examples: LISP, Scheme
 Logic
– Rule-based (rules are specified in no particular order)
– Example: Prolog
 Object-oriented
– Data abstraction, inheritance, late binding
– Examples: Java, C++
 Markup
– New; not a programming per se, but used to specify the layout of information in
Web documents
– Examples: XHTML, XML

Language Design Trade-Offs

 Reliability vs. cost of execution


– Conflicting criteria
– Example: Java demands all references to array elements be checked for proper
indexing but that leads to increased execution costs
 Readability vs. writability
– Another conflicting criteria
– Example: APL provides many powerful operators (and a large number of new
symbols), allowing complex computations to be written in a compact program but at
the cost of poor readability
 Writability (flexibility) vs. reliability
– Another conflicting criteria
– Example: C++ pointers are powerful and very flexible but not reliably used

Implementation Methods -
 Compilation
– Programs are translated into machine language
 Pure Interpretation
– Programs are interpreted by another program known as an interpreter
 Hybrid Implementation Systems
– A compromise between compilers and pure interpreters
Compilation
 Translate high-level program (source language) into machine code (machine
language)
 Slow translation, fast execution
 Compilation process has several phases:
– lexical analysis: converts characters in the source program into lexical units
– syntax analysis: transforms lexical units into parse trees which represent the
syntactic structure of program
– Semantics analysis: generate intermediate code
– code generation: machine code is generated
Figure 1.2 Layered View of Computer: The
operating system and language
implementation are layered over Machine Figure 1.3 The Compilation Process
interface of a computer

Additional Compilation Terminologies


 Load module (executable image): the user and system code together
 Linking and loading: the process of collecting system program and linking them to
user program
Execution of Machine Code
 Fetch-execute-cycle (on a von Neumann architecture)
initialize the program
counter repeat forever
fetch the instruction pointed by the counter
increment the counter
decode the instruction
execute the instruction
end repeat
Von Neumann Bottleneck
 Connection speed between a computer‘s memory and its processor determines the
speed of a computer
 Program instructions often can be executed a lot faster than the above
connection speed; the connection speed thus results in a bottleneck
 Known as von Neumann bottleneck; it is the primary limiting factor in the speed of
computers
interpreter
The interpreter in the compiler checks the source code line-by-line and if an error is found on any line, it
stops the execution until the error is resolved. Error correction is quite easy for the interpreter as the
interpreter provides a line-by-line error. But the program takes more time to complete the execution
successfully. I
Pure Interpretation
 No translation
 Easier implementation of programs (run-time errors can easily and immediately
displayed)
 Slower execution (10 to 100 times slower than compiled programs)
 Often requires more space
 Becoming rare on high-level languages
 Significantly comeback with some latest web scripting
languages (e.g., JavaScript)

Hybrid Implementation Systems


 A compromise between compilers and pure interpreters
 A high-level language program is translated to an intermediate
language that allows easy interpretation
 Faster than pure interpretation
 Examples
– Perl programs are partially compiled to detect errors before
interpretation
– Initial implementations of Java were hybrid; the intermediate
form, byte code, provides portability to any machine that has
a byte code interpreter and a runtime system (together, thesare

called Ja

Just-in-Time Implementation Systems


 Initially translate programs to an intermediate language
 Then compile intermediate language into machine code
 Machine code version is kept for subsequent calls
 JIT systems are widely used for Java programs
 .NET languages are implemented with a JIT system

Preprocessors -
 Preprocessor macros (instructions) are commonly used to specify
that code from another file is to be included
 A preprocessor processes a program immediately before the program
is compiled to expand embedded preprocessor macros
 A well-known example: C preprocessor
– expands #include, #define, and similar macros

Compiler
The compiler is software that converts a program written in a high-level language
(Source Language) to a low-level language (Object/Target/Machine Language/0,
1’s).
Phases of Compiler
1. Lexical Analysis: The first stage of compiler design is lexical analysis, also
known as scanning. In this stage, the compiler reads the source code character
by character and breaks it down into a series of tokens, such as keywords,
identifiers, and operators. These tokens are then passed on to the next stage of
the compilation process.
2. Syntax Analysis: The second stage of compiler design is syntax analysis, also
known as parsing. In this stage, the compiler checks the syntax of the source
code to ensure that it conforms to the rules of the programming language. The
compiler builds a parse tree, which is a hierarchical representation of the
program’s structure, and uses it to check for syntax errors.
3. Semantic Analysis: The third stage of compiler design is semantic analysis. In
this stage, the compiler checks the meaning of the source code to ensure that it
makes sense. The compiler performs type checking, which ensures that variables
are used correctly and that operations are performed on compatible data types.
The compiler also checks for other semantic errors, such as undeclared variables
and incorrect function calls.
4. Code Generation: The fourth stage of compiler design is code generation. In
this stage, the compiler translates the parse tree into machine code that can be
executed by the computer. The code generated by the compiler must be efficient
and optimized for the target platform.
5. Optimization: The final stage of compiler design is optimization. In this stage,
the compiler analyzes the generated code and makes optimizations to improve its
performance. The compiler may perform optimizations such as constant folding,
loop unrolling, and function inlining.

Syntax vs Semantics in Programming Languages


Syntax refers to the structure of the elements of a language based on its type. On the
other hand, semantics are all about the meaning.

Something written syntactically correctly in a language can be completely


meaningless. And no text can be meaningful if its syntax is incorrect.

The following code is syntactically correct but semantically wrong because it's not
possible to reassign something to a constant variable:

const name = "Palash";

name = "Akash";

The following is syntactically incorrect and thus does not even have any chance to be
semantically correct.

"Palash" = const name;"Akash" = name;

Terminals and Non-Terminals


BNF/EBNF is usually used to specify the grammar of a language. Grammar is a set
of rules (also called production rules). Here language refers to nothing but a set of
strings that are valid according to the rules of its grammar.

A BNF/EBNF grammar description is an unordered list of rules. Rules are used to


define symbols with the help of other symbols.

You can think of symbols as the building blocks of grammar. There are two kinds of
symbols:

 Terminal (or Terminal symbol): Terminals are strings written within quotes. They
are meant to be used as they are. Nothing is hidden behind them. For
example "freeCodeCamp" or "firefly".
 Non-terminal (or Non-terminal symbol): Sometimes we need a name to refer to
something else. These are called non-terminals. In BNF, non-terminal names are
written within angle brackets (for example <statement>), while in EBNF they don't
usually use brackets (for example statement).
What is BNF?
BNF stands for Backus–Naur Form which resulted primarily from the contributions
of John Backus and Peter Naur.

<something> ::= "content"


Each rule in BNF (also in ENBF) has three parts:

 Left-hand side: Here we write a non-terminal to define it. In the above example, it
is <something>.
 ::=: This character group separates the Left hand side from Right hand side. Read
this symbol as "is defined as".
 Right-hand side: The definition of the non-terminal specified on the right-hand side.
In the above example, it's "content".
The above <something> is just one thing fixed thing. Let's now see all the ways you
can compose a non-terminal.

How to compose a non-terminal


BNF offers two methods to us:

 Sequencing
 Choice
You can just write a combination of one or more terminals or non-terminals in a
sequence and the result is their concatenation, with non-terminals being replaced by
their content. For example, you can express your breakfast in the following ways:

<breakfast> ::= <drink> " and biscuit"<drink> ::= "tea"

It means the only option for breakfast for you is "tea and biscuit". Note that here, the
order of symbols is important.

<breakfast> ::= <drink> " and biscuit"<drink> ::= "tea" | "coffee"

The | operator indicates that the parts separated by it are choices.

What is EBNF?

digits = digit { digit }digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"

The braces above mean that its inner part may be repeated 0 or more times. It frees
your mind from getting lost in recursion.

One interesting fact is that everything you can express in EBNF can also be expressed
in BNF.

EBNF usually uses a slightly different notation than BNF. For example:

 ::= becomes just =.


 There are no angle brackets around non-terminals.

For concatenation, instead of juxtaposition, some prefer `,` to be more explicit.


However, I will not use it here.

Don't assume that these styles to be universal. There are several variants of them and
they are usually clear from the context. The more important thing to focus on is the
new operations it offers like the braces we've seen above.

EBNF extends BNF by adding the following 3 operations:

 Option
 Repetition
 Grouping
Option
Option uses square brackets to make the inner content optional. Example:

thing = "water" [ "melon" ]

So the above thing is either water or watermelon.

Repetition
Curly braces indicate the inner content may be repeated 0 or more times. You have
already seen a good example of it above. Below is a very simple one just to make the
idea solid in your mind:

long_google = "Goo" { "o" } "gle"

So "Google", "Gooogle", "Gooooooogle" are all valid long_google non-terminal.

Grouping
Parentheses can be used to indicate grouping. It means everything they wrap can be
replaced with any of the valid strings that the contents of the group represent
according to the rules of EBNF. For example:

fly = ("fire" | "fruit") "fly"

Here fly is either "firefly" or "fruitfly".

With BNF we could not do that in one line. It would look like the following in BNF:
<fly> ::= <type> "fly"

<type> ::= "fire" | "fruit"

Context free grammar

Context free grammar is a formal grammar which is used to generate all possible
strings in a given formal language.

Context free grammar G can be defined by four tuples as:

1. G= (V, T, P, S)

Where,

G describes the grammar

T describes a finite set of terminal symbols.

V describes a finite set of non-terminal symbols

P describes a set of production rules

S is the start symbol.

Production rules:

1. S → aSa
2. S → bSb
3. S → c

Now check that abbcbba string can be derived from the given CFG.

1. S ⇒ aSa
2. S ⇒ abSba
3. S ⇒ abbSbba
4. S ⇒ abbcbba
By applying the production S → aSa, S → bSb recursively and finally applying the
production S → c, we get the string abbcbba.

Derivation

Derivation is a sequence of production rules. It is used to get the input string through
these production rules. During parsing we have to take two decisions. These are as
follows:

o We have to decide the non-terminal which is to be replaced.


o We have to decide the production rule by which the non-terminal will be
replaced.

We have two options to decide which non-terminal to be replaced with production


rule.

Left-most Derivation

In the left most derivation, the input is scanned and replaced with the production rule
from left to right. So in left most derivatives we read the input string from left to right.

Example:

Production rules:

1. S = S + S
2. S = S - S
3. S = a | b |c

Input:

a-b+c

The left-most derivation is:

1. S = S + S
2. S = S - S + S
3. S = a - S + S
4. S = a - b + S
5. S = a - b + c

Right-most Derivation
In the right most derivation, the input is scanned and replaced with the production rule
from right to left. So in right most derivatives we read the input string from right to
left.

Example:

1. S = S + S
2. S = S - S
3. S = a | b |c

Input:

a-b+c

The right-most derivation is:

1. S = S - S
2. S = S - S + S
3. S = S - S + c
4. S = S - b + c
5. S = a - b + c
Parse tree

o Parse tree is the graphical representation of symbol. The symbol can be


terminal or non-terminal.
o In parsing, the string is derived using the start symbol. The root of the parse
tree is that start symbol.
o It is the graphical representation of symbol that can be terminals or non-
terminals.

The parse tree follows these points:

o All leaf nodes have to be terminals.


o All interior nodes have to be non-terminals.
o In-order traversal gives original input string.

Example:

Production rules:
1. T= T + T | T * T
2. T = a|b|c

Input:

a*b+c

Step 1:

Step 2:

Step 3:

Step 4:
Step 5:

Ambiguity

A grammar is said to be ambiguous if there exists more than one leftmost derivation
or more than one rightmost derivative or more than one parse tree for the given input
string. If the grammar is not ambiguous then it is called unambiguous.

Example:

1. S = aSb | SS
2. S = ∈

For the string aabb, the above grammar generates two parse trees:
If the grammar has ambiguity then it is not good for a compiler construction. No
method can automatically detect and remove the ambiguity but you can remove
ambiguity by re-writing the whole grammar without ambiguity.

What is BNF?
BNF stands for Backus–Naur Form which resulted primarily from the contributions
of John Backus and Peter Naur.

Below is an example of a simple production rule in BNF:

<something> ::= "content"

Each rule in BNF (also in ENBF) has three parts:

 Left-hand side: Here we write a non-terminal to define it. In the above example, it
is <something>.
 ::=: This character group separates the Left hand side from Right hand side. Read
this symbol as "is defined as".
 Right-hand side: The definition of the non-terminal specified on the right-hand side.
In the above example, it's "content".
The above <something> is just one thing fixed thing. Let's now see all the ways you
can compose a non-terminal.

How to compose a non-terminal


BNF offers two methods to us:

 Sequencing
 Choice
You can just write a combination of one or more terminals or non-terminals in a
sequence and the result is their concatenation, with non-terminals being replaced by
their content. For example, you can express your breakfast in the following ways:

<breakfast> ::= <drink> " and biscuit"<drink> ::= "tea"


It means the only option for breakfast for you is "tea and biscuit". Note that here, the
order of symbols is important.

Let's say someday you want to drink coffee instead of tea. In this case, you can
express your possible breakfast items like below:

<breakfast> ::= <drink> " and biscuit"<drink> ::= "tea" | "coffee"

The | operator indicates that the parts separated by it are choices. there is no difference
between "tea" | "coffee and "coffee" | "tea".

As a simple example let's see how you express one or more digits in BNF:

<digits> ::= <digit> | <digit> <digits><digit> ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" |
"7" | "8" | "9"

What is EBNF?
BNF is fine, but sometimes it can become verbose and hard to interpret. EBNF (which
stands for Extended Backus–Naur Form) may help you in those cases. For example,
the previous example can be written in EBNF like below:

digits = digit { digit }digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"

The braces above mean that its inner part may be repeated 0 or more times. It frees
your mind from getting lost in recursion.

One interesting fact is that everything you can express in EBNF can also be expressed
in BNF.

EBNF usually uses a slightly different notation than BNF. For example:

 ::= becomes just =.


 There are no angle brackets around non-terminals.

For concatenation, instead of juxtaposition, some prefer `,` to be more explicit.


However, I will not use it here.

Don't assume that these styles to be universal. There are several variants of them and
they are usually clear from the context. The more important thing to focus on is the
new operations it offers like the braces we've seen above.

EBNF extends BNF by adding the following 3 operations:


 Option
 Repetition
 Grouping
Option
Option uses square brackets to make the inner content optional. Example:

thing = "water" [ "melon" ]

So the above thing is either water or watermelon.

Repetition
Curly braces indicate the inner content may be repeated 0 or more times. You have
already seen a good example of it above. Below is a very simple one just to make the
idea solid in your mind:

long_google = "Goo" { "o" } "gle"

So "Google", "Gooogle", "Gooooooogle" are all valid long_google non-terminal.

Grouping
Parentheses can be used to indicate grouping. It means everything they wrap can be
replaced with any of the valid strings that the contents of the group represent
according to the rules of EBNF. For example:

fly = ("fire" | "fruit") "fly"

Here fly is either "firefly" or "fruitfly".

With BNF we could not do that in one line. It would look like the following in BNF:

<fly> ::= <type> "fly"

<type> ::= "fire" | "fruit"

Attribute Grammar

Attribute grammar is a special form of context-free grammar where some additional


information (attributes) are appended to one or more of its non-terminals in order to
provide context-sensitive information. Each attribute has well-defined domain of
values, such as integer, float, character, string, and expressions.
Attribute grammar is a medium to provide semantics to the context-free grammar and
it can help specify the syntax and semantics of a programming language. Attribute
grammar (when viewed as a parse-tree) can pass values or information among the
nodes of a tree.

Example:

E → E + T { [Link] = [Link] + [Link] }

The right part of the CFG contains the semantic rules that specify how the grammar
should be interpreted. Here, the values of non-terminals E and T are added together
and the result is copied to the non-terminal E.

Semantic attributes may be assigned to their values from their domain at the time of
parsing and evaluated at the time of assignment or conditions. Based on the way the
attributes get their values, they can be broadly divided into two categories :
synthesized attributes and inherited attributes.

Synthesized attributes

These attributes get values from the attribute values of their child nodes. To illustrate,
assume the following production:

S → ABC

If S is taking values from its child nodes (A,B,C), then it is said to be a synthesized
attribute, as the values of ABC are synthesized to S.

As in our previous example (E → E + T), the parent node E gets its value from its
child node. Synthesized attributes never take values from their parent nodes or any
sibling nodes.

Inherited attributes

In contrast to synthesized attributes, inherited attributes can take values from parent
and/or siblings. As in the following production,

S → ABC

A can get values from S, B and C. B can take values from S, A, and C. Likewise, C
can take values from S, A, and B.

Expansion : When a non-terminal is expanded to terminals as per a grammatical rule


Basic Data Types

The data type specifies the size and type of information the variable will store.

In this tutorial, we will focus on the most basic ones:

Data Type Size Description

int 2 or 4 bytes Stores whole numbers, without decimals

float 4 bytes Stores fractional numbers, containing one or more decimals. Sufficien
6-7 decimal digits

double 8 bytes Stores fractional numbers, containing one or more decimals. Sufficien
15 decimal digits

char 1 byte Stores a single character/letter/number, or ASCII values

Basic Format Specifiers

There are different format specifiers for each data type. Here are some of them:

Format Specifier Data Type

%d or %i int

%f or %F float

%lf double
%c char

%s Used for strings (text), which you will learn more about in a late

Primitive Data Types

A primitive data type specifies the size and type of variable values, and it has no
additional methods.

There are eight primitive data types in Java:

Data Type Size Description

byte 1 byte Stores whole numbers from -128 to 127

short 2 bytes Stores whole numbers from -32,768 to 32,767

int 4 bytes Stores whole numbers from -2,147,483,648 to 2,147,483,

long 8 bytes Stores whole numbers from -9,223,372,036,854,775,808


9,223,372,036,854,775,807

float 4 bytes Stores fractional numbers. Sufficient for storing 6 to 7 de

double 8 bytes Stores fractional numbers. Sufficient for storing 15 decim

boolean 1 bit Stores true or false values

char 2 bytes Stores a single character/letter or ASCII values

Union Types

A union is a type whose variables may store different type values at different
times during program execution.

Record vs Union

struct sample

int x;
float y;

char z;

};

union sample

int x;

float y;

char z;

};

union sample x;

Free Unions vs Discriminated Unions

C and C++ provide union constructs in which there is no language support


for type checking.

The unions in these languages are called free unions, because programmers
are allowed complete freedom from type checking in their use.

union sample

int a;

float b;

};
union sample myunion;

float x;

myunion.a = 27;

x = myunion.b;

Type checking of unions requires that each union construct include a type
indicator. Such an indicator is called a tag, or discriminant, and a union with
a discriminant is called a discriminated union.

The first language to provide discriminated unions was ALGOL 68. They are
now supported by Ada, ML, Haskell, and F#.

Unions in Ada

e.g.

type Shape is (Circle, Triangle, Rectangle);

type Colors is (Red, Green, Blue);

type Figure (Form : Shape) is

record

Filled : Boolean;

Color : Colors;

case Form is

when Circle =>

Diameter : Float;

when Triangle =>

Left_Side : Integer;
Right_Side : Integer;

Angle : Float;

when Rectangle =>

Side_1 : Integer;

Side_2 : Integer;

end case;

end record;

Figure_1 : Figure;

Figure_2 : Figure(Form => Triangle);

Here,

Figure_1 is unconstrained variant record.

Figure_2 is constrained variant record.

Unions in F#

type intReal =

| IntValue of int

| RealValue of float;;

A compile-time descriptor for a discriminated union


type Node (Tag : Boolean) is

record

case Tag is

when True => Count : Integer;

when False => Sum : Float;

end case;

end record;

Creating Pointers

You learned from the previous chapter, that we can get the memory address of a
variable with the reference operator &:

Example

int myAge = 43; // an int variable

printf("%d", myAge); // Outputs the value of myAge (43)


printf("%p", &myAge); // Outputs the memory address of myAge (0x7ffe5367e044)

A pointer is a variable that stores the memory address of another variable as its
value.

A pointer variable points to a data type (like int) of the same type, and is created
with the * operator.

The address of the variable you are working with is assigned to the pointer:

Example
int myAge = 43; // An int variable
int* ptr = &myAge; // A pointer variable, with the name ptr, that stores the address of
myAge

// Output the value of myAge (43)


printf("%d\n", myAge);

// Output the memory address of myAge (0x7ffe5367e044)


printf("%p\n", &myAge);

// Output the memory address of myAge with the pointer (0x7ffe5367e044)


printf("%p\n", ptr);

Dereference

In the example above, we used the pointer variable to get the memory address of a
variable (used together with the & reference operator).

You can also get the value of the variable the pointer points to, by using the * operator
(the dereference operator):

Example

int myAge = 43; // Variable declaration


int* ptr = &myAge; // Pointer declaration

// Reference: Output the memory address of myAge with the pointer (0x7ffe5367e044)
printf("%p\n", ptr);

// Dereference: Output the value of myAge with the pointer (43)


printf("%d\n", *ptr);

 When used in declaration (int* ptr), it creates a pointer variable.


 When not used in declaration, it act as a dereference operator.

List

Lists are used to store multiple items in a single variable.

Lists are one of 4 built-in data types in Python used to store collections of data, the
other 3 are Tuple, Set, and Dictionary, all with different qualities and usage.

Lists are created using square brackets:

Example
Create a List:

thislist = ["apple", "banana", "cherry"]


print(thislist)

List Items

List items are ordered, changeable, and allow duplicate values.

List items are indexed, the first item has index [0], the second item has index [1] etc.

Ordered

When we say that lists are ordered, it means that the items have a defined order, and
that order will not change.

If you add new items to a list, the new items will be placed at the end of the list.

Changeable

The list is changeable, meaning that we can change, add, and remove items in a list
after it has been created.

Allow Duplicates

Since lists are indexed, lists can have items with the same value:

Example

Lists allow duplicate values:

thislist = ["apple", "banana", "cherry", "apple", "cherry"]


print(thislist)

List Length

To determine how many items a list has, use the len() function:

Example

Print the number of items in the list:


thislist = ["apple", "banana", "cherry"]
print(len(thislist))

Try it Yourself »

List Items - Data Types

List items can be of any data type:

Example

String, int and boolean data types:

list1 = ["apple", "banana", "cherry"]


list2 = [1, 5, 7, 9, 3]
list3 = [True, False, False]

A list can contain different data types:

Example

A list with strings, integers and boolean values:

list1 = ["abc", 34, True, 40, "male"]

Tuple

Tuples are used to store multiple items in a single variable.

Tuple is one of 4 built-in data types in Python used to store collections of data, the
other 3 are List, Set, and Dictionary, all with different qualities and usage.

A tuple is a collection which is ordered and unchangeable.

Tuples are written with round brackets.

Example

Create a Tuple:
thistuple = ("apple", "banana", "cherry")
print(thistuple)

Tuple Items

Tuple items are ordered, unchangeable, and allow duplicate values.

Tuple items are indexed, the first item has index [0], the second item has
index [1] etc.

Ordered

When we say that tuples are ordered, it means that the items have a defined order, and
that order will not change.

Unchangeable

Tuples are unchangeable, meaning that we cannot change, add or remove items after
the tuple has been created.

Allow Duplicates

Since tuples are indexed, they can have items with the same value:

Example

Tuples allow duplicate values:

thistuple = ("apple", "banana", "cherry", "apple", "cherry")


print(thistuple)

You might also like