1- Pointers
Pointers
- A pointer is declared like a variable, but with * after the type
- What stored in a pointer variable is an address.
- Operator & can take the address of an object or a variable of fundamental types
- Operator * can take the content that the pointer points to
pointer.cpp
cpp
#include <iostream>
using namespace std;
int main()
{
int num = 10;
int * p1 = NULL, * p2 = NULL; // declaration, initialize to 0
p1 = # // take the address of num, assign to p1
p2 = # // take the address of num, assign to p2
cout << "num = " << num << endl;
*p1 = 20; // assign to num
cout << "num = " << num << endl;
*p2 = 30; // assign to num
cout << "num = " << num << endl;
return 0;
}
Structure member accessing
- p->member
- (*p).member
pointer-struct.cpp
cpp
#include <iostream>
#include <cstring>
using namespace std;
struct Student
{
char name[4];
int born;
bool male;
};
int main()
{
Student stu = {"Yu", 2000, true};
Student * pStu = &stu;
cout << stu.name << " was born in " << stu.born
<< ". Gender: " << (stu.male ? "male" : "female") << endl;
strncpy(pStu->name, "Li", 4);
pStu->born = 2001;
(*pStu).born = 2002;
pStu->male = false;
cout << stu.name << " was born in " << stu.born
<< ". Gender: " << (stu.male ? "male" : "female") << endl;
return 0;
}
Print out the address
- Since the value of a pointer is an address, we can print it out
cpp
printf("Address of stu: %p\n", pStu); //C style
cout << "Address of stu: " << pStu << endl; //C++ style
cout << "Address of stu: " << &stu << endl;
cout << "Address of member name: " << &(pStu->name) << endl;
cout << "Address of member born: " << &(pStu->born) << endl;
cout << "Address of member male: " << &(pStu->male) << endl;
- The address should be an unsigned 32-bit or 64-bit integer
cpp
cout << "sizeof(pStu) = " << sizeof(pStu) << endl;
Pointers of Pointers
- Pointers are variables, they also have address
pointer-pointer.cpp
cpp
#include <iostream>
using namespace std;
int main()
{
int num = 10;
int * p = #
int ** pp = &p;
*(*pp) = 20;
cout << "num = " << num << endl;
return 0;
}
Constant Pointers
const-pointer.cpp
cpp
#include <iostream>
using namespace std;
int foo(const char * p)
{
// the value that p points to cannot be changed
// play a trick?
char * p2 = p; //syntax error
//...
return 0;
}
int main()
{
int num = 1;
int another = 2;
//You cannot change the value that p1 points to through p1
const int * p1 = #
*p1 = 3; //error
num = 3; //okay
//You cannot change value of p2 (address)
int * const p2 = #
*p2 = 3; //okay
p2 = &another; //error
//You can change neither
const int* const p3 = #
*p3 = 3; //error
p3 = &another; // error
return 0;
}
const int *: 不可以修改指针指向的内容
int * const: 不可以修改指针本身(地址)
const int * const: 既不可以修改指针指向的内容也不可以修改指针本身
const int * p;
char * p2 = p;
不能将const 的指针赋值给普通指针
2- Pointers and Arrays
- Use & operator to get the address of elements
pointer-array.cpp
cpp
#include <iostream>
using namespace std;
struct Student
{
char name[4];
int born;
bool male;
};
int main()
{
// Part One
Student students[128];
Student * p0 = &students[0];
Student * p1 = &students[1];
Student * p2 = &students[2];
Student * p3 = &students[3];
printf("p0 = %p\n", p0);
printf("p1 = %p\n", p1);
printf("p2 = %p\n", p2);
printf("p3 = %p\n", p3);
//the same behavior
students[1].born = 2000;
p1->born = 2000;
// Part Two
printf("&students = %p\n", &students);
printf("students = %p\n", students);
printf("&students[0] = %p\n", &students[0]);
Student * p = students;
p[0].born = 2000;
p[1].born = 2001;
p[2].born = 2002;
printf("students[0].born = %d\n", students[0].born);
printf("students[1].born = %d\n", students[1].born);
printf("students[2].born = %d\n", students[2].born);
return 0;
}
Array name
- You can consider an array name as a pointer
Pointer arithmetic
- p + num or num + p points to the num-th element of the array p
- p-num points to the -num-th element
arithmetic.cpp
cpp
#include <iostream>
using namespace std;
#define PRINT_ARRAY(array, n) \
for (int idx = 0; idx < (n); idx++) \
cout << "array[" << idx << "] = " << (array)[idx] << endl;
int main()
{
int numbers[4] = {0, 1, 2, 3};
PRINT_ARRAY(numbers, 4)
int * p = numbers + 1; // point to the element with value 1
p++; // point to the element with value 2
cout << "numbers = " << numbers << endl;
cout << "p = " << p << endl;
*p = 20; //change number[2] from 2 to 20
*(p-1) = 10; //change number[1] from 1 to 10
p[1] = 30; //change number[3] from 3 to 30
PRINT_ARRAY(numbers, 4)
return 0;
}
- The following are equivalent
cpp
int i = ...;
int *p = ...;
p[i] = 3;
*(p + i) = 3;
int *p2 = p + i;
*p2 = 3;
- Be careful of out-of-bound
cpp
int num = 0;
int * p = #
p[-1] = 2; // out of bound
p[0] = 3; // okay
*(p+1) = 4; // out of bound
bound.cpp
cpp
#include <iostream>
using namespace std;
int main()
{
int a;
int num = 0;
int * p = #
p[-1] = 2; //out of bound
p[0] = 3; //okay
*(p+1) = 4; //out of bound
cout << "num = " << num << endl;
return 0;
}
程序越界
Differences between a pointer and an array
- Array is a constant pointer
- The total size of a ll elements in an array can be got by operator sizeof
- sizeof operator to a pointer will return the size of the address (4 or 8)
cpp
int numbers[4] = {0, 1, 2, 3};
int * p= numbers;
cout << sizeof(numbers) << endl; // 4 * sizeof(int)
cout << sizeof(p) << endl; // 4 or 8
cout << sizeof(double *) << endl; // 4 or 8
3- allocate-memory: C style
Program memory
The address space of a program contains several data segments
- Code: executable code
- Data: initialized static variables
- BSS: uninitialized static data including variables and constants
- Heap: dynamically allocated memory
- Stack: local variable, call stack
stack-heap.cpp
cpp
#include <iostream>
using namespace std;
int main()
{
int a = 0;
int b = 0;
int c = 0;
cout << &a << endl;
cout << &b << endl;
cout << &c << endl;
int * p1 = (int*) malloc (4);
int * p2 = (int*) malloc (4);
int * p3 = (int*) malloc (4);
cout << p1 << endl;
cout << p2 << endl;
cout << p3 << endl;
free(p1);
free(p2);
free(p3);
return 0;
}
- But different CPU architectures may be different
Memory allocation
- Allocate size bytes of uninitialized storage
cpp
void* malloc(size_t size);
- Allocate 4 bytes and convert the pointer to (int *) explicitly
cpp
int * p1 = (int *)malloc (4);
- Question:
cpp
int * p1 = (int *) malloc(3);
pointer-convert.cpp
cpp
#include <iostream>
using namespace std;
int main()
{
int * pi = new int[2]();
unsigned char * pc = (unsigned char*)pi;
pc[1] = 1;
pc[5] = 2;
cout << "pi[0] = " << pi[0] << endl;
cout << "pi[1] = " << pi[1] << endl;
delete []pi;
//delete []pc;
return 0;
}
Memory deallocation
- The dynamically allocated memory must be deallocated explicitly
cpp
void free(void* ptr);
- Question:
cpp
p = (int *) malloc (4 * sizeof(int));
p = (int *) malloc(8 * sizeof(int));
free(p);
第一次申请的内存丢失了,无法管理也无法销毁
cpp
void foo()
{
int* p = (int *) malloc( sizeof(int));
return;
} //memory leak
内存泄漏
memory leak.cpp
cpp
#include <stdio.h>
#include <stdlib.h>
void foo()
{
int* p = (int *) malloc( sizeof(int));
return;
} //memory leak
int main()
{
int * p = NULL;
p = (int *) malloc(4 * sizeof(int));
// some statements
p = (int *) malloc(8 * sizeof(int));
// some statements
free (p);
// the first memory will not be freed
for(int i = 0; i < 1024; i++)
{
p = (int *) malloc(1024 * 1024 * 1024);
}
printf("End\n");
return 0;
}
4- Allocate memory: CPP Style
operator new and new[]
- Operator new is similar with malloc() but with more features
newdelete.cpp
cpp
#include <iostream>
using namespace std;
struct Student
{
char name[4];
int born;
bool male;
};
int main()
{
//allocate an int, default initializer (do nothing)
int * p1 = new int;
//allocate an int, initialized to 0
int * p2 = new int();
//allocate an int, initialized to 5
int * p3 = new int(5);
//allocate an int, initialized to 0
int * p4 = new int{};//C++11
//allocate an int, initialized to 5
int * p5 = new int {5};//C++11
//allocate a Student object, default initializer
Student * ps1 = new Student;
//allocate a Student object, initialize the members
Student * ps2 = new Student {"Yu", 2020, 1}; //C++11
//allocate 16 int, default initializer (do nothing)
int * pa1 = new int[16];
//allocate 16 int, zero initialized
int * pa2 = new int[16]();
//allocate 16 int, zero initialized
int * pa3 = new int[16]{}; //C++11
//allocate 16 int, the first 3 element are initialized to 1,2,3, the rest 0
int * pa4 = new int[16]{1,2,3}; //C++11
//allocate memory for 16 Student objects, default initializer
Student * psa1 = new Student[16];
//allocate memory for 16 Student objects, the first two are explicitly initialized
Student * psa2 = new Student[16]{{"Li", 2000,1}, {"Yu", 2001,1}}; //C++11
cout << psa2[1].name << endl;
cout << psa2[1].born << endl;
return 0;
}
Operator delete and delete[]
- Destroys object/objects allocated by new and free memory
cpp
//deallocate memory
delete p1;
//deallocate memory
delete ps1;
//deallocate the memory of the array
delete pa1;
//deallocate the memory of the array
delete []pa2;
//deallocate the memory of the array, and call the destructor of the first element
delete psa1;
//deallocate the memory of the array, and call the destructors of all the elements
delete []psa2;