C Programming
Streaming Video Lectures On-Demand
Colin Archibald, Ph.D.
Valencia Community College
Orlando, FL 32811
This is a complete course in the C language. It uses the the free programming tools
from Microsoft - Visual C++ Express.
It is
intended for students who have some background in computer programming.
Beginners are referred to the video lecture course Computer
Programming Concepts.
Students completing this course will have a solid understanding of the C
language, including data types, control structures, operators, arrays,
pointers, strings, structs, and file I/O.
Please send feedback to: ColinArchibald@acm.org
These videos have moved to YouTube.
Updates will only be posted there. Here is a link to the
PlayList:
https://www.youtube.com/playlist?list=PL16462912149C15F6
|
|
|
|
Power Point slides that are used in these
Video Lectures are available here:
Download PowerPoint Slides
|
|
-
nSyntax – rules for writing
a computer program in a particular language.
-
nErrors in Syntax are called
compile-time errors because they are reported by the compiler.
-
nOutput – information that
originates in the program and is output to a screen, or a file.
-
nYou must
get a simple program to run at this point – all subsequent segments
depend on your ability to experiment with the concepts that
are introduced.
|
|
-
Variables and data types
-
Variable naming rules and conventions
-
Assignment and arithmetic operators, including modulus
-
Integer division – operators also have a data type
|
|
-
The char data type can be used for small numbers, or the ASCII
code of a character
-
The
sizeof
operator can be used to determine the size of a variable, or a
data type.
-
The choice of a data type depends on whether you need character,
real or integer data and how large the values might be that you
are computing with.
-
The
unsigned
modifier allows you to use an integer data type for positive
values only.
-
Mixed data type expressions, including cast operators, apply to
these new data types in the same way as with
int
and
double.
-
There are different versions of C that have other data types.
C99 is the most recent standard.
-
Operators and literals have a data type.
Operators work on operands of the same type.
-
The data type of the operators is determined at the time the
operator is to be executed
-
The type of the operator is determined by the type of the
operands
-
C will promote, to avoid losing data, programmers should demote
explicitly
-
Type casting is used to temporarily change the type of a value
for the purpose of evaluating an expression
|
|
-
Output information going from the program to the user
-
Input information going from the user to the program
-
printf and scanf
-
Escape characters are used to control the position of the output
cursor, and to output some special characters
-
% sequences, correspond to the variables that are being input or
output, and can be modified for formatting the output.
-
You can specify the data type of the input, and the type and
format of the output.
-
Use the documentation for your compiler – search for "Format
Specification Fields."
-
Don’t forget the & on the variable name for input!
-
A "Prompt" is a message that tells the user what the program is
expecting them to enter.
|
|
-
Selection – execute lines of code based on a condition
-
Relational operators are used to compare two things with a
result of TRUE or FALSE
-
if
statements are used to change the flow of control, the lines of
code that will execute
-
if
statements may have an associated
else
-
if
and
else
control one statement or one "compound statement" {
}
-
A
switch
can be used to selectively execute some statements based on the
value of a variable, or expression.
-
The break; statement prevents the execution
from 'bleeding' into the next case.
-
The default case is optional, and if present is executed if none
of the other cases match.
-
The cases must all be unique, and constant.
-
Switch cannot be used to compare doubles, or to express a range
of values – sometimes you need to use multiple if-else
statements.
|
|
-
There are three logical operators:
And
&&
Or
||
Not
!
-
Can be used to express more interesting conditions
-
Precedence Not, And, Or
-
True and False are numeric in C.
Zero is False, Non-zero is True
-
Short-circuit behavior
&& ||
-
No short-circuit
&
|
-
New Operator: compound Assignment
+=
a = a + b;
a += b; often
used for accumulators
-
New Operator:
increment ++
decrement
--
-
Pre, and post increment and decrement
-
++
and
--
break the usual rules of precedence.
|
|
-
Sequence, Selection, Repetition (looping)
-
Counter and Sentinel controlled loops
1. Start
2. Stop 3. Get
there
-
Counter variables, Accumulator variables
-
Use a test case, and step through the code in the debugger to
see its behavior
-
while
-
Pre-test loop
-
Often used for sentinel controlled loops
-
do-while
-
Post-test loop - generally frowned upon, but may be useful in
some circumstances – when you learn the status of the stop
condition inside the body of the loop.
-
for
-
Used for counter controlled loops.
Very commonly used.
|
|
-
#define is used to create named constants – these are not
variables.
-
Always have some test cases that demonstrate the expected result
for the problem you are solving.
-
Develop the solutions progressively.
-
Compile frequently – isolate compiler errors.
-
Use the debugger to find logic errors – the program cannot hide
anything from you.
-
Use
for
loops for counter controlled loops.
-
Use short-cut operators where possible.
-
Choose variable names carefully.
-
srand, and rand are function in the stdlib that generate random
numbers.
|
|
-
The indexes of an array start with 0 (zero).
-
Eg. an array with 10 elements has indexes 0 – 9
-
A one-dimensional array is sometimes called a "List"
-
A 2-D array is a "Table"
-
Arrays can be of any data type – elements are used as if they
are simple variables of that type
-
A defined constant can be used to make your program easier to
modify / maintain.
for ( i = 0; i < SIZE; i++)
{ // loop to each element
array[i]
= …
|
|
-
Programming with arrays is easier if you use a picture to help
you think about the data, and the loops that access the elements
of the array.
-
Program progressively.
Compile and run the code often.
-
Always have at least one good test case that is the target
result.
-
Good variable names are more important when the problems become
more complex.
|
|
-
Hierarchy charts are used to organize anything complex including
C programs
-
There are many functions already defined for you, eg. scanf,
printf.
-
We define functions to 'divide and conquer' – solve more complex
problems.
-
Define functions that achieve 1 (one) well define objective –
name the function carefully
-
General form for defining a function:
returnDatatype
functionName( type parameter, type parameter) {
body of function
}
-
General form for calling a function:
resultReturned
= functionName(
argument, argument );
|
|
-
Determining how to break the problem into functions - can take
practice.
-
Functions should do only one thing – and should have some
documentation that describes what it does.
-
Work progressively: solve small problems - and only move on when
those are correct.
-
Decide what information needs to be passed into the function and
what information needs to be passed back to the caller also
requires practice.
"coupling"
-
Functions should be created so that they can be re-used in other
applications.
-
The syntax for passing arrays to functions is tricky.
Until you have practiced this several times, keep a working
example nearby for reference.
|
|
-
There are many well known algorithms that solve common problems.
We looked at the bubble sort, and the binary search
-
Nested Loops.
Write
pseudocode to help with a solid understanding.
-
Some programmers use psuedocode as an intermediate step between
understanding the problem, and writing the code.
-
It takes some practice to get used to nested loops that use
arrays.
-
Use a picture of the arrays.
Walk through code using a pencil.
-
Bubble sort is only one algorithm that can be used for sorting.
(There are many: selection sort, insertion sort, quick sort,
etc.)
-
A binary search is much more efficient than a linear search, but
the data must be sorted for a binary search to work.
There is a relationship between sorting and searching
algorithms.
|
|
-
A pointer is the address of a byte in RAM
-
A pointer, address, and reference are the same thing
-
&
is the "address of" operator.
Use it to get the address of a variable
-
int*
is a new data type that can hold the address of an
int
-
double*, char*, float*, long long*
are all data types that can hold addresses
-
* is the dereference, or indirection, operator.
-
The * operator is not the same as the one in the data type, but
they are related because you use the * operator on pointer
types.
-
When you dereference a pointer, you use the piece of memory that
is pointed at by that pointer
|
|
A. Using the return
statement is information coming OUT of the function.
B. Pass by value is
information going only IN to the function.
C. Pass by reference is
information going IN and coming OUT of the function.
-
Pointers are useful.
-
scanf("%i",
&a); // pass the address
of a to scanf
-
A function can pass information back to the caller by using an
address
-
The caller passes the address of a variable to the function
-
The function uses a pointer data type for the parameter, so that
it can receive the address from the caller
-
A pointer, address and reference are the same thing
-
When you dereference a pointer, you use the piece of memory that
is pointed at by that pointer
|
|
- Watch what is going on in the debugger.
- Draw a picture of the data.
- Make some comments in the code regarding the
information going in to and coming out of the function.
- Make the functions achieve only one goal.
If there are more than 5 parameters, the function might be too
complex.
|
|
-
The name of the array contains a pointer to the first element in the
array.
-
Array elements are stored contiguously in memory.
-
Arrays can be manipulated using subscript syntax, or pointer-offset
syntax.
-
Pointer arithmetic - add 1 to a double pointer increases the address
by 8.
-
Be very careful about going past the end of an array.
|
|
-
A string is an array of char's terminated with a null character.
-
Using "
" in the syntax of C results in a literal of data type char*
-
Using "
" automatically adds the null character, so this char* is a
string
-
Functions that process strings, look for the null character.
If there is no null character present, the function will keep
looking at bytes beyond the end of the array.
-
String.h contains the prototypes for many standard functions
that can be used to manipulate strings.
|
|
-
Draw pictures of the data so you can refer back to them when
programming
-
You can't work with data if you don't know what it looks like!
-
Work progressively.
Get small things working and put them together.
-
Use the debugger all the time when using arrays and pointers
|
|
-
User Defined Types (UDT) in C are created with the keyword 'struct'
-
There are different ways to create a struct, and it's easy to
confuse them.
-
Create new types so that the code can express the solution to
the problem in the same terms the problem is described.
-
Adopt a convention for capitalization
-
This is the basis for object-oriented programming, but it is not
considered object oriented.
-
The "things" that are created, are sometimes called "objects,"
but OO languages have the capability to add executable code to
the data types.
|
|
-
Structs are passed by value unless a pointer is used to pass
them by ref
-
Anything passed by value – there is a copy of the data used by
the function
-
It is often better to pass structs by ref even if the data is
not going to be changed – the size of the pointer is 4 bytes,
the data can be quite large
-
Use the keyword const to prevent programmers from changing the
data in a struct inappropriately.
-
A pointer to a struct can use the
->
operator to access the component parts of the struct.
The
->
operator is a shortcut for the more awkward (*p).part
syntax
-
Structs can be composed of other structs to make more
interesting data structures
-
sizeof
can be used to count the number of bytes in a struct.
|
|
-
Structs are used to represent one "thing"
-
Multiple instances of a struct can be stored in an array and
manipulated similarly to arrays of primitive data types.
-
A common error is to attempt to move an array of characters
(string) with the assignment operator.
-
Draw pictures of the data that is being manipulated.
|
|
-
Memory for variables is allocated from either the stack or the
heap.
-
The stack is also called the "call stack" – each function's
local variables are available during the execution of the lines
of code in that function.
-
Memory for local variables is automatically returned to the free
space within the stack when the functions end.
"Automatic" variables.
-
Stack size can be set in the IDE.
If it is set too small, the program can end with a "stack
overflow" error.
|
|
-
Dynamic memory allocation can be done one object at a time, or
for an entire array of structs.
-
Choosing how to do the memory management depends on the nature
of the application.
-
Some applications need to grow and shrink their memory usage
continually, while some have relatively static memory
requirements.
-
Draw pictures of the data!
|
|
-
Files can be thought of as a sequence of bytes on an external
storage medium
-
Files can be text or binary
-
Reading text files can be complicated.
Read the descriptions of the format specifiers
carefully. Don't guess!
Incorrect format specifiers will do something, and might
appear to work, but the behavior is really indeterminate.
-
It is impossible to read a binary file without knowing what the
bytes represent – the data types and their locations in the
file.
-
Binary files can be read and written with large blocks of data
or a byte at a time using fread and fwrite
-
You can mix binary and text file access, but it shouldn't be
done.
The behavior is indeterminate, and tends to result in guessing
what the code will do, and then changing it – over and over.
|
|
-
Don't mix the use of functions intended for Text and Binary
files.
-
Keep a reference for the description of the format specifiers
handy!
-
Close the files as soon as you are done with them.
-
Draw pictures of a binary file – use graph paper to help keep
track of the bytes.
-
Don't guess!
It will take forever to work with files using trial and error,
and the result might not be doing exactly what you expect it to
be doing.
|
Appendix
|
|
|
- How to get a free copy of Visual C++ Express
2010
- Registering your Visual C++
- Testing with Hello World
|
|
-
Decimal number system, base 10
-
Binary number system, base 2
-
A Byte has 8 bits
-
One byte can hold values 0 – 255
-
Bytes can be combined to represent larger values.
-
Converting from decimal to binary, and binary to decimal.
|
|
-
Hexadecimal (hex) uses Base 16.
-
Hex is an easier way to represent binary numbers.
-
4 bits can be represented in one hex place
-
Conversion between binary
and hex is very quick.
-
All programmers must know how to represent
numbers in binary and hex.
|