A Quick Introduction To C Programming: Lewis Girod CENS Systems Lab July 5, 2005
A Quick Introduction To C Programming: Lewis Girod CENS Systems Lab July 5, 2005
A Quick Introduction To C Programming: Lewis Girod CENS Systems Lab July 5, 2005
Lewis Girod
CENS Systems Lab
July 5, 2005
http://lecs.cs.ucla.edu/~girod/talks/c-tutorial.ppt
or,
Answer(s):
• Complexity: Every conditional (“if”) doubles number of paths
through your code, every bit of state doubles possible states
o Solution: reuse code with functions, avoid duplicate state variables
#include <stdio.h>
/* The simplest C Program */
int main(int argc, char **argv)
{
printf(“Hello World\n”);
1. Write text of program (source code) using an editor
such as emacs, save as file e.g. my_program.c
return 0;
}
#include <stdio.h>
The main() function is always
/* The simplest C Program */
int main(int argc, char **argv) where your program starts
{ running.
printf(“Hello World\n”);
return 0;
Blocks of code (“lexical
}
scopes”) are marked by { … }
Return ‘0’ from this function Print out a message. ‘\n’ means “new line”.
A Quick Digression About the Compiler
#include <stdio.h>
/* The simplest C Program */
int main(int argc, char **argv)
{
Preprocess Compilation occurs in two steps:
printf(“Hello World\n”);
return 0;
} “Preprocessing” and “Compiling”
Why ?
Function Arguments
#include <stdio.h>
/* The simplest C Program */
int main(int argc, char **argv)
{
printf(“Hello World\n”);
Calling a Function: “printf()” is just another
return 0;
} function, like main(). It’s defined for you in
a “library”, a collection of functions you
can call from your program.
Returning a value
What is “Memory”?
void p(char x)
Every Variable is Defined within some scope. A {
/* p,x */
Variable cannot be referenced by name (a.k.a. char y;
Symbol) from outside of that scope. /* p,x,y */
char z;
/* p,x,y,z */
}
Lexical scopes are defined with curly braces { }. /* p */
char z;
/* p,z */
{
The scope of Variables defined inside a char c;
char b?
function starts at the definition and ends at /* p,z,q,a,b,c */
}
the closing brace of the containing block
char d;
/* p,z,q,a,b,d (not c) */ legal?
}
The scope of Variables defined outside a
function starts at the definition and ends at /* p,z,q */
1+2*21+45
(1 + 2) * 2 3 * 2 6
Don’t confuse = and ==! The compiler will warn “suggest parens”.
#include <stdio.h>
“if” statement #include <inttypes.h>
#include <stdio.h>
Recall lexical scoping. If a variable is valid #include <inttypes.h>
“within the scope of a function”, what happens float pow(float x, uint32_t exp)
when you call that function recursively? Is {
/* base case */
there more than one “exp”? if (exp == 0) {
float
int argc
x 5.0
1 return 1.0; static
}
uint32_t
char **argv
exp 1
0
0x2342
Yes. Each function call allocates a “stack /* “recursive” case */
float p undefined
5.0 return x*pow(x, exp – 1); Java?
frame” where Variables within that function’s }
scope will reside. int main(int argc, char **argv)
{
float p;
p = pow(5.0, 1);
printf(“p = %f\n”, p);
Return 1.0
return 0;
}
Return 5.0
Grows
Iterative pow(): the “while” loop
Other languages?
float pow(float x, uint exp)
Problem: “recursion” eats stack space (in C). {
int i=0;
Each loop must allocate space for arguments float result=1.0;
while (i < exp) {
and local variables, because each new call result = result * x;
creates a new “scope”. i++;
}
return result;
}
Solution: “while” loop. int main(int argc, char **argv)
{
loop: float p;
if (condition) { while (condition) {
p = pow(10.0, 5);
statements; statements;
printf(“p = %f\n”, p);
goto loop; }
return 0;
} }
The “for” loop
The “for” loop is just shorthand for this “while” loop structure.
So far, all of our examples all of the data values we have used
have been defined in our lexical scope
Grows
Passing Addresses
A Valid pointer is one that points to memory that your program controls.
Using invalid pointers will cause non-deterministic behavior, and will often
cause Linux to kill your process (SEGV or Segmentation Fault).
char * get_pointer()
{
char x=0;
return &x;
}
{
char * ptr = get_pointer();
*ptr = 12; /* valid? */
}
Answer: Invalid!
char * get_pointer()
{
char x=0;
return &x;
} But now, ptr points to a
{ location that’s no longer in use,
char * ptr = get_pointer();
*ptr = 12; /* valid? */ and will be reused the next
other_function();
}
time a function is called!
Return 101
Grows
More on Types
We’ve seen a few types at this point: char, int, float, char *
At this point we have seen a few basic types, arrays, pointer types, and
structures. So far we’ve glossed over how types are named.
C type names are parsed by starting at the type name and working
outwards according to the rules of precedence:
x is
an array of
pointers to
int *x[10]; int Arrays are the primary source
of confusion. When in doubt,
x is use extra parens to clarify the
int (*x)[10];
a pointer to expression.
an array of
int
Function Types
void qsort(void *base, size_t nmemb, size_t size, The last argument is a
int (*compar)(const void *, const void *));
comparison function
/* function matching this type: */
int cmp_function(const void *x, const void *y);
const means the function
/* typedef defining this type: */ is not allowed to modify
typedef int (*cmp_type) (const void *, const void *);
memory via this pointer.
/* rewrite qsort prototype using our typedef */
void qsort(void *base, size_t nmemb, size_t size, cmp_type compar);
Whereas the compiler enforces that reclaimed stack space can no longer
be reached, it is easy to accidentally keep a pointer to dynamic memory
that has been freed. Whenever you free memory you must be certain that
you will not try to use it again. It is safest to erase any pointers to it.
sizeof() can take a variable reference in place of a type name. This gurantees the right
allocation, but don’t accidentally allocate the sizeof() the pointer instead of the object!
/* when you are done with it, free it! */ memmove is preferred because it is
free(s);
s = NULL; safe for shifting buffers
Why?
Macros and static inline functions must be included in any file that uses
them, usually via a header file. Common uses for macros:
More on C
/* Macros are used to define constants */ constants?
#define FUDGE_FACTOR 45.6 Float constants must have a decimal
#define MSEC_PER_SEC 1000 point, else they are type int
#define INPUT_FILENAME “my_input_file”
enums
/* Macros are used to do constant arithmetic */
#define TIMER_VAL (2*MSEC_PER_SEC) Why?
Put expressions in parens.
/* Macros are used to capture information from the compiler */
#define DBG(args...) \
do { \
fprintf(stderr, “%s:%s:%d: “, \ Multi-line macros need \
__FUNCTION__, __FILE__, __LINENO__); \
fprintf(stderr, args...); \
} while (0)
args… grabs rest of args
Why?
/* ex. DBG(“error: %d”, errno); */ Enclose multi-statement macros in do{}while(0)
Macros and Readability
/* often best to define these types of macro right where they are used */
#define CASE(str) if (strncasecmp(arg, str, strlen(str)) == 0)
Some schools of thought frown upon goto, but goto has its place. A
good philosophy is, always write code in the most expressive and clear
way possible. If that involves using goto, then goto is not bad.
goto try_again;
goto fail;
Unrolling a Failed Initialization using goto
state_t *initialize()
{
state_t *initialize()
/* allocate state struct */
{
state_t *s = g_new0(state_t, 1); /* allocate state struct */
if (s) { state_t *s = g_new0(state_t, 1);
/* allocate sub-structure */ if (s == NULL) goto free0;
s->sub = g_new0(sub_t, 1);
if (s->sub) { /* allocate sub-structure */
/* open file */ s->sub = g_new0(sub_t, 1);
s->sub->fd = if (s->sub == NULL) goto free1;
open(“/dev/null”, O_RDONLY);
if (s->sub->fd >= 0) { /* open file */
/* success! */ s->sub->fd =
} open(“/dev/null”, O_RDONLY);
else { if (s->sub->fd < 0) goto free2;
free(s->sub);
free(s);
/* success! */
s = NULL; return s;
}
} free2:
else { free(s->sub);
/* failed! */ free1:
free(s); free(s);
s = NULL;
free0:
}
return NULL;
}
}
return s;
}
High Level Question: Why is Software Hard?
Answer(s):
• Complexity: Every conditional (“if”) doubles number of paths
through your code, every bit of state doubles possible states
o Solution: reuse code paths, avoid duplicate state variables
Recursive Iterative
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: