Fundamentals of C
Program Structure
Constants
Variables
Assignment Statements
Standard Output
Standard Input
Math Functions
Character Functions
System Limitations
Conditional Expressions
Selection Statements
Loop Structures
Simple Program Structure
/* ANSI-compliant comments */
// Comment to end of line - common but not ANSI-compliant prior to C99
#include <stdio.h> // printf() Standard header File
#include “myinclude.h” // custom header file
// Constant declaration - text replacement to comment of end of line
#define PI (3.14159)
int main(void) // default declaration for main()
{
// Variable Declarations
int m,n,p=12;
double area, r = 9.0, z = 9.2;
// executable code here
area = PI * r * r;
return(0); // main() declared as type int - must return int.
}
Constants
Literal constants
Values literally appearing in the code.
Format determines how compiler interprets them.
Interpreted as an integer value:
42 - Interpreted as an integer value.
0x4F - Hexadecimal (0x prefix) - interpreted as an integer.
042 - Octal (0 prefix - watch out!) - interpreted as an integer.
84293L - Long integer - prevents compiler from truncating to int.
Interpreted as a floating point value:
42. - Decimal point is sufficient.
42.0 - But easy to miss - tacking on a zero is better.
1e9 - Scientific notation
#define statements
Convenient way to define symbolic constants.
Surrounding values with parentheses is good practice.
Variables
A name associated with a memory location where a value can be stored.
Can consist of letters, digits, underscore characters - that’s it!
Leading character cannot be a digit.
Case sensitive - myvar, MYVAR, and MyVar are all different.
Only first 32 characters are significant (more in newest ANSI Standard)
Variable types
Size and range system dependent - sizes below for Borland Turbo C/C++ V4.5
integer types (can be prefixed with ‘unsigned’ to double positive range)
char - always one byte (but not always eight bits). One ASCII character.
int - two bytes (-32768 to +32767)
long (or long int) - four bytes (-2147483649 to +2147483648)
floating point types:
float - four bytes - ~5 sig figs, exponent +/- 38
double - eight bytes - ~15 sig figs, exponent +/- 308
long double - ten bytes - ~19 sig figs, exponent +/- 4932
Operators
Arithmetic Operators
Relational Operators
Logical Operators
Assignment Operators
Precedence
Associativity
Type Casts
Arithmetic Operators
* (Multiplication)
/ (Division)
Integer Division if both operands are integers.
17 / 5 = 3, not 3.4 - common, common error!
% (Modulo)
Remainder after Integer Division (17%5 = 2)
+ (Addition)
- (Subtraction)
Relational Operators
Evaluate to 0 if FALSE and 1 if TRUE
== (equality) (not = common, common mistake)
!= (inequality)
> (greater than)
< (less than)
>= (greater than or equal to)
<= (less than or equal to)
Complementary Pairs (always opposite result)
(==, !=), (>, <=), (<, >=)
Logical Operators
Evaluate to 0 if FALSE and 1 if TRUE
! (negation) (unary operator - operand to its right)
&& (logical AND) (TRUE only if both operands are TRUE)
|| (logical OR) (TRUE if either operand is TRUE)
Logical Evaluation of Operands
Operand is FALSE if it is exactly equal to zero.
Operand is TRUE if it is ANYTHING other than zero.
Guaranteed Short Circuiting
If result is known after evaluating left operand, right will not be evaluated.
Can by very useful in preventing errors.
Care must be exercised if there are side-effects in right operand.
(0 != x) && ( (y/x) > 1)
Useful: cannot result in division by zero.
(y >= x) || (j < k++)
Dangerous: Will not increment k if x < y!
Assignment Operators
In expressions, evaluate to the value assigned.
x = y = 9 + (k = 12 + (x = j = 3)); // is valid code!
Abbreviated Assignment Operators
*=, /=, %=, +=, -=,
k += x; is the same as k = k + x;
Increment/Decrement Operators
k++, k-- (post-increment/decrement)
evaluates to original value of k in expressions.
++k, --k (pre-increment/decrement)
evaluates to new value of k in expressions.
Precedence of Operators
Largely follow familiar rules
(*, /, %) before (+, -)
Use parentheses liberally
Easy to get trapped in subtleties.
Prevents the compiler from making your decisions for you!
Prevents common mistakes such as:
x = a+b / c; instead of x = (a+b)/c;
Associativity of Operators
Determines order of evaluation when all else is equal.
Left Associativity:
x = y * z * w; => x = ( (y * z) * w);
Right Associativity:
x = y += z += w; => x = (y += (z += w));
Use parens liberally - don’t let the compiler decide!
Type Cast Operators
Used to convert the representation of a value within an expression.
Has NO effect on the variable that is cast.
Operates on the value immediately to the right of the cast.
Use name of type in parens:
x = (double) j / (double) k; will force floating point division.
x = (double) (j/k); will still perform integer division.
Compiler will do some casting automatically.
Only performed at points where necessary.
k = 12 + (14/20) + (7.5/3);
(7.5/3) => (7.5/3.0) = 2.5 (integer promoted to floating point)
(14/20) = 0 (no cast necessary, integer division used)
(12 + 0 + 2.5) => (12.0 + 0.0 + 2.5) = 14.5 (promotion)
k = 14.5 => k = 14 (demotion if k is an int)
Standard Output
#include <stdio.h>
printf(“format string”, arg1, arg2, .... argN); // to the screen
fprintf(file_ptr, “format string”, arg1, arg2, .... argN); // to a file
sprintf(str_ptr, “format string”, arg1, arg2, .... argN); // to a string
each returns the number of characters printed.
Format String
All but two characters printed verbatim.
% character used to format and output the next argument.
\ character used to print characters that can’t be typed directly.
Must be at least as many arguments as % specifiers.
% - printf() conversion specifiers
Format: %[flags][width][.precision][modifier]type_character
All except type_character are optional.
Conversion specifier is everything from % sign to the first type_character.
[flags] - controls justification, leading spaces, sign, etc.
{-, +, , #, 0}
[width] - sets the minimum width of the field - may be longer.
[.precision] - sets the number of digits following the decimal point.
Usually used for floating points, but also affects character and integer types as
well.
[modifier] - combines with type_character to determine argument type.
type_character - the basic type of that argument.
{c, d, e, E, f, g, G, i, o, p, s, u, x, X, %}
In general, look up what you need.
You will tend to remember the forms you use most often.
\ - printf() escape sequences
Format: \(character) or \(number)
If a character follows the \, the action indicated by the character is performed.
\n - newline
\r - return w/o line feed.
\” - print double quote
\’ - print single quote (aka apostrophe)
\a - sound bell
\b - backspace
\\ - print backslash
\? - question mark
If a number follows the \, the ASCII character of the octal number is printed.
Standard Input
#include <stdio.h>
scanf(“format string”, arg1, arg2, .... argN); // from the keyboard
scanf(file_ptr, “format string”, arg1, arg2, .... argN); // from a file
sscanf(str_ptr, “format string”, arg1, arg2, .... argN); // from a string
each returns the number of successful conversions.
Format String
Literal characters in format string can be used to skip characters.
% conversion specifiers similar (but not identical) to printf().
Arguments need to be memory locations where values will be stored.
Big Time Caveat
If input does not adequately match format, results can be VERY unpredictable.
Many programmers avoid the use of scanf() at nearly any cost.
Use of fscanf() for file I/O is generally safe provided the file format is adequately
constrained.
Common mistakes with scanf()
Passing values instead of memory locations.
The scanf() function read values and store them at the memory locations you
supply.
k = 10;
scanf(“%i”, k);
Tells scanf() to format the value as an integer and store it at location 10.
But the memory location for variable k is almost certainly not 10.
The address operator, &, returns the memory location of the specified variable.
scanf(“%i”, &k);
Tells scanf() to format the value as an integer and store it at the memory address
used for variable k.
Using %lf for doubles.
printf() uses %lf for both floats and doubles because the compiler promotes all
arguments of type float to double.
scanf() cannot due this. It must know which type the variable is so that the number
and format of the bytes stored is correct.
Math functions
#include <math.h>
Approximately 30 function, most with a companion function for long ints.
trigonometric
sin(), cos(), tan() and their inverses.
sinh(), cosh(), tanh() but NOT their inverses (use trig relations)
atan2(y,x) - two argument version of atan() allowing four quadrant answer.
arguments and/or return values in radians - not degrees.
exponential/logorithmic
base e: exp(), log()
base 10: pow10(), log10
other: sqrt(), pow(x, y) - returns x^y
absolute value
abs() - for integers only! common mistake
fabs() - for floating point values
ASCII Codes
American Standard Code for Information Interchange - 7 bits (128 values)
Used to represent characters and certain codes used to control their display.
Originally developed for Teletypewriter applications.
Many nonstandard extensions exist to extend the code to 8 (or more) bits.
Codes <32 are control codes, some of which are no longer used.
Codes >=32 are printable characters (except 127 which is the DELETE control code.
ASCII 32 is the space character.
In C, a character surrounded with single quotes is that character’s ASCII code.
‘ ‘ = 32
‘0’ = 48
‘A’ = 65
‘a’ = 97 = ‘A’ + 32 = ‘A’ + ‘ ‘
Character functions
#include <ctype.h>
Character test functions
Return a logical value (0 or not-0) based on the properties of the character code.
isdigit(k) returns 0 unless ‘0’ <= k <= ‘9’
isupper(k) returns 0 unless ‘A’ <= k <= ‘Z’
Character manipulation functions
Return a different code for some characters, otherwise return the value passed.
tolower(k) returns k+32 if isupper(k) is TRUE otherwise returns k.
System Limitations
#include <limits.h>
Symbolic constants that define the limits of integer representations.
Examples:
INT_MAX Maximum value of an int
INT_MIN Minimum value of an int
ULONG_MAX Maximum value of an unsigned long int
#include <float.h>
Symbolic constants that define the limits of floating point representations.
Examples:
DBL_MAX Largest representable value for a double.
DBL_MIN Smallest positive representable value for a double.
DBL_EPSILON Smallest value x such that 1+x is not equal to 1.
Selection Statements
Selectively choose one path of execution.
Based on the evaluation of a test.
Test outcome is either TRUE or FALSE.
FALSE if expression evaluates to ZERO.
TRUE if expression evaluates to ANYTHING else.
Three varieties of selection statements.
if()/else
switch()
()? (conditional or ternary operator)
Conditional Expressions
(test)
May be ANY expression that evaluates to a value.
logical operator (!, ||, &&)
relational operator (==,!=),(>, <=), (<,>=)
assignment operator (equal to value assigned)
single variable (or constant)
function return value
Test outcome is either TRUE or FALSE.
FALSE if expression evaluates to ZERO - exactly.
TRUE if expression evaluates to ANYTHING else.
if() and if()/else statements
Syntax if() if()...else
if(test)
{
if_code;
}
else test? test?
{ F F
else_code;
}
T T
if_code if_code else_code
()? - conditional or ternary operator
Syntax x = ()?:
x = (test)? if_expr:else_expr;
Shorthand version of if()/else
test?
F
T
x = if_expr x = else_expr
switch() statement
Syntax (int_expr)
must evaluate to an integer value
switch(int_expr)
at runtime.
{
case int_const1: code1;
(int_constN)
break;
must evaluate to a unique integer
case int_const2: code2; constant at compile time.
case int_const3: code3;
break; execution jumps to case where
default: code4; (int_constN == int_expr) is TRUE.
}
Compact way of writing certain break;
terminates switch() execution.
types of complex but common
if()/else blocks. default case
Optional. Executes only if NO
other case executes.
Testing for floating point
equality
if(x == y) // BAD!!!
Only true if EXACTLY equal. Because a great deal of care went into how floating
point values are represented, you can frequently get away with it - but unless you
REALLY know what is going on and what is preventing disaster from visiting you,
you are just being lucky!
#DEFINE EPSILON (0.0001)
if(EPSILON > fabs(x-y)) // GOOD!!!
Looking for the difference between two values to be less than some small amount. Will
work most of the time but EPSILON must be matched to the size of the values to be
compared and the range of values can’t be too great.
#DEFINE EPSILON (0.0001)
if(fabs(EPSILON*y) > fabs(x-y)) // EVEN BETTER!!!
Looking for two values to vary by less than a certain percentage. Comparison written
so as to avoid potential division by zero during test.
Loop Structures
Special case of Selection Statement
One branch eventually leads back to the original selection statement.
Permits a block of code to be executed repeatedly as long as some test condition
is satisfied.
C provides three different looping structures
while(), do/while(), for()
Only one is needed and any one is sufficient.
Different structures are better matches for the logic.
Using the “proper” one aides the programmer and anyone else reading the code.
The compiler doesn’t care and will often implement the code identically
regardless of which structure is used.
while() loop ini_code
Syntax
ini_code // not part of loop
while(test_expr) test?
{ F
loop_code;
increment_code; T
}
loop_code
next_code; // not part of loop
Features
loop does not execute at all if test
inc_code
fails the first time.
next_code
do/while() loop ini_code
Syntax loop_code
ini_code // not part of loop
do
{ inc_code
loop_code;
increment_code;
} while(test_expr);
next_code; // not part of loop T
test?
Features
loop will always execute at least
once, even if test fails the first F
time.
next_code
for() loop ini_code
Syntax
for(ini_code; test_expr; inc_code)
{ test?
loop_code; F
}
next_code; // not part of loop T
Features loop_code
Just a while() loop with the initialization
and increment code formally
inc_code
incorporated into the syntax.
Can makes a cleaner divide between the
loop logic and the housekeeping logic.
next_code