0% found this document useful (0 votes)
8 views85 pages

08 Pointers

The document discusses pointers in C programming, explaining their functionality, syntax, and usage in relation to arrays and memory management. It highlights the differences between pointers and arrays, including how pointers can be modified while arrays cannot, and introduces concepts such as dynamic data structures and pointer arithmetic. The document also provides examples of pointer operations and their implications in programming.

Uploaded by

carlotta.hoelzle
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views85 pages

08 Pointers

The document discusses pointers in C programming, explaining their functionality, syntax, and usage in relation to arrays and memory management. It highlights the differences between pointers and arrays, including how pointers can be modified while arrays cannot, and introduces concepts such as dynamic data structures and pointer arithmetic. The document also provides examples of pointer operations and their implications in programming.

Uploaded by

carlotta.hoelzle
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 85

PT1

pointers
when you get stuck today, raise your hand, stop me

professor patrick baudisch


pt1
hasso-plattner institute
let's look at strings again… up-close…
c[0] c[3]
array variable = the address of the
first element char c[22] h e l l o w o r l d
f rn o mt p1 t 1 !!d \0 o
m 71
c[21]
we may also say that a H e l l o \0
s
string (or
variable
any array)
:: variable ::
really is just the address of the first element in memory
H e l l o \0
s
pointer ::
object, the value of which refers to (or "points to") another value stored elsewhere in the computer memory using its memory address
H e l l o \0
array p

one (of many) uses of pointers is to point into arrays.

pointers are a bit like arrays, however


while arrays always point to their first element
we can move pointers around, so as to point to any element
1
72 2

3
i
4

5
j
6

rather than "give me the plate in shelf[4]" we can just point to it


7
8
pointer = 4/8 bytes H e l l o \0

size of a pointer today is typically long pointers can point anywhere in memory
enough to reach any address in memory.
resolution of pointers is one byte
For > 4GB of RAM that's 8 bytes
(but it may not be very efficient to do so)
(otherwise 32 bit = 4 bytes)

To find out
int main() {
printf("My pointers occupy \
%ld bytes\n",sizeof(int*));
}
(pointers can point anywhere, but they may
not be able to access it ! seg fault)

memory management unit (MMU) ::


