Вы находитесь на странице: 1из 111

What you expect from this training ?

• Take notes upfront from students as to any


specific area, they want to know more about
• Programming Process

• C Program Structure

• Program Elements

• Control Structures

• Functions and Storage Classes

• Arrays and Strings

• Pointers & Dynamic Memory Allocation

• Structures, Union
Programming Process

+ documentation
Example

1. Write a program to compute the volume of box.


2. Input: length, width, height
Output: volume
3. Hand Example:
volume = 20.75*11.5*9.5
9.5
11.5
20.75

4. Algorithm: input length, width and height


compute volume
output volume
5. Implement algorithm in C and test.
Strategies: Divide and Conquer
Break up large problems into smaller problems that are easier to handle
(Top-Down approach)

Hard problem

Easy Hard Easy


subproblem subproblem subproblem

Easy Easy
subproblem subproblem
Structure of a C Program
The Greeting Program
Program Elements Lexical Tokens
• Character Set
• Keywords
• Identifiers
• Constants
• Literal Strings
• Operators
• Punctuators
• Special
Characters

C++ C
Identifiers
• Identifiers in C consist of three types:
– Reserved words (Keywords )
– Standard identifiers Not recommend to use for Programmer variables
– Programmer-created identifiers
• Can be any combination of letters, digits, or underscores (_)
subject to the following rules :
– First character must be a letter or underscore (_)
– Only letters, digits, or underscores may follow the initial character
– Blank spaces are not allowed
– Cannot be a reserved word
Keywords

Category Keyword

Data Types char double float int void


Data Type Modifiers long short signed unsigned
Access Type Modifiers const volatile
Storage Class Specifiers auto extern register static
User-Defined Data Types enum struct typedef union
Selection (Conditional) case default else if switch
Iteration do for while
Jump break goto return continue
Compile Time Operator sizeof
Find output

1.
int x = -10;
printf("%c\n", '1' + 1);
printf("%d\n", ~x+1);

2.
int sum = 5;
sum = sum + sum *5/2;

3. Not recommended, instead do


b=a+20 OR a++
int a=10,b; a++ b=a+20
Whichever is required for the purpose
b=a+++20;
printf("a=%d b=%d",a,b);
Find output
4.
Not recommended
int x = 10; Better not to know.
Modify it, make it explicit
printf ("%d %d", ++x, ++x);
5.
int a=10,b; Not recommended
Better not to know.
Modify it, make it explicit
b=a++ + ++a;
printf("%d,%d,%d,%d",b,a++,a,++a);
6.
main() { Not recommended
int x = 20; { Instead do,
x = (10%7)/2;
int x = 10 % 7/2;
OR
printf ("%d\n", x);
} x = 10 % (7/2)

printf ("%d", x);


}
7 In general (other than within string constants like "Hello World" and a few
obscure
constructs), what effect does the amount of white space between code elements
have on a C program's compiled output?
a. Spaces are ignored, tabs have meaning.
b. Spaces and tabs are both ignored.
c. Tabs are ignored, spaces have meaning.
d. Spaces and tabs both have meaning

8 How does one indicate that certain text is to be treated as a "comment" in the
classic C language?
a. Place the text between /* */ .
b. Place 'COMMENT:' before the text.
c. Place '#' before the text.
d. Place the text between # and #.

9. In a C program, the first statement that will be executed is:


a. the first executable statement of the program.
b. the first executable statement after the comment /*start
here*/
c. the first executable statement of the main() function.
10 What will this piece (snippet) of C code print to the screen?
printf("Hello World");
/* This is a comment
printf("Hello Again");
This is another comment */
a. Only "Hello World".
b. Only "Hello Again".
c. Both "Hello World" and "Hello Again".
d. Neither.
Tips

1. A good identifier name is worth more than a comment.


1. Be consistent, be clear, ok to be verbose
1. Example: for a graphics library to draw line, rectangle, set a
color
1. draw_Line, drawRect, s_col
2. drawLine, drawRect, setColor
3. GRAPHICS_drawLine, GRAPHICS_drawRect,
GRAPHICS_setColor
2. Follow coding guidelines where ever appropriate
2. Comment whatever you do that is not obvious.
3. Comment those places where the coding standards or good practices
are violated in the interest of an overriding factor (such as code size
or performance).
4. Sections of code shall not be commented out. Instead #if or #ifdef
constructs shall be used for commenting code. If piece of code is not
needed it should be removed. Pieces of code should not be kept in
files for the purpose of history.
What is “Memory”?
Memory is like a big table of numbered Addr Value
slots where bytes can be stored. 0
1
The number of a slot is its Address. 2
One byte Value can be stored in each slot.
3 72?

