The document provides an in-depth overview of advanced C programming concepts, focusing on pointers, their types, and usage. Key topics include pointer arithmetic, precedence rules, pointers to functions, and assignment issues related to pointers. Additionally, it discusses typedefs, differences between declaration and definition, and the behavior of arrays as pointers.
2
Agenda
Pointer overview
Precedence rule
Assignments and pointers
Arrays and pointers
Pointers to functions
Reference type
Linking
Cache
3.
3
Pointer Types
Apointer is a variable which contains the address in
memory of another variable.
We can have a pointer to any variable type.
The operator ‘&’ gives the address of a variable.
The indirection or dereference operator * gives the
contents of an object pointed to by a pointer.
When a pointer is declared it does not point
anywhere. You must set it to point somewhere before
you use it.
int* pi;
*pi = 100;// error!!
4.
4
Pointer Types (Cont.)
A pointer can’t hold a nonaddress value.
int ival;
pi = ival; // error: pi assigned int value of ival
Nor can a pointer be initialized or assigned the
address value of an object of another type.
double dval;
double *pd = &dval;
pi = pd; // both are compile-time error
pi = &dval; // invalid assignment: int * <- double *
5.
5
Pointer Types (Cont.)
intx = 1, y = 2;
int* ip;
ip = &x;
y = *ip;
x = ip;
*ip = 3;
1 2 100x y ip
100 200 1000
1 1 100x y ip
100 200 1000
100 1 100x y ip
100 200 1000
3 1 100x y ip
100 200 1000
6.
6
void * Pointer
The void* pointer can be assigned the address value
of any data pointer type.
The void* indicates that the associated value is an
address but the type of the object at that address is
unknown.
int *pi = 0;
void *pv;
pv = pi; // ok: implicit conversion
pi = pv; // error: no standard conversion
const int *pci = &ival;
pv = pci; // error: pv isn’t a const void *
const void *pcv = pci; // ok
7.
7
Integer Arithmetic ona Pointer
char* cp;
float* flp;
cp++; // add 1 byte to the address
flp++; // add 4 bytes to the address
flp flp++ flp+2
4 bytes
8.
8
Dereference Operator *
Example
int ival = 10;
int* pi = &ival; // pi is a pointer to int
int** ppi = π // ppi is a pointer to a pointer to int
int* pi2 = *ppi; // dereference ppi
printf("ival=%dn*pi=%dn**ppi=%d", ival, *pi, **ppi);
Results
ival=10
*pi=10
**ppi=10
10
1200
1200
1232
1200
1232
1320
ival
pi
pii
pi2 1324
9.
9
Precedence Rule
Whatexactly, does the following declaration
declare?
char* const * (*next)();
10.
10
Precedence Rule
.is higher than *
*p.f -> *(p.f)
Take the f offset from p, use it as a pointer
[] is higher than *
int *ap[] -> int *(ap[])
ap is an array of ptrs-to-int
Function () higher than *
int *fp() -> int *(fp())
fp is a function returning ptr-to-int
11.
11
Precedence Rule (Cont.)
== and != higher than bitwise operators
val & mask !=0 -> val & (mask != 0)
== and != higher than assignment
c = getchar() != EOF -> c = (getchar() != EOF)
Arithmetic higher precedence than shift
msb << 4 + lsb -> msb << (4+lsb)
, has lowest precedence of all operators
i = 1, 2; -> (i = 1), 2;
12.
12
Precedence Rule (Cont.)
Declarations are read by starting with the name and
then reading in precedence order.
The precedence, from high to low, is:
parentheses grouping together parts of a declaration
the posfix operators:
parentheses () indicating a function, and square brackets []
indicating an array.
the prefix operator: the asterisk denoting "pointer to".
If a const keyword is next to a type specifier (e.g. int,
long, etc.), it applies to the type specifier.
Otherwise the const keyword applies to the pointer
asterisk on its immediate left.
13.
13
Precedence Rule (Cont.)
char* const * (*next)()
next is a pointer to a function returning a pointer to
a const pointer-to-char
Try to explain it
char *(*c[10])(int **p);
14.
14
Assignment and Qualifiers
Problemsfor Pointers
Why it can’t work?
void foo(const char **p) { }
int main(int argc, char** argv)
{
foo(argv);
}
You will get: cannot convert parameter 1 from
'char **' to 'const char**'
15.
15
Assignment and Qualifiers
Problemsfor Pointers (Cont.)
Keyword const doesn’t turn a variable to a constant
This makes the value read-only through that symbol.
Rules
Argument passing is supposed to behave like assignment.
Both operands are pointers to qualified or unqualified
versions of compatible types, and the type pointed to by the
left has all the qualifiers of the type pointed to by the right.
16.
16
Assignment and Qualifiers
Problemsfor Pointers (Cont.)
Argument char *s matches parameter const
char *p.
s: An unqualified pointer to a character with no
qualifiers.
p: An unqualified pointer to a character qualified
by const qualifier.
p = s, legal.
s = p, illegal.
17.
17
Assignment and Qualifiers
Problemsfor Pointers (Cont.)
Argument char **s can’t match parameter
const char **p.
s: A pointer to an unqualified pointer to a character with no
qualifiers.
p: A pointer to an unqualified pointer to a character qualified
by const qualifier.
Both s and p are pointers to unqualified types that aren’t the
same type – incompatible type
Both s = p and p = s aren’t allowed.
p
s
const char
char
18.
18
const Orderings
Possibleordering for pointer and const
const int * grape;
int const * grape;
int * const grape;
The first two make the object that it points at read-only.
The last one make pointer read-only.
19.
19
const Orderings (Cont.)
Example:
const int a = 10;
int b = 5;
const int *pc; // pointer to const int
int *const cp = &b; // const pointer to int
pc = &a; // legal
*pc = 5; // you cannot assign to a variable that is const
pc = &b; // legal
*cp = 0; // legal
cp = &a; // cannot convert from 'const int *__w64' to 'int *const'
20.
20
Symbol Overloading
static
Inside a function, retains its value between calls.
At the function level, visible only in this file.
extern
Applied to a function definition, has global scope.
Applied to a variable, defined elsewhere.
21.
21
Symbol Overloading (Cont.)
void
At the return type of a function, doesn’t return a
value.
In a pointer declaration, the type of generic
pointer.
In a parameter list, takes no parameters.
*
The multiplication operator.
Applied to a pointer, indirection.
In a declaration, a pointer.
22.
22
Rule for ReturnType
A function can’t return a function.
You never see foo()().
A function can’t return an array.
You never see foo()[].
A array can’t hold a function.
You never see foo[]().
23.
23
Rule for ReturnType (Cont.)
A function returning a pointer to a function is
allowed: int (* fun())()
A function returning a pointer to an array is
allowed: int (* foo())[]
An array holding pointers to function is
allowed: int (* foo[])()
An array can hold other array, so you
frequently see: int foo[][]
24.
24
typedef
Simplify declaration
Example:
Declaration for signal
void (*signal(int sig, void (*func)(int)))(int);
Using typedef
void (*signal( ))(int);
signal is a function returning a pointer to a function.
typedef void (*ptr_to_func)(int);
A pointer to a function taking an int argument and returning void.
Simlified version of signal
ptr_to_func signal(int, ptr_to_func);
25.
25
Differences between typedef
and#define
You can extend a macro typename with other
type identifier
#define peach int
unsigned peach i; /* work fine */
typedef int banana;
unsigned banana i; /* illegal */
26.
26
Differences between typedef
and#define (Cont.)
A typedef’d name provides the type for every
declarator in a declaration
typedef char * char_ptr;
char_ptr a, b;
#define int_ptr int *
int_ptr c, d;
It becomes int *c, d;
27.
27
Definition vs. Declaration
Definition
occurs only one place
specifies the type of an object; reserves storage
for it; is used to create new objects
ex. int my_array[100];
Declaration
can occur multiple times
describe the type of an object; is used to refer to
objects defined elsewhere
ex. extern int my_array[];
28.
28
Match Your Declarationsto
the Definition
Why doesn’t it work?
File 1:
int mango[100];
File 2:
extern int *mango;
some code that reference mango[i]
Change declaration to match definition
File 1:
int mango[100];
File 2:
extern int mango[];
29.
29
A Subscripted Array
Reference
char a[9] = “abcdefgh”;
c = a[i];
Compiler symbol table has a as address 9980
Runtime step 1: get value i, and add it to 9980
Runtime step 2: get the contents from address (9980+i)
9980 +1 +i+2
30.
30
A Subscripted Pointer
Reference
char *p = “abcdefgh”;
c = p[i];
Compiler symbol table has p as address 4624
Runtime step 1: get the contents from address 4624, say 5081
Runtime step 2: get value i, and add it to 5081
Runtime step 3: get the contents from address (5081+i)
5081 +1 +i+2
50814624
(5081+i)
31.
31
When Arrays ArePointers
Rule 1: An array name in an expression is a
pointer.
An array reference a[i] is always rewritten to *(a+i)
by the compiler.
a[i] can can be accessed in any of these ways:
p=a; p[i];
p=a; *(p+i);
p=a+i; *p;
32.
32
When Arrays Are
Pointers(Cont.)
Rule 2: C treats array subscripts as pointer
offsets.
Rule 3: Array name as a function parameter
is a pointer.
They are all completely equivalent:
my_func(int* turnip) {}
my_func(int turnip[]) {}
my_func(int turnip[100]) {}
33.
33
When You Seesquash[i][j] – You
Don’t Known How It Was Declared!
int squash[5][10];
array[5] of array[10] of int
int *squash[5];
an array of 5 pointers-to-int
int **squash;
pointer to a pointer to int
int (*squash)[10];
pointer to array-of-10-ints
34.
34
A Pointers toPointers
Example
Consider the following:
char ch; /* a character */
char *pch; /* a pointer to a character */
char **ppch; /* a pointer to a pointer to a character */
ppch pch ch
string
ppch pch
string0
ppch
pch
0
string1
string2
Pointers to pointers
Pointers to string
Pointers to several strings,
is identical to *ppch[].
36
Pointers to Functions
Declaration
int (*pf)(char*, char*)
pf to be a pointer to a function that takes two parameters
and has a return type of int.
Assignment
int calc(int, int);
int (*pf2i)(int, int) = 0;
int (*pf2s)(char*, char*) = 0;
pf2i = calc; // ok
pf2s = calc; // type mismatch
37.
37
Pointers to Functions(Cont.)
Invocation
pf2i(x, y);
(*pf2i)(x, y); // the same as above, but more readable
A pointer to a function can be the type of a function’s
return value:
int (*ff(int))(int, int);
It declared ff() to be a function taking one parameter of type
int, return a pointer to a function type int (*)(int, int).
Use typedef to make it easier to read:
typedef int (*PF)(int, int);
PF ff(int);
38.
38
Pointers to extern“C”
Function
A pointer pf refers to a C function in a cpp file:
extern “C” void exit(int); // a C function
extern “C” void (*pf)(int) = exit;
A pointer to a C function can’t be initialized or be
assigned to a pointer to a C++ function (and vice
versa)
void (*pf1)(int);
extern “C” void (*pf2)(int);
pf1 = pf2;// error: pf1 and pf2 have different types
39.
39
Pointers to extern“C”
Function (Cont.)
When a linkage directive applies to a declaration, all
functions declared by the declaration are affected by
the linkage directive
// pfParm is a pointer to a C function
extern “C” void f1(void (*pfParm)(int));
Use typedef to make a C++ function to have a
parameter that is a pointer to a C function
extern “C” typedef void FC(int);
// f2() is a C++ function with a parameter that is
// a pointer to a C function
void f2(FC* pfParm);
40.
40
Arrays of Pointersto Function
int (*pfv[10])()
Declares pfv to be array of ten elements. Each element is a
pointer to a function that take no arguments and that has a
return type of int
Use typedef to simplify declaration:
typedef int (*PFV)();
PFV pfv[10];
Invocation
int ret = pfv[0]();
41.
41
Arrays of Pointersto Function
(Cont.)
An array of pointers to functions can be initialized
using initializer list in which each initializer represents
a function of the same type as the type of the array
element
int lexicoCompare(char *, char *);
int sizeCompare(char *, char *);
typedef int (*PFS)(char *, char *);
PFS compareFunc[2] = {lexicoCompare, sizeCompare};
42.
42
Reference Type
Oncedefined, a reference can’t be made to refer to
another object.
A reference serves as a kind of pointer
int val = 10;
int &refVal = &val; // error: refVal is of type int, not int*
int* pi = &val;
int *&refPtr = pi; // refPtr is a reference to a pointer
Swap two pointers
void ptrSwap(int *&v1, int *&v2) {
int* tmp = v2
v2 = v1
v1 = tmp;
}
43.
43
Array Parameters
Thesize of an array isn’t part of its parameter type:
void putValues(int [10]); // equal to putValues(int *)
int i, j[2];
putValues(&i); // ok, but potential run-time error
putValues(j); // ok, but potential run-time error
When the parameter is a reference of an array type,
the array size become part of the parameter:
void putValues(int (&ar)[10]);
parameter is a reference to an array of 10 ints
int i, j[2];
putValues(&i); // error, i is not an array of 10 ints
putValues(j); // error, j is not an array of 10 ints
44.
44
Header File
Nevercontain a definition, for example:
extern int ival=10;
The declaration of a global object specifies both extern and
explicit initializer is treated as a definition
double rate;
No extern keyword, so it is a definition
extern void dummy() { }
The empty brace pair stands as the definition of that function
Symbolic constants and inline functions can be
defined many times, so they don’t violate this rule
Their definitions can appear in a header file
45.
45
Linkage Directives: extern“C”
Indicate to the compiler that a function is
written in a different programming language.
extern “C” void exit(int);
A linkage directive can’t appear within a
function.
46.
46
Static Linking versusDynamic
Linking
hello.chello.c
libc.alibc.a
libc.solibc.so
a.outa.out
a.outa.outresult in
result in
statically linked with
dynamically linked with Library functions are mapped
into the process at runtime
1KB
750KB
620KB
502KB
5KB
47.
47
BSS
BSS –Block Started by Symbol.
Only hold variables that don’t have any value
yet.
It doesn’t actually need to store the image of
these variables.
The size of that BSS will require at runtime is
recorded in the object file.
48.
48
Executable File Format
charpear[40];
static double peach;
int mango = 13;
static long melon = 2001;
main()
{
int i = 3, j, *ip;
ip = malloc(sizeof(i));
pear[5] = i;
peach = 2.0 * mango;
/* other codes */
a.out magic number
other a.out contents
size need for BSS segment
data segment
initialized global and
static variables
text segment
executable instructions
Source file a.out file
Local variables don’t go in a.out,
but are created at runtime.
49.
49
How a.out Mapsto Memory?
a.out magic number
other a.out contents
size need for BSS segment
data segment
initialized global and
static variables
text segment
executable instructions
a.out file
data segment
text segment
BSS segment
stack segment
the hole
Address space of a process
highest memory address
unmapped
lowest memory address
(instructions)
(initialized
data)
(uninitialized
data)
(data local
to functions)
50.
50
Stack Segment
Thestack provides the storage area for local
variables declared inside functions
The stack stores the "housekeeping" information
involved when a function call is made
a procedure activation record
any parameters that won't fit into registers
saved values of registers
The stack also works as a scratch-pad area — every
time the program needs some temporary storage
To evaluate a lengthy arithmetic expression, it can push
partial results onto the stack, popping them when needed.
Storage obtained by the alloca() call is also on the stack.
51.
51
Data Segment &Heap
data segment
text segment
stack segment
the hole
unmapped
lowest memory address
(data local
to functions)
the heap
the break
used for malloc()
BSS segment
highest memory address
52.
52
Data Segment &Heap (Cont.)
Heap
Make data segment grows dynamically on
demand.
Storage is obtained through malloc and accessed
through a pointer.
The end of the heap is marked by a pointer known
as the break.
Heap management
malloc and free – get memory from heap and give
it back to heap.
brk and sbrk – adjust the size of the data segment.
53.
53
Considering the Cache
Why SMARTCOPY is faster?
#define DUMBCOPY for (int i = 0; i < 65536; i++)
destination[i] = source[i]
#define SMARTCOPY memcpy(destination, source, 65536)
main()
{
char source[65536], destination[65536];
for (int j = 0; j < 100; j++)
DUMBCOPY;
for (int j = 0; j < 100; j++)
SMARTCOPY;
}
56
A Better Exampleof Memcpy
void* Memcpy(void* dst, void const* src, size_t len)
{
long* plDst = (long *)dst;
long const* plSrc = (long const *)src;
if (0xFFFFFFFC & len) {
while (len >= 4) {
*plDst++ = *plSrc++; // copy 4 bytes every time
len -= 4;
}
}
// copy remainder bytes
char* pcDst = (char *)plDst;
char const* pcSrc = (char const *)plSrc;
while (len--)
*pcDst++ = *pcSrc++; // copy 1 byte every time
return dst;
}
57.
57
References
Expert CProgramming - Deep C Secrets, by
Peter van der Linden
Programming in C,
http://www.cs.cf.ac.uk/Dave/C/CE.html
C++ Primer, 3rd Edition, by Stanley B.
Lippman & Josee Lajoie