computer hardware unit having all memory references passed through itself, primarily performing the translation of virtual memory addresses to physical addresses.
It is usually implemented as part of the central processing unit (CPU), but it also can be in the form of a separate integrated circuit.
#include <stdio.h>
int main(void) {
H e l l o \0
char s[] = "Hello";
char *t;
s t t
t = s;
this is what we will
printf("first letter = %c\n", *t); use pointers for
today: to sweep
printf("t = %ld\n", t); // _big_
t++; through memory
printf("second letter = %c\n", *t);

printf("t
return 0; = %ld\n", t); // _big_ + 1
}
what's going on here/what will it output?
<30sec brainstorming>
confusing: here the * defines that t is a pointer (but does nothing)…

…while here the * actually does nothing = looks up where t points

pointer (syntax) ::
char *t; // defines a varable t as a pointer to char

char c = *t; // * operator assesses value pointed to by t


// one says the '*' "dereferences" t
http://stackoverflow.com/questions/4025768/what-do-people-find-difficult-about-c-pointers
it’s worth getting past that tricky syntax nonetheless, because…
pointers are insanely
awesome

a preview of coming attractions…


pointers allow you to represent complex relationships efficiently
represent friends-with graphs [Fekete et al.]
pointers + struct :: no, I will not explain
lists and trees today
this is a teaser ☺
the kicker: pointers may point to other pointers
this allow building up complex data structures

NU
‘l’ ‘i’ ‘s’ LL ‘t’

list the key to processing variable amounts of data (which arrays lack)

‘t’ NU
LL ‘r’ NU
LL
‘e’ NU
LL ‘e’ NU
LL
NU
LL ‘e’

tree the key to fast algorithms (O(log n))


dynamic data structure ::
organization or collection of data in memory that has the flexibility to grow or shrink
in size, enabling a programmer to control exactly how much memory is utilized.

they change in size by having unused memory allocated or de-allocated as needed


(see later lecture on malloc() and free())
(everyone understands arrays, but)
dynamic data structures are the key to advanced programming
ultimately, programming is about dynamic data structures.

1. all this awesomeness in a few weeks, when we talk about struct


2. and then much more about great data structures in pt2
the basis of all of this awesomeness is…

pointers

that said, today let's learn the syntax at the


example of something simple & manageable:
pointers as an alternative to arrays
moving pointers
around
moving pointers around

#include <stdio.h> H e l l o \0
int main(void) {
char s[] = "Hello";
char *t = s; // *t just definest t, does not dereference
t++;
// advance pointer to ‘e’
t += 2;
// ... by another two steps to second ‘l’
t *= 2;
// error, undefined (or can you think
t = t + s; // of a case where this would be useful)
return 0; // error, same reason
}
ok or not?
<30sec brainstorming>
not the same as… math on what is being pointed at

#include <stdio.h>
H e l l o \0
int main(void) {
char s[] = "Hello";
t
char *t = s;
*t += 17; // increment what t points at : 'H' ! 'Y'
(*(t+4))++; // move t 4 over to 'o', increment that ='p'
printf(s); // prints "Yellp"
return 0;
lots of () here to help us read.
} we'll reduce them some other time

ok or not?
<30sec brainstorming>
the message here is: a pointer always represents two things
1.the thing that's being pointed at
2.the pointer itself

some C statements deal with both at once


(I will explain the exact syntax later; for

c =c *(s++)
= *s++ 1. copies the pointer s
(and increments s afterwards)

3. assigns 2. looks up the variable


this to c being pointed at *s
*s++ is part of the canonical pointer function…
c = *s++
start next lecture
#include <stdio.h>
H e l l o \0
int main(void) {
char s[] = "Hello";
t
char *t = s; // define a pointer and make it point to s
t++; // make point to the ’e’
*t += 10; // change what t points at from ‘e' to ‘o'
(*(t+3))++; // increment the other ‘o’ to'p'
printf(s); // prints ”Hollp” (with warning)
return 0;
}

<3min repl>
use pointers to traverse arrays…
stringcopy.c
void strcpy1(char from[], char to[]) {
int i = 0;
do
H e l l o \0
to[i] = from[i];
while(to[i++] != '\0')
fr[0] fr[1] fr [2] fr [3] fr [4] fr [5]
}

void strcpy2(char *from, char *to) { H e l l o \0


do
*to++ = *from++;
while (*(to-1) != '\0')
from from from from from from
}
don’t mentally parse this, but recognize as a pattern
this could be done using do, but instead everyone does this…
stringcopy.c
void strcpy1(char from[], char to[]) {
int i = 0;
while (to[i] = from[i])
H e l l o \0
i++;
}
fr[0] fr[1] fr [2] fr [3] fr [4] fr [5]

H e l l o \0
void strcpy2(char *from, char *to) {
while (*to++ = *from++)
;
pointers
}
some say "elegant!"
1. uses one variable less from from from from from from
2. clarifies program flow

<vote>
3. executes faster what do you say?
others say "confusing!"
another
warm-up
even though pointers are whole numbers and may well be represented using the
same number of bits as int, C does not consider them as int
it restricts math to what is considered useful/meaningful.
int main(void) {
char s[] = "string"; // initialization like an array = ok
char *t;
int i;
t = s; // ok
t = s + 2; // ok
of limited use unless p and
t = 2 * s; // error q point to same array
t = s + s; // sneaky. but still error
i = t – s; // ok & useful: num of elements in between
t = t + t – s; // error (stops at t + t)
t = t + (t – s); // ok
i = s; // warning
i = *t; // valid
i = (t < s); // (a Boolean…) ok and done all the time
} ok or error?
<vote>
NULL
NU
‘l’ ‘i’ ‘s’ LL ‘t’

how to say that list ends here?


list
similar to strings: use “some sort of 0”

null pointer (aka NULL) ::


used to indicate that the pointer does not refer to a valid object.
int main(void) {
char s[] = "string"; // initialization like an array = ok
char *t;
t = NULL; // ok
if (t == NULL)... // ok
printf(“t is pointing at %c\n”, *t); // seg fault
}

ok or error?
<vote>
so pointers and arrays are pretty much the same things…
only minor difference….
C does not allow array variables to be modified
char a[5];
char *pa = a + 1; // legal
a = pa; // illegal

pointers, in contrast, _can_ be modified.


this means that pointer can stand on the left of an assignment.
they are thus said to be lvalues,

arrays, in contrast, are rvalues


meaning they can only stand on the right of assignment

one might say that arrays are "const pointers"


This does not increment the array in main(),
but the local variable (parameter) in Increment()
(C is "call by value", remember?)

<30sec brainstorming>
http://stackoverflow.com/questions/3839553/array-as-const-pointer
but if you really want to have something that acts as array and can be modified

#include <stdio.h>
int main(void) {
int a[100] = {1,2,3,4,5};
a += 2; // error: C will not modify an array
int *b = a; // but, we can point b to our array
printf ("b[2] = %d\n", b[2]); // and use b as array (wild)
b += 2; // screw around with b
printf ("b[2] = %d\n", b[2]); // and still pretend
return 0; // it's an array
}
any errors/what does it print?

<30sec brains>
pointing to
non-arrays
pointers can point to anything, not just arrays…
we already looked at
* declaration
int *p; // pointer to int <30sec
* dereferences (indirection operator)
brains>
int d = *p; // copy value of c
*&c == c
NEW: one may say that *
& returns the address of a variable is the inverse of &
int c;
int *p = &c; // initialization &*c == <syntax error>
#include <stdio.h>
int main()
{
int number1, number2;
printf("Enter two integers: \n");
fflush(stdout);
scanf("%d %d", &number1, &number2);
ah, this is what was
going on here!
if(number1 == number2)
printf("%d = %d\n", number1, number2);
else if (number1 > number2)
printf("%d > %d\n", number1, number2);
else
printf("%d < %d\n", number1, number2);
return 0;
}
# include <stdio.h>

int main(void) {
int x = 1;
int y = 2;
int *ip; // ip is a pointer, can point to ints

ip = &x;
y = *ip; // ip now points to x
*ip = 0; // value of y becomes same as x, i.e., 1
printf("y = %d\n", //
y);value of x becomes 0, (y stays 1)
return 0; // prints y = 1
}
what does it print?
<30sec brainstorming>
#include <stdio.h> we can use the address operator to write
functions that affect multiple values
C
void swap(int
(int*x, intint
*x, *y)*y)
{ {
int temp;
int temp;
temp = *x;
temp = *x;
*x = *y;
*x
*y = =temp;
*y;
*y
return;= temp;
} return;

int main () {
int a = 100, b = 200;
<3min repl>
swap(&a, &b);
printf("After swap: a = %d, b = %d\n", a, b);
(&a,
return 0; &b);
}
main insight here:

pointers ::
enable access to objects in scope of the caller
In languages that support true "call by reference", such as C++, we can write
swap(x,y); // does not work in C

and the fact that x and y are passed as pointers


is only declared in the definition of swap, e.g.,
void swap(int &x, int &y) // cannot say that in C

http://stackoverflow.com/questions/17423218/diff-between-call-by-reference-and-call-by-pointer
even cooler,
in languages that allow for multiple return parameters or "implicit tuples",
you can avoid the problem in the first place by writing
(x, y) = (y, x); // cannot say this in C

http://stackoverflow.com/questions/31374721/what-is-the-logic-for-x-y-y-x-to-swap-the-values-in-python
back to pointing at arrays…
start third lecture
how C does pointer
math
#define arraySize 10

char s[arraySize];
char *t = s + arraySize - 1;
// t now points to the last elememt of s

int a[arraySize];
int *b = a + arraySize - 1;
yep!

does b end up pointing to the end of a?


<30sec brainstorming>
that's why pointers have a type

(even though an int * is a memory address


the same that char * is a memory address)

they know what they are pointing at


!this allows for "pointer arithmetic", such as a + 5, a++, etc.
for int *a C increments in steps of sizeof(int), typically 4 or 8 bytes

(side effect: it allows the compiler to detect additional programming errors)


implementing arrays
using pointers
on assembler-level, it turns out, there are no arrays, only pointers…
storage (RAM)
where data and
program code reside

main processor (CPU)


LH5801
let’s zoom in…
these are places to store pointers
array index—using pointers

#include <stdio.h> H e l l o \0
char element(char s[], int i) {
return s[i];
}
s s[4]
char elementBasedOnPointerMath(char *s, int i) {
return *(s + i);
} return *(s + i);
this is how arrays are actually implemented
int main(void) {
char s[] = "Hello";
printf("s[4] = %c\n", element(s,4));
printf("s[4] = %c\n", elementBasedOnPointerMath(s,4));
return 0;
}

<30sec repl on paper>


and you might have noticed:
The C compiler treats array and pointer declarations as syntactically equivalent
(we invoked both by passing an array, but could also have passed a pointer)
that said, you should write them so as to best "document" your code

char element(char s[], int i) {...}

use this if you treat s as an array,


it better documents this fact

char elementBasedOnPointerMath(char *s, int i) {


use this to document that you
will use pointer math
just to hammer this point home…
void strcpy1(char from[], char to[]) {
int i = 0;
H e l l o \0
while (to[i] = from[i])
i++;
}
void strcpy2(char *from, char *to) { s s[4]
while (*to++ = *from++)

H e l l o \0
;
}
int main (void) {
char sArray[] = "hello";
char tArray[20];
char *s = sArray;
char *t = tArray; s s s s s s
strcpy1(s, t);
strcpy2(sArray, tArray);
printf("%s\n%s\n%s\n%s",
sArray, tArray, s, t); yes, these are all ok.
}
array access operator [] and
pointer dereferencing operator*
can often be used synonymously
formatting
char * s, char * t; for C, all three are ok.
char *s, char *t; but which format to use and why?
char* s, char* t;

you voted for this one, right?


<vote>
char* s, t;
// visually suggests “two char pointers: s and t”
// however, C reads it as “a char pointer s and a char t“
// to clarify this, people "attach" the '*' to the pointer
char *s, t;
==
int my_strcmp(char *s, char *t) {
return s == t;
}

what do you think?

<30sec brainstorming>
when would we say two strings are "the same"?

(s == t) // if the two pointers are identical


or // t ist der selbe String wie s

(*s == *t) && (*(s+1) == *(t+1)) && ...


// or if what they point to is identical
// t ist der gleiche String wie s

C’s strcmp() implements the latter…

<30sec brainstorming>
this is a deeply rooted issue
and we will re-encounter this ambiguity with other data structures
#include <stdio.h>
int my_stery(char *s, char *t) {
while (*s != '\0') {
if (*t == '\0') return 1;
if (*s < *t) return -1; = strcmp()
if (*s > *t) return 1; iterates over the strings and
s++; compares char by char
t++;
}
if (*t != '\0') return -1;
return 0;
}
int main(void) {
char s[] = "Hello World";
char t[] = "Hello Worm";
printf("my_stery (\"%s\", \"%s\") = %d\n", s, t, my_stery(s,t));
return 0;
}

<30sec brains>
what does it do?
here is a case where this becomes a problem…
#include <stdio.h> 5 5 01 \0
#include <string.h>
int main(void) {
char phoneNumberTholen[] = "550"; 5 5 0 \0
tb
// I started out co-using my admin's phone
5 5 0 \0
char *phoneNumberBaudisch = phoneNumberTholen; 1
Solution 1: replace line with t
phoneNumberBaudisch = strdup(phoneNumberTholen);
// then I changed my mind and switched to my own number b
strcpy(phoneNumberBaudisch, "551");
5 5 0 \0
Solution 2: replace line with
phoneNumberBaudisch = "551";
printf("%s\n",phoneNumberBaudisch);
5 5 1 \0
printf("%s\n",phoneNumberTholen); problem: now Tholen and I
tb
both have my new number
return 0;
} b

<30sec brains>
thoughts?
why pointers
are hard
http://stackoverflow.com/questions/4025768/what-do-people-find-difficult-about-c-pointers
end
pointers
professor patrick baudisch
pt1
hasso-plattner institute
I did not do the following samples in the lecture,
but consider solving them at home in order to practice…
practice!
more array examples
incString.c
#include <stdio.h>
"Hello World"
! "Ifmmp Xpsme"
C
char incChar(char c) {return c+1;}

void incString(char s[]) {


int i = 0; char *t = s;
while (s[i] != '\0') { while (*t != '\0') {
s[i] = incChar(s[i]); *t = inc(*t);
i++; t++;
} }
}
int main(void) {
char s[] = "Hello World";
printf("map (\"%s\") = ", s);
incString(s); translate to pointers

}
printf("%s\n", s);
return 0; <3min repl>
numberToReverseString.c
#include <stdio.h> // works by copying every non-c to the current j position
C
void itoa(int n,char s[]) {
int i = 0; char *t = s;
do { do {
s[i++] = n % 10 + '0';
*t++ = n % 10 + '0';
} while ((n /= 10) > 0);
} while ((n /= 10) > 0);
}

int main(void) {
char s[255];
int n = 2016;
itoa(n, s);
printf("itoa(\"%d\") = %s\n", n,s);
return 0;
translate to pointers
}
<3min repl>
reverseString.c
#include <stdio.h>
C
#include <string.h>
the comma operator allows evaluating
int main(void) {
multiple expressions in for statement.
char s[] = "Hello";
(general idea: pair of expressions separated
int i, j, tmp;
by comma is evaluated left to right)

for (i = 0, j = strlen(s)-1; i < j; i++, j--){


tmp = s[i];
s[i] = s[j];
s[j] = tmp;
} s H e l l o \0
printf("s = %s\n", s); i j
return 0;
} what does it do?

<30sec brains>
reverseStringWithPointers.c
#include <stdio.h>
C
#include <string.h>
int main(void) {
char s[] = "Hello";
char *i = s, tmp;
char *j = s + strlen(s) - 1; // j points at last char
while (i < j) {
tmp = *i,
*i++ = *j,
*j-- = tmp;
} s H e l l o \0
printf("s = %s\n", s); i j
return 0;
} same using pointers

<30sec brains>
deleteThisCharfromStr.c
#include <stdio.h> H e l l o \0
i
// works by copying every non-c to the current j position
char *deleteThisCharfromStr(char s[], int c) {
j
int i, j; char *i, *j;
for (i = j = 0; s[i] != '\0'; i++) for (i = j = s; *i != '\0'; i++)
if (s[i] != c) if (*i != c)
s[j++] = s[i];
*j++ = *i;
s[j] = '\0';
*j = '\0';
return s;
}
int main(void) {
char s[] = "Hello World";
printf("Delete l from (\"%s\") = %s\n", s, deleteThisCharfromStr(s, 'l'));
return 0;

<3min repl>
}
translate to pointers
priority (also in
priority.ppt)
so far we have placed parentheses to make things clear

t++
(*t)++;
(*(t+4))++;

...but what is the natural way pointer expressions are to be read?


how to do it
1. what operations are involved
2. look up their priority and rank them
3. look up the associated associativity

*ip++ // ++ has prio


= *(ip++)
= *ip, pointer++

++*ip // same prio


*ip++// right-left!
= ++(*ip)
= contents++, *ip

++*ip

<30sec brains>
operators * and & bind stronger than arithmetic operations

y = *ip + 1; // y contains the value that


// ip points to, incremented by 1
*ip += 1; // the variable that ip points to is incremented
++*ip; // both prio 14, R-L associativity, so same as before

iq = ip; // assignment; iq now points to the same address as ip

(*ip)++; // brackets are required because


// postfix++ is prio 15 over + prio 14

// L-R associativity of post increment operator ++


*ip++; // ip is dereferenced, then incremented

You might also like