Some “logical” data values span more than 4 ‘H’ (72)


one slot, like the character string “Hello\n” 5 ‘e’ (101)
6 ‘l’ (108)
A Type names a logical meaning to a span
7 ‘l’ (108)
of memory. Some simple types are:
8 ‘o’ (111)
char a single character (1 slot)
char [10] an array of 10 characters 9 ‘\n’ (10)
int signed 4 byte integer 10 ‘\0’ (0)
not always…
float 4 byte floating point
int64_t signed 8 byte integer Signed?…
11
12
What is a Variable? symbol table?

A Variable names a place in memory Symbol Addr Value


where you store a Value of a certain Type. 0
1
You first Define a variable by giving it a
2
name and specifying the type, and
optionally an initial value 3
declare vs define?
x 4 ?
char x; Initial value of x is undefined y 5 ‘e’ (101)
char y=‘e’;
6
The compiler puts them 7
Initial value
somewhere in memory.
8
Name What names are legal? 9
10
Type is single character (char)
extern? static? const?
11
12
Multi-byte Variables
Different types consume different amounts Symbol Addr Value
of memory. Most architectures store data 0
on “word boundaries”, or even multiples of 1
the size of a primitive data type (int, char) 2
3
char x;
char y=‘e’; x 4 ?
int z = 0x01020304; y 5 ‘e’ (101)
6
0x means the constant is padding
written in hex 7
z 8 4
9 3
An int consumes 4 bytes
10 2
11 1
12
Naming Conventions
• C programmers generally agree on the following
conventions for naming variables.
– Begin variable names with lowercase letters
– All uppercase letters used to indicate a symbolic constant
– An identifier should be descriptive
– Use meaningful
identifiers

– Separate “words” within identifiers with underscores or


mixed upper and lower case.
– Examples: surfaceArea surface_Area
surface_area
– Be consistent! C is a case-sensitive language !!
• TOTAL, and total represent different identifiers
Operator Precedence
• An operator’s precedence Operator Precedence
determines its order of
function calls highest
evaluation.
• Unary operator is an ! + - &
operator that has only one * / %
operand.
– !, +(plus sign), -(minus + -
sign), and &(address of) < <= >= >
– They are evaluated
== !=
second only after
function calls. &&
||
= lowest
C Expressions
Logic operators are evaluated using lazy evaluation.
Lazy evaluation – Once a value completes the condition, stop
OR any condition is found to be TRUE
AND any condition is found to be FALSE
Why is lazy evaluation important?
Makes code run faster – skips unnecessary code
Know condition will/will not evaluate, why evaluate other terms
Can use lazy evaluation to guard against unwanted conditions
Checking for a NULL pointer before using the pointer

L-value: An expression that refers to a region of storage; only l-values can be used at the
left side of “=” operator

Are the following valid uses of L-value?


int a;
(float) a = 3.14;
* ((float*) &a) = 3.14; Try not do write such code
• Expression and casting
1. Avoid assignment in comparisons.
2. Avoid using auto increment (‘++’) and audodecrement
(‘--’) in expressions. These should not be mixed with
other operators.
3. Expressions should not be tested against true or false.
4. Don’t use assignments in expressions that perform
relational tests.
5. Don’t use relational tests in statements that perform
assignments.
6. Try to avoid the use of casts as far as possible, as this
may indicate that something is wrong elsewhere.
When used, follow: a) C++ -Use cast definitions
(static_cast, dynamic_cast, const_cast and
reinterpret_cast). b) C - Use standard C-style cast, e.g.
(type *) identifier.
Control Structures in C
• Control structures control the flow of execution in a
program or function.
• There are three kinds of execution flow:
– Sequence:
Sequence
• the execution of the program is sequential.
– Selection:
Selection
• A control structure which chooses alternative to execute. C has
three types: if, if/else, and switch
– Repetition:
Repetition
• A control structure which repeats a group of statements. C has
three types: while, do/while and for
1. What is the final value of x when the code int x; for(x=0; x<10; x++) {} is
run?
A. 10
B. 9
C. 0
D. 1
2. When does the code block following while (x<100) execute?
A. When x is less than one hundred
B. When x is greater than one hundred
C. When x is equal to one hundred
D. While it wishes
3. Which is not a loop structure?
A. for
B. do while
C. while
D. repeat until
4. How many times is a do while loop guaranteed to loop?
A. 0
B. Infinitely
C. 1
D. Variable
The if Statement

