Lecture 27 - Pointers I
Goals
- Look at how arrays are passed as arguments to functions
- Learn the basics of pointers
Passing Arrays
At this point, the only thing that we have passed to our functions are integers, which is a little boring. You can probably imagine that passing longs, chars, floats and doubles would be pretty similar (and you would be right). But, what about more interesting things like arrays and strings?
int f(int a[])
{
int result;
result = a[0] + a[1];
return result;
}
int main(int argc, char *argv[])
{
int a[2];
int result;
a[0] = 0x42;
a[1] = 0x24;
result = f(a);
return result;
}This gives us
0000000000000000 <f>:
0: 55 push rbp
1: 48 89 e5 mov rbp,rsp
4: 48 89 7d e8 mov QWORD PTR [rbp-0x18],rdi
8: 48 8b 45 e8 mov rax,QWORD PTR [rbp-0x18]
c: 8b 10 mov edx,DWORD PTR [rax]
e: 48 8b 45 e8 mov rax,QWORD PTR [rbp-0x18]
12: 48 83 c0 04 add rax,0x4
16: 8b 00 mov eax,DWORD PTR [rax]
18: 01 d0 add eax,edx
1a: 89 45 fc mov DWORD PTR [rbp-0x4],eax
1d: 8b 45 fc mov eax,DWORD PTR [rbp-0x4]
20: 5d pop rbp
21: c3 ret
0000000000000022 <main>:
22: 55 push rbp
23: 48 89 e5 mov rbp,rsp
26: 48 83 ec 20 sub rsp,0x20
2a: 89 7d ec mov DWORD PTR [rbp-0x14],edi
2d: 48 89 75 e0 mov QWORD PTR [rbp-0x20],rsi
31: c7 45 f4 42 00 00 00 mov DWORD PTR [rbp-0xc],0x42
38: c7 45 f8 24 00 00 00 mov DWORD PTR [rbp-0x8],0x24
3f: 48 8d 45 f4 lea rax,[rbp-0xc]
43: 48 89 c7 mov rdi,rax
46: e8 00 00 00 00 call 4b <main+0x29>
4b: 89 45 fc mov DWORD PTR [rbp-0x4],eax
4e: 8b 45 fc mov eax,DWORD PTR [rbp-0x4]
51: c9 leave
52: c3 ret
- On lines 31 and 38, we can see the values being loaded into the array
- On 3f, we use
lea– the “load effective address” instruction. This computes the address using our addressing format and then saves the address itself. - The result is stored into register
rdi, which is argument 1 - in
f(), the value of the argument is stored at[rbp-0x18](and then put intorax) - on line c, we can see it accessing memory using the address in
raxto get the first value - on line 12, the address is advanced by 4 and then on the next line we access memory again for the second value
The big lesson here is that we aren’t passing the entire array – we are passing the address of the array.
Passing Arrays
Last time we looked at the mechanics of how arrays are passed and determined that we pass around the address, not the values
What will this print out?
int f(int a[])
{
a[1] = 0x96;
printf("during\n");
for (int i = 0; i <= 2; i++)
{
printf("%x\n", a[i]);
}
}
int main(int argc, char *argv[])
{
int a[2];
int result = 0x32;
a[0] = 0x42;
a[1] = 0x24;
printf("before\n");
for (int i = 0; i <= 2; i++)
{
printf("%x\n", a[i]);
}
f(a);
printf("after\n");
for (int i = 0; i <= 2; i++)
{
printf("%x\n", a[i]);
}
}$ ./func5
before
42
24
32
during
42
96
32
after
42
96
32
There are two things going on here - we are walking off the end of the array and accessing the next variable (the 0x32s) - we can change the values in the array in the function and they stay changed! (we never had two arrays – so our edits happened to the only one that we had)
Pointers
Pointers are the nature compliment to our “address of” operator (&). A pointer is, in essence, a variable that can hold an address. The concept itself isn’t that hard, but the syntax is…. a little unfortunate.
To create a pointer, we add a star after the type. Note that this means that pointers are typed, this is so the compiler can figure out how big the thing being stored there is (though we do have ways to make this explicit or to typecast the type of an expression).
int x = 42;
int * p = &x; //p has the address of xIf we want to read the value stored at p, we dereference it by putting a star in front of it
int y = *p; // y is now 42This also works on the left hand side of assignment statements, though here we are assigning into that memory location
*p = 255; // x is now 255What might we use this for?
Take a moment to see if you can figure out this function
void g(int * a, int * b){
int c = *a;
*a = * b;
*b = c;
}This is a swap function that swaps the values of two variables. The big implication here is that pointers allow us to pass in values that can be changed! of course this purely perceptual – we actually pass in the addresses here and those we can’t change.
Mechanical level
vocabulary
Skills