Show Lecture.BasicSyntax as a slide show.
CS253 Basic Syntax
The main
function
int main() {
return 0;
}
- This is a complete C program.
main()
is a function, not a method.
- Methods are functions inside of classes.
- methods ⊂ functions
- All methods are functions.
- Not all functions are methods.
- Unlike Java, C++ doesn’t have to have a class,
so
main()
is a function.
- We sometimes call this a free function.
- It’s not part of a
class
. It’s free!
Slightly More
Here’s a complete C++ program that creates some output:
#include <iostream>
using namespace std;
int main() {
cout << "Hello, world!\n";
return 0;
}
Hello, world!
- You need
#include <iostream>
to access I/O facilities.
- You need
using namespace std;
because you just have to,
for the moment.
How Examples Work
Many examples in these slides are just snippets of code:
cout << "How do you do?" << '\n';
How do you do?
- They’re turned into complete programs via webserver magic.
- You still need
#include <iostream>
.
- You still need
using namespace std;
.
- You still need
int main() {
.
- The
return 0;
is optional in main()
,
which is stoooopid, so I always include it
(unless I run out of slide space).
- You still need the
}
to close main
.
The main
function
Here’s the other valid definition of main()
:
int main(int argc, char *argv[]) {
// Display all arguments, including program name.
for (int i=0; i<argc; i++)
cout << "argv[" << i << "]: \"" << argv[i] << "\"\n";
return 0;
}
argv[0]: "./a.out"
That is all
Don’t even ask about void main()
.
It does not exist.
⚠ ☢ ☣ ☠
Return value
main()
returns an int
, a success/failure code to the invoker.
- 0: success
- >0: failures of various sorts.
Return different values for different failures, e.g.:
- 1: “not enough arguments”
- 2: “can’t read the file”
- 3: “bad data in file”
- <0: That’s just weird. Only the least-significant
eight bits of the return value count, so −1 ⇒ 255.
Arguments
int main(int argc, char *argv[])
argc
: number of arguments, including the program name as argv[0]
.
argc
stands for “argument count”.
argv
: array of C-style strings, corresponding to program arguments.
argv
stands for “argument vector”.
argc
is always ≥ 1, except in strange embedded environments.
argv
is always an array of C strings, even if you type
arguments that look like numbers or something else.
Arguments example
% cat ~cs253/Example/show-args.cc
#include <iostream>
using namespace std;
int main(int argc, char *argv[]) {
for (int i=0; i<argc; i++)
cout << "argv[" << i << "]: " << argv[i] << '\n';
}
% g++ -Wall ~cs253/Example/show-args.cc -o foobar
% ./foobar This is "CS253: best class ever!"
argv[0]: ./foobar
argv[1]: This
argv[2]: is
argv[3]: CS253: best class ever!
argv[0]
contains the real program name, as executed.
Compatibility
- Why is
argv[]
an array of char *
?
Surely they should be C++ strings?
- C++ strings didn’t exist in C.
- Why is
argv[]
an array of char *
?
Surely they should be const char *
?
- C didn’t have
const
when this was all invented.
- It’s your memory, you should be able to change it.
Basic types
C++ has a number of built-in types:
void
bool
(not boolean
)
char
(not byte
) / short
/ int
/ long
/ long long
unsigned
versions of those
float
/ double
/ long double
size_t
(an alias for an unsigned integral type)
Sizes
- The sizes of types are determined by the implementation.
- On my home machine,
sizeof(long)==4
, but sizeof(long)==8
on
many computers.
- The C++ standard defines minimum sizes for types:
short
, int
: 16 bits
long
: 32 bits
long long
: 64 bits
sizeof(char) == 1
sizeof(char)
≤ sizeof(short)
≤ sizeof(int)
≤
sizeof(long)
≤ sizeof(long long)
- Pointer types often vary.
sizeof(int *)==4
on a 32-bit machine
sizeof(int *)==8
on a 64-bit machine
Qualifiers
Qualifiers (const
, constexpr
, static
) modify existing types.
const auto id = getpid();
constexpr double PI = 3.14159265;
static long csuid = 800000000;
cout << id << ' ' << PI << ' ' << ++csuid << '\n';
1469594 3.14159 800000001
const
: not allowed to change this
constexpr
: compile-time constant, never changes
static
: longer-than-function lifetime, private if a global
Derived types
Via pointers & arrays, a vast number of derived types exist:
int a[10]; // 10 ints
int *b; // A pointer to any number of ints
int *c[10]; // An array of 10 pointers-to-ints
int (*d)[10]; // A pointer to an array of 10 ints
If you find complex types confusing, build intermediate types
with typedef
:
typedef float cash; // cash is now a synonym for float (note the order)
typedef int *intp; // New type intp, a pointer to ints
intp e[10]; // An array of 10 such pointers
Aliases via typedef
With typedef
, you can create an alias for an existing type.
It does not create a new type.
typedef int counter; // typedef old new;
counter c = 42;
cout << c << '\n';
42
To use typedef
, think of it in two steps:
- Declare a variable:
int counter;
- Slap
typedef
in front of it: typedef int counter;
Aliases via using
We’re familiar with using
from using namespace std;
but it
can also be used to make aliases for types:
using counter = int; // using new = old;
counter c = 43;
cout << c << '\n';
43
Lazy Programmer’s Declaration
Or, you can just declare variables with auto
(which is not a type!):
auto i=4; // an int
auto r=3.45; // a double
cout << i+r << '\n';
7.45
But you must initialize the variable, so that the compiler knows
what type to make it:
auto foo;
foo = 'x';
c.cc:1: error: declaration of 'auto foo' has no initializer
Why auto
is useful
Consider this common code:
pid_t p1 = getpid();
cout << "My process id is " << p1 << '\n';
My process id is 1469598
pid_t
is an alias (via typedef
) for short
, int
,
long
, or long long
. It can hold whatever getpid()
produces. Many functions have a related type for their return value,
and they clutter up your brain.
auto p2 = getpid();
cout << "My process id is " << p2 << '\n';
My process id is 1469599
What type is p2
? I don’t care.
It’s the type that getpid()
returned.
Control Flow
if
switch
while
do
… while
for
- range-based
for
if
int x = 42;
if (x < 100)
cout << "This is true\n";
This is true
double pi = 3.14159265;
if (pi*pi < 10) {
cout << "Good--math hasn’t changed.\n";
}
else
cout << "Can’t even trust math any more‽\n";
Good--math hasn’t changed.
if
An if
statement can contain a variable declaration.
The condition succeeds if the value is true
(non-zero):
if (const char *p = getenv("PATH"))
cout << "PATH environment variable is " << p << '\n';
PATH environment variable is /bin
The scope of the new variable is restricted to the if
statement,
even without braces.
switch
auto now = time(nullptr);
switch (localtime(&now)->tm_hour % 12) {
case 2: case 3: case 5: case 7: case 11:
cout << "Prime time!\n"; break;
default:
cout << "Composite time!\n"; break;
case 1:
cout << "Bed time!\n";
}
Prime time!
switch
on integral types
(char
, short
, int
, long
, …).
- You can’t
switch
on floating-point types or strings.
- The
break
prevents flow into the next case
.
while
char c = 'f';
while (c < 'x')
cout << c++ << ' ';
f g h i j k l m n o p q r s t u v w
do … while
double age = 0.0;
do {
age += 1.0/13.0;
cout << age << '\n';
} while (age < 1);
0.0769231
0.153846
0.230769
0.307692
0.384615
0.461538
0.538462
0.615385
0.692308
0.769231
0.846154
0.923077
1
1.07692
Isn’t that one too many iterations?
do … while
double age = 0.0;
cout << fixed << setprecision(16);
do {
age += 1.0/13.0;
cout << age << '\n';
} while (age < 1);
0.0769230769230769
0.1538461538461539
0.2307692307692308
0.3076923076923077
0.3846153846153846
0.4615384615384616
0.5384615384615385
0.6153846153846154
0.6923076923076923
0.7692307692307692
0.8461538461538460
0.9230769230769229
0.9999999999999998
1.0769230769230766
- Printing more digits shows that
floating-point numbers are inherently imprecise.
for
for (int i=0; i<5; i++)
cout << i;
01234
range-based for
int a[] = {11,22,33};
for (int v : a)
cout << v << ", ";
11, 22, 33,
vector<short> b = {101, 202, 303, 404};
for (short &n : b)
n *= 3;
for (const short n : b)
cout << n << ", ";
303, 606, 909, 1212,
for (auto q : {12, 34, 56, 78})
cout << q << " and ";
12 and 34 and 56 and 78 and
Variable declaration
The condition of an if
, switch
, or while
can be a declaration.
const char show[] = "Star Trek";
if (const char *p = strchr(show, 'T'))
cout << "Found it at location " << p-show << '\n';
Found it at location 5
false
, 0
, and a null pointer are false,
everything else is true.