• Executes a block of code if condition is true


• The condition, which is a C expression,
evaluates to zero (false) or nonzero (true)
• Examples:
if (x > 20)
20) x = 20;
20; True False
x > 20

if (x <= 10)
10) {
y = x*x + 5; X = 20;
z = (2
(2 * y) / 3;
}

if (0 <= age && age <= 11)


11)
kids = kids + 1;
The if-else Statement

• Executes one block of code if condition is true,


otherwise executes another block
• Examples:
if (x) {
True False
x++; x==0
z++; ?
}
y++; y--;
--;
else { z++; z--;
--;
y--;
--;
z--;
--;
}
Process-control System Example
The switch Statement

switch (c) { True False


case '+': c='+'
'+':
r = a + b;
break;
break; r=a+b;
break;
case '-':
r = a - b;
break;
break; True False
c='-
c='-'
case '*':
'*':
r = a * b; r=a-
r=a-b;
break;
break;
break;
default:
default:
printf(
printf("Invalid op!");
op!"); True False
c='*'
break;
break;
}
r=a*b;
break;
i = 1;
j = 0;
if( i = 1 ) j = 3;
if( i = 2 ) j = 5;

Did you know that the following if statement is semantically right, but
could logically be wrong? if ( i = 2 ) { /* do something */ } Tip: The
compiler may only produce a waring: "Possibly incorrect assignment", but
we may ignore it. To avoid such a mistake, just reverse the two
identifiers. if ( 2 == i ) { /* do something */ } If '==' is replaced by an '=', the
compiler will give an error saying "Lvalue required".
if (n1 >= n2 >= n3) cout << "max = " << n1
The while loop

• Execute a block of code as long as loop


condition is true
• Checks condition at beginning of loop, so loop
may or may not execute
/* Print digits from 7 down to 1 */ False
Test
int a = 7;
True
while (a) {
printf(
printf("%c\
"%c\n", a+‘a');
Body
a--;
--;
}
printf(
printf("All done!\
done!\n");
n");
The do-while loop

• Execute a block of code as long as loop


condition is true
• Checks condition at end of loop, so loop always
executes at least once
Body
/* Print digits from 7 down to 1 */
int a = 7;
True Test
do {
printf(
printf("%c\
"%c\n", a+‘a'); False
a--;
--;
} while (a);
printf(
printf("All done!\
done!\n");
n");
The for loop
• A special form of the while loop, with initialization and re-initialization
sections
for (init ; test ; re-
re-init) {
body
}

What is the output of the following program? Init

int oldval,newval = 0;
False
Test
int i;
True
for (i=0;i<10;i++){
oldval = newval; Body

newval = i; Re-init

}
printf("%d",oldval);
Write a program
1. Test whether a particular bit of given number is ON or OFF
2. Set a particular Bit on in a given number
• Write a program
1. To count number of bits in a given number
2. to count 1 bit and 0 bit in a given number
3. To swap two variables
4. To check a variable is even or odd
Jump

• C supports four jump statements:


• break,
• continue,
• return
• goto.
• These statements transfer control to another
part of your program.
goto
• It is possible to jump to any statement within the
same function using goto.
• A label is used to mark the destination of the jump.

goto label1;
:
:
label1:
Structured Programming
• Structured programming is a design discipline
in which the programmer:
(1) uses only high-level control structures
(2) avoids using the goto statement

• Goal: Produce only clear, “well-structured”


code that will:
(1) follow naturally from top-down design
(2) lead to “readable” programs
(3) will avoid programming errors
C Guidelines

General
a. Do not create big “C” files. Split files into smaller logical files.
b. Limit the size of each function. Functions should fit into single page
whenever possible.
c. Logical units within a block shall be separated by one blank line.
d. Three blank lines shall separate functions.
e. Avoid use of multiple returns from function. Multiple returns will
reduce the readability of the code.
f. Access to hardware should be abstracted to enable portability. Avoid
access of hardware/peripherals such as timers, DMA in the source
files directly. Create functions that perform hardware/peripherals
related operations and use these functions wherever needed.
g. All variables should be initialized before use.
h. As the stack size is limited, recursion should be avoided
Function Syntax
Parameter names can
be omitted from the
function prototype

• Function Prototype:
return_type function_name (type1 name1,
type2 name2, …,
typen namen) ;

Return type and Semi-colon indicates that this


parameter types is only the function prototype,
must be provided in and that its definition will be
the prototype found elsewhere
Function Syntax
No semi-colon
• Function Definition:
return_type function_name (type1 name1,
type2 name2, …,
typen namen)
{
....statements...
}

Parameter names are


Body of the function required here – they’ll be
appears in its definition used in the function body
What is the output of the following program?

#include <stdio.h>
int func (int n){
int f, I i;
f=1;
for(i=1; i<=;n;i++){
f *=i;
}
return f;
}
main(){
printf("%d\n",func(4));
}
• Type
Attributes of Identifiers • Visibility (Scope)
• Uniqueness (Linkage)
• Permanence (Duration)
• Storage Class
• Qualifier (Modifiability)

In the following program segment The use of external variables are illustrated
in the following 2-file C programs

… in file 1
void f1 (…) extern int xy;
{ extern long arr [ ];
… main ( )
} {

int a, b, c; }
void f2(…) void foo (int abc) { … }
{ long soo (void) { … }

} in file 2
int xy;
Variables a, b, and c are accessible to long arr [100];
function f2 but not f1.
Given the following,
1. An int variable with block scope and temporary storage
2. A constant character variable with block scope
3. A float local variable with permanent storage
4. A register int variable
5. A char pointer initialized with a null character

write declarations for all of them.

#include <stdio.h>
int main() {
int i; for (i=0; i<5; i++){
int x = 0;
static int y = 0;
printf("x=%d, y=%d\n", x++, y++);
}
return 0;
Identify the storage class, access type of each declaration in the
following code portion:
int i = 0;
static int x;
extern float y;
volatile int i;
int myFunction() {
int i, j;
extern float z;
register long s;
static int index;
const char str[] = "Warning message.";
...
}
Array
Array: a set of index and value
data structure
For each index, there is a value associated with
that index.
representation
implemented by using consecutive memory.

0 1 2 3 4 5 6 7 8 9
int arr[10]; 21
5

arr

arr[0]=5;
arr[7]=21;
arr[10]=3; Error!!!
An Example
#include <stdio.h>
What value is stored in marks[i] if
float dataarray[5]; the value -10 is entered?
float total = 0;
#define LIMIT 100
float avg;
int main() { main() {

int i; for (i= 0; i < LIMIT; i++){


for (i = 0; i < 5; i++) { printf("\nEnter mark:");
printf(“I/P Value for index %d”,i); scanf("%d", &score);
scanf(“%f”,&dataarray[i]); if (score <0) continue;
total += dataarray[i]; marks[i] = score;
}
}
avg = total/i;
}
printf(“Average = %f\n avg);
}
Multidimensional Arrays

a[0] a[0][0] a[0][1] a[0][2]


The array declared using
int a [4] [3];
a[1] a[1][0] a[1][1] a[1][2]
is normally thought of as a
table.
a[2] a[2][0] a[2][1] a[2][2]

a[3] a[3][0] a[3][1] a[3][2]


Multidimensional Arrays

In memory, which is one-dimensional, the


rows of the array are actually stored
contiguously.

increasing order of memory address

a[0][0] a[0][1] a[0][2]

a[0] a[1] a[2] a[3]


Array Initialization
• Initializers
int n[ 5 ] = { 1, 2, 3, 4, 5 };
– If not enough initializers, rightmost elements become 0
int n[ 5 ] = { 0 }
All elements 0
• If size omitted, initializers determine it
int n[ ] = { 1, 2, 3, 4, 5 };

• Initialization 1 2
– int b[ 2 ][ 2 ] = { { 1, 2 }, { 3, 4 } }; 3 4
– Initializers grouped by row in braces
– If not enough, unspecified elements set to zero 1 0
int b[ 2 ][ 2 ] = { { 1 }, { 3, 4 } }; 3 4
Pointers and Variables

int a = 5; 0x4343525 5

int *b; 0x2343223 garbage

b = &a; 0x2343223 0x4353525


Pointers and Arrays

Adress Memory

int a[5] = {1,2,3,4,5}; 0x4343524 1 2 3 4 5

int *b; 0x2343223 garbage


int c;

b = a; 0x2343223 0x4353524

c = b[1]; // *(b+1) 0x5435455 2

How about
b = & a[0]?? vs. b=a;??
Passing Arrays
• When an array is passed to • Because you can compile
a function, what is being functions separately, the compiler
passed is a pointer to the must be able to “know” about an
array array being passed in to a
function, so you must specify all
– In the formal parameter
(or most) of the definition:
list, you can either
specify the parameter as – The type and all dimensions
an array or a pointer except for the first

int array[100]; int array[5][10][15];


… …
afunction(array); afunction(array);
… …
void afunction(int a[ ][10][15]) {…} or
void afunction(int *a) {…} void afunction(int *a[10][15]) {…} or
or void afunction(int a[5][10][15]) {…} or
void afunction(int a[ ]) {…} void afunction(int **a[15]) {…} etc
• Write a bubble sort function to sort an array of integers.

void swap (int *px, int *py); /* function prototype


declaration */
void bubble (int a[], int n) /* n is the array count */
{
int i, j;
for (i = 0; i < n - 1; i++)
for (j = n - 1; j > i; j--)
if (a[j - 1] > a[j])
swap (&a[j - 1], & a[j]);
}

void swap(int *px, int *py)


{
int temp;
temp = *px;
*px = *py;
*py = temp;
}
When to pass by pointer

• When declaring a function, you can either pass by


value or by reference.
• Factors to consider:
– How much data do you have?
– Do you “trust” the other functions that will be
calling your function.
– Can you handle the memory management
complexity?
Dynamic Memory Allocation
• Dynamic memory allocation
– Obtain and release memory during execution
• malloc
– Takes number of bytes to allocate
• Use sizeof to determine the size of an object
– Returns pointer of type void *
• A void * pointer may be assigned to any pointer
• If no memory available, returns NULL
– Example
newPtr = malloc( sizeof( struct node ) );
• free
– Deallocates memory allocated by malloc
– Takes a pointer as an argument
– free ( newPtr );
What's wrong with this code?
void f(int *ip) {
static int dummy = 5;
ip = &dummy;
}
Main(){
int *ip;
f(ip);
}
Passing Pointers by References

• int getBlockRef(int **p, unsigned n) {


• if((*p = (int*)malloc(n*sizeof(int))) ==
NULL)
• return 0;
• return 1;
• }
• ...
• int *q;
• if(getBlockRef( &q , 10) == 1)
• success
"Pass by Reference"
Idiom
What is the output of the following program?

void f1(int*,int);
void f2(int*,int);
void(*p[2]) (int*,int);
main() {
void f1(int *x, int y){
int a=3,b=5;
int temp;
p[0]=f1;
temp = *x; *x= y; y = temp;
p[1]=f2;
}
p[0](&a,b);
void f2(int *x, int y){
printf(" %d %d \n",a,b);
int temp;
p[1](&a,b);
temp = *x ; *x =y ; y = temp;
printf("%d %d \n", a,b);
}
}
Stack vs. Heap

• Both are sources from which memory is


allocated
– Stack is automatic
• Created when memory is “in scope”
• Destroyed when memory is “out of scope”
– Heap is manual
• Created upon request
• Destroyed upon request
Memory Usage
High end
static char greeting[] I/O addresses
=“Hello world!”;
Stack
main() (grows down)

{
int i;
Heap (grows up)
char bVal;
Static Data
LCD_init();
LCD_PutString(greeting);
… Code
}
Low end
Two ways to get an int:

• On the Stack:
int main() {
int myInt; //declare an int on the stack
myInt = 5; //set the memory to five
return 0;
}

• On the Heap:
int main() {
int *myInt = malloc(sizeof(int));
//allocate mem. from heap
*myInt = 5; //set the memory to five
return 0;
}
String (Array of Char)
• In C, we can emulate string with an 1-D array of char terminated by NULL
character (‘\0’)
• C does not know where an array ends at run time – no boundary
checking
• All C library functions that use strings depend on the null character being
stored so that the end of the string can be detected
• Example: char str [10] = {'u', 'n', 'i', 'x', '\0'};
– Length of str is 4 (not 5, and not the declared size of the array)

char n[5] = “John”;


n[0] n[1] n[2] n[3] n[4]

‘j’ ‘o’ ‘h’ ‘n’ ‘\0’


char n[5] = {‘J’, ‘o’, ‘h’, ‘n’, ‘\0’};
printf(“%s”, n);
63
What is the difference between these initializations?

char a[] = "hello"; char *p = "world";

What is wrong with the following :


char *foo = "hello";
char *bar = "hello";
if (foo == bar) puts (“String equal");
else puts(“ Strings do not equal");
64
Compare

char *a = "Hello ";


char *b = "world";
strcat(a, b);
printf("%s\n", a);
Better?

char a[12] = "Hello ";


char *b = "world";
strcat(a, b);
printf("%s\n", a);
What's happening in C?

char a[12] = "Hello ";

a
H e l l o \0

?
What's happening in C?

char a[12] = "Hello ";


char *b = "world";

a
H e l l o \0

b
w o r l d \0
What's happening in C?

char a[12] = "Hello ";


char *b = "world";
strcat(a, b);

a
H e l l o w o r l d \0

b
w o r l d \0
What's happening in C?

char a[12] = "Hello ";


char *b = "world";
strcat(a, b);
printf("%s\n", a);
a
H e l l o w o r l d \0

b
w o r l d \0
Hello world
Functions from string.h

• strlen returns the length of a NULL


terminated character string:
size_t strlen (const char * str);
• size_t: a type defined in <string.h> that is
equivalent to an unsigned int
• char *str: points to a series of characters or
is a character array ending with '\0'
– What’s wrong with:
char a[5]={'a', 'b', 'c', 'd', 'e'}; strlen(a);
• strcpy makes a copy of a string:
char *strcpy (char * destination,
const char * source);
• A copy of the string at address source is made
at destination
– String at source should be null-terminated
– destination should point to enough room
(at least enough to hold the string at source)
• The return value is the address of the copied
string (that is, destination)
• strcat concatenates strings:
char * strcat (char * str1, const char * str2);
• Appends a copy of str2 to the end of str1
• The result string is null-terminated
• str2 is not modified
• A pointer equal to str1 is returned
• Programmer must ensure that str1 has
sufficient space to hold the concatenated string
Example
#include <string.h>
#include <stdio.h>
int main( ) {
char str1[27] = "abc";
char str2[100];
printf("%d\n",strlen(str1)); Show the output
strcpy(str2,str1);
puts(str2);
puts("\n"); #include <string.h>
strcat(str2,str1); int main() {
puts(str2); char str1[ ] = "The first string.";
} char str2[ ] = "The second string.";
printf("%d\n", strncmp(str1, str2, 4) );
printf("%d\n", strncmp(str1, str2, 7) );
}
When manipulating text in C

• Use char array to hold strings


• Extremely important:
 If you creating temporary arrays to copy string,
make sure that array size must be string length + 1
 why??
• Use the string library (string.h) when possible instead
of creating your own functions
Pointers and Arrays

int main() {
int array[10];
int* pntr = array;
for(int i=0; i < 10; i++) {
printf(“%d\n”, pntr[i]);
}
return 0;
}

• We can get a pointer to the beginning of an array using the name of


the array variable without any brackets.
• From then on, we can index into the array using our pointer.
Pointer Arithmetic
int main() {
int array[10];
int* pntr = NULL; //set pointer to NULL
for(pntr = array; pntr < array + 10; pntr++) {
printf(“%d\n”, *pntr); //dereference the pntr
}
return 0;
}

• We can “increment” a pointer, which has the effect of making it point to the
next variable in a array.
• Instead of having an integer counter, we iterate through the array by moving
the pointer itself.
• The pointer is initialized in the for loop to the start of the array. Terminate
when we get the tenth index.
void*
int i = 10;
• A pointer to nothing??
void *p = &i; /* p holds address of int value i */
• NO!! A pointer to anything
int *ip = (int *)p; /* ip now holds that same address
int main() { */
char c; int j = * ((int *)p ); /* j contains the value of i */
int i;
float f;
void* ptnr;
pntr = &c; //OK
pntr = &i; //OK
pntr = &f; //OK
return 0;
}

• Remember, all pointers are the same size (typically 32 or 64 bits)


because they all store the same kind of memory address.
Memory Leak

A memory leak is an error condition that is created


when an object is left on the heap with no pointer
variable containing its address. This might happen if the
object's pointer goes out of scope:
void MySub()
{
Student * pS = malloc(sizeof(Student));

// use the Student for a while...

} // pS goes out of scope

(the Student's still left on the heap)


Dangling Pointer

A dangling pointer is created when you delete its


storage and then try to use the pointer. It no longer
points to valid storage and may corrupt the program's
data.
double * pD = malloc( sizeof(double));
*pD = 3.523;
.
.
free(pD); // pD is dangling...
.
.
*pD = 4.2; // error!
Avoid Dangling Pointers

To avoid using a dangling pointer, assign NULL to a


pointer immediately after it is deleted.
And, of course, check for NULL before using the
pointer.
free(pD);
pD = NULL;
.
.
if( pD != NULL ) // check it first...
*pD = 4.2;
Const-Qualified Pointer

A const-qualified pointer guarantees that the program


has read-only access to the data referenced by the
pointer.
void MySub( const int * A )
{
*A = 50; // compile error
A++; // ok
}

The pointer itself can be modified, but this has no


lasting effect--the pointer is passed by value.
What's wrong with this code?

int array[5], i, *ip;


for(i = 0; i < 5; i++) array[i] = i;
ip = array;
printf("%d\n", *(ip + 3 * sizeof(int)));
How to use typedef’s
1) Create a logical data type scheme. For example, a signed 8-bit
number could be “s8”.
2) Create a “typedef.h” file for each microcontroller platform you use.
3) #include “typedef.h” in each of your files.
4) Use your new data type names.

typedef unsigned char u8;


typedef signed char s8;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned long u32;
typedef signed long s32;

In your code:
unsigned char variable;
Is replaced with:
u8 variable;
Function Pointers

#include <stdio.h>
static void function(int a) {
printf("function: %d\n", a);
}
static void caller(void (*func)(int), int p) {
(*func)(p);
}
int main(void) {
caller(function, 10); return 0;
}
float plus (float a, float b) { return a+b; }
float minus (float a, float b) { return a-b; }
float multiply (float a, float b) { return a*b; }
float divide (float a, float b) { return a/b; }

float f (float a, float b, float (*pt2Func)(float, float)) {


return pt2Func(a, b); // call using function pointer
}
Main() {
float x =12.5 , y = 14.5,z;
z = f( x, y , &minus )
Structures
• A structure has several elements (a.k.a. members) that may have,as
opposed to an array, different types
• Each member has a name
– The selection of a member is done using name not index
struct pair {
int number;
char grade;
}; number
grade

struct pair y;
y.number = 216;
y.grade = ‘A’;
• The size of a structure can be determined using sizeof operator
– e.g. sizeof(y);
sizeof(y); /*may be bigger than 5!! */
– Addresses are normally multiple of 4
Structures and Pointers

struct pair {int number; char grade;};


struct pair x;
x.number=2160;
x.grade=’A’; x 2160
A

struct pair *p;


p = &x; p

int n = (*p).number; n 2160


char g = (*p).grade; g A
Dereferencing Fields
struct pair {int number; char grade;} *p;
p = &x;
2160
p A

Easier-to-use
*p 216
notation
A

int n = (*p).number; n 2160


int n = p-
p->number;

char g = (*p).grade;
g A
char g = p-
p->grade;
Dereferencing Fields

• The -> operator is combination of “*” and “.”


• The -> operator produces an lvalue and we can
use it wherever an ordinary variable would be
allowed
– e.g. scanf(“%d”,&p->number);
– We need “&” because we are assigning value
to member element number not p
Self-referential Structures
• A structure cannot have a structure of its type as a
member
struct pair{
struct pair another; /* WRONG */

}
• But C allows us to use pointer to implement self-
referencing
struct pair{
struct pair *another; /* CORRECT */

}
15.1
Nodes and Linked Lists

– A linked list is a list that can grow and shrink while


the program is running
– A linked list is constructed using pointers
– A linked list often consists of structs or classes that
contain a pointer variable connecting them to other
dynamic variables
– A linked list can be visualized as items, drawn as
boxes, connected to other items by arrows

12 14 end
head 10
Example
struct pair{
int number;
char grade;
struct pair *next;
} x = {2160,’A’},y = {2150,’B’};
x y
216 A • 215 B •
0 0

x.next = &y;
x.next-
x.next->number will be 2150
Using the variable x, give definitions for the following:
a) An integer
b) A pointer to an integer
c) A pointer to a pointer to an integer
d) An array of 10 integers
e) An array of 10 pointers to integers
f) A pointer to an array of 10 integers
g) A pointer to a function that takes an integer as an argument
and returns an integer
h) An array of ten pointers to functions that take an integer
argument and return an integer
• volatile qualifier
– Variable may be altered outside program
– Variable not under control of program
– Variable cannot be optimized

