{C}
Lecture 10
Pointers
Basics
char c; declares a variable of type character
char* pc; declares a variable of type pointer to character
char** ppc; declares a variable of type pointer to pointer to character
c = ‘a’; initialize a character variable
pc = &c; get the address of a variable
ppc = &pc; get the address of a variable
c == *pc == **ppc
2
‘a’ c
pc
ppc
Experimenting...
#include <stdio.h>
int main() {
char c='a';
char* pc=&c;
char** ppc=&pc;
printf("%p\n", pc);
printf("%p\n", ++pc);
printf("%p\n", ppc);
printf("%p\n", ++ppc);
}
3
0x7fff6540097b
0x7fff6540097c
0x7fff65400970
0x7fff65400978
Basics
A variable declared as a pointer has the size of a memory
address on the current architecture (e.g. 4 bytes or 8 bytes)
Incrementing a pointer adds a multiple of the pointer target
size (e.g. 1 for characters, 2 for short, …)
Pointers are initialized with addresses obtained by the &
operator or the value NULL
A pointer can be dereferenced by prefix a pointer value with
the * operator
Attempting to dereference a NULL pointer will result in an
error caught by the hardware (bus error or segmentation fault)
4
Examples
char c = ‘a’; value of c = 97, address of c=0xc00f4a20
char* pc = &c; value of pc=0xc00f4a20, address of pc=0xc00eaa1c
pc value 0xc00f4a20
*pc value 97
**pc compile warning, runtime error
c value 97
&c value 0xc00f4a20
&&c compile error
5
Pointer to pointer
int i = 5;
int *p = &i;
int **pp = &p;
Think about it as *pp is an int*, that is, p is a pointer to
pointer to int
char *s[3] = {"John", "Dan", "Christopher"};
s is a char **
char **p = s;
6
Character arrays and pointers
What’s the difference between char s[] and char* s?
As a declaration, none:
int f(char* s)
int f(char s[])
As a definition:
char s[] = “hello”
- Allocates the string in modifiable memory, and defines s to be a pointer to the head of the string.!
- Can change the contents, but s will always point to the same place!
- Can’t write: s = p; an array name is not a variable (i.e., can’t be used as an l-value)!
char* s = “hello”
- Allocates a pointer (freely modifiable)!
- Allocates a string (not modifiable) - typically allocated in the text segment of memory!
- s points to the beginning of the string, but modifications to the string (e.g., *s = ‘x’) is undefined!
- s can be reassigned to point to other strings
7
Strings
When we pass a char array as a parameter, C makes a
copy of the address of the first array element, and passes
it (as a char *) to the function."
void myFunc(char *myStr) {
...
}
int main(int argc, char *argv[]) {
char str[6];
strcpy(str, "apple");
myFunc(str); // equivalent
!!!!!!!!!!!!!!!!!!!!!//!!!char!*strAlt!=!str;!
!!!!!!!!!!!!!!!!!!!!!//!!!myFunc(strAlt);}!!!!!!
!!!!!…!
}!
8
Summary
9
If you are invoking a function that is not expected to change the
input being supplied, pass the data type itself.
If you are invoking a function that is expected to perform a side-
effect on the argument, pass the location of what you would like
to modify.
If a function takes an address (pointer) as a parameter, it can go
to that address if it needs the actual value.
In general, setting a function parameter equal to a new value
is just setting the function’s own copy of the parameter equal to
some new value.
Double Pointers
10
Suppose we want to write a function skipSpaces that modifies a
string pointer to skip past any initial spaces.
int main(int argc, char *argv[]) {!
char *str = " hello";!
skipSpaces(str);!
printf("%s", str); // should print "hello"
}
void skipSpaces(char *strPtr) {
...
}
What is wrong with this signature?
Double Pointers
Need skipSpaces to share the pointer to the string, and not
just the string!
11
void skipSpaces(char **strPtr) {
int numSpaces = strspn(*strPtr, " ");
*strPtr += numSpaces;
}
int main(int argc, char *argv[]) {
char *myStr = " hi";
skipSpaces(&myStr);
printf("%s\n", myStr); // “hi”
return 0;
}
strspn returns the length of the initial portion of
str1 which consists only of characters
that are part of str2.
// updates the pointer (myStr) that points
// to the string “ hi”
Double Pointers
12
50
Pointers to Strings
Address
Value
0x105
0xf
0xf0
0x105
0x13
'\0'
0x12
'i'
0x11
'h'
0x10
' '
0xf
' '
DATA SEGMENT
void skipSpaces(char **strPtr) {
int numSpaces = strspn(*strPtr, " ");
*strPtr += numSpaces;
}
int main(int argc, char *argv[]) {
char *myStr = " hi";
skipSpaces(&myStr);
printf("%s\n", myStr); // hi
return 0;
}
myStr
strPtr
main()
skipSpaces()
STACK
void skipSpaces(char **strPtr) {
int numSpaces = strspn(*strPtr, " ");
*strPtr += numSpaces;
}
int main(int argc, char *argv[]) {
char *myStr = " hi";
skipSpaces(&myStr);
printf("%s\n", myStr); // “hi”
return 0;
}
Pointer Arithmetic
Generalizing to arrays of strings
void skipSpaces(char **strPtr, size_t size) {
for (int i = 0; i < size; i++) {
char* s = *(strPtr + i);
int numSpaces = strspn(s, " ");
*(strPtr + i) += numSpaces;
}
}
int main(int argc, char *argv[]) {
char* s[5] = { " hello", " goodbye", " hi",
!! “ bye", "seeya" };
skipSpaces(s, 5);
for (int i = 0; i < 5; i++) { printf("%s\n", s[i]); }
return 0;
}
13
Pointer Arithmetic
14
When you do pointer arithmetic, you are adjusting the pointer by a
certain number of places (e.g. characters).
char* str = "apple";
char* str1 = str+1;
char* str3 = str+3;
//e.g.!0xff0!!
//e.g.0xff1!!
//e.g.0xff3!
int* nums = ...
int* nums1 = nums + 1;
int* nums3 = nums + 3;
// e.g. 0xff0
// e.g. 0xff4
// e.g. 0xffc
Pointer arithmetic does not work in bytes. Instead, it works
in the size of the type it points to.
When you use bracket notation with a pointer, you are
actually performing pointer arithmetic and dereferencing:
Pointer Arithmetic and Types
15
How does the code know how many bytes it should add when performing
pointer arithmetic?
int nums[] = {1, 2, 3};
// How does it know to add 4 bytes here?
int* intPtr = nums + 1;
char str[6];
strcpy(str, "CS240");
// How does it know to add 1 byte here?
char *charPtr = str + 1;
At compile time, C can figure out the sizes of different data types, and the sizes of what
they point to.
For this reason, when the program runs, it knows the correct number of bytes to
address or add/subtract for each data type.
Const Pointers
16
Use const with pointers to indicate that the data that is pointed to cannot change.
char str[6];
strcpy(str, "Hello");
const char *s = str;
// Cannot use s to change characters it points to
s[0] = 'h'; // Disallowed
// This function promises to not change str’s characters
int func(const char *str) { // compiler warning and error
char *strToModify = str;
strToModify[0] = ...
}
const char c = ‘h'; // cannot modify this char
const char *str = … // cannot modify char pointed to by str
const char **strPtr = … // cannot modify chars pointed to by *strPtr
char* const str = … // cannot modify the pointer str
const char * const str = … // cannot modify str or the string it points to