Indicates that a variable can be changed by a background routine.


Keyword volatile is an extreme opposite of const. It indicates that a variable
may be changed in a way which is absolutely unpredictable by analysing the
normal program flow (for example, a variable which may be changed by an
interrupt handler). This keyword uses the following syntax:
volatile data-definition; Every reference to the variable will reload the
contents from memory rather than take advantage of situations where a copy
can be in a register.
volatile
volatile specifies a variable whose value may be changed by processes outside the
current program
One example of a volatile object might be a buffer used to exchange data with an
external device:

volatile int *iobuf=(int*)0x123;

int check_iobuf(void) {
int val;

*iobuf = 1;

while (*iobuf == 0) { }
val = *iobuf; *iobuf = 0; return(val); }

if iobuf had not been declared volatile, the compiler would notice that nothing
happens inside the loop and thus eliminate the loop
const and volatile can be used together

An input-only buffer for an external device could be declared as const volatile


(or volatile const, order is not important) to make sure the compiler knows that
the variable should not be changed (because it is input-only) and that its value
may be altered by processes other than the current program
Your Own Header files
This is to separate the function declarations from the function definitions.
useful.h
#ifndef USEFUL_H
#define USEFUL_H main.c
float square(float x); #include <stdio.h>
int factorial(int x); #include “useful.h”

#endif int main() {


useful.c float f;
int i;
#include "useful.h"
float square(float x) { f = square(3.5);
return x * x; i = factorial(10);
}
int factorial(int x) { printf(“The numbers are %f
if (x==1) { %d\n”, f, i);
return x; return 0;
} else { }
return x * factorial(x-1);
}
}
Danger of Macros

• Consider the following example.


• What is the actual output?
• What is the intended output?
• What is the solution to the problem?

#define SQUARE(A) A * A

int func(int m) {
int i;
i = SQUARE(4+m);
return i;
}
C Example for Maintainability
enum Color {White, Green, Blue, Black};

main(){
enum Color x = Black;
int i = x;
while (i >= White){
if (i < Green)
printf(“this is a light color!\n”);
i--;
}
}
Evaluation of Enumeration Types

• Efficiency – e.g., compiler can select and use a compact efficient


representation (e.g., small integers)

• Readability -- e.g. no need to code a color as a number

• Maintainability – e.g., adding a new color doesn’t require updating


hard-coded constants.

• Reliability -- e.g. compiler can check operations and ranges of


values.
C Example for Maintainability
enum Color {White, Yellow, Green, Blue, Black};
main(){
enum Color x = Black;
int i = x;
while (i >= White){
if (i < Green)
printf(“this is a light color!\n”);
i--;
}
}
What if no enumeration?
if (i < 1) printf(“this is a light color!\n”);
Has to be changed to:
if (i < 2) printf(“this is a light color!\n”);
Backup
Disk Controller Register
Struct bit-fields

• Way to aggressively pack data in memory

struct {
unsigned int baud : 5;
unsigned int div2 : 1;
unsigned int use_external_clock : 1;
} flags;
• Compiler will pack these fields into words
• Very implementation dependent: no guarantees of
ordering, packing, etc.
• Usually less efficient
– Reading a field requires masking and shifting
C Unions
• Can store objects of different types at different times

union {
int ival;
float fval;
char *sval;
};

• Useful for arrays of dissimilar objects


• Potentially very dangerous
• Good example of C’s philosophy
– Provide powerful mechanisms that can be abused
Lists, stacks, and queues

• List: A collection of data whose entries are


arranged sequentially
• Head: The beginning of the list
• Tail: The end of the list
Linked Lists

struct node {
int value;
5
struct node *next;
};

struct node a = {5,NULL};


struct node b = {6,NULL};
a.next = &b; 6

Undefined pointer
The structure of a linked list
struct list {
int value;
struct list *next;
};
main(){
struct list n1, n2, n3,*l;
l= &n1;
n1.value = 100;
n2.value = 200;
n3.value = 300;
n1.next = &n2;
n2.next = &n3;
n3.next = NULL;
while(l) {
printf("%d\n", l->value);
l = l->next;
}
}
Deleting an entry from a linked list
Stack

Вам также может понравиться