pointer
pointer
Basic concept of pointers
The Role of Pointers: Allows indirect memory access through pointers.
- Memory addresses start from 0 and are typically represented in hexadecimal numbers.
- Pointer variables can be used to store addresses.
Definition and Usage of Pointer Variables
Pointer variable definition syntax: 数据类型 * 变量名;
Example:
int main() {
//1、指针的定义
int a = 10; //定义整型变量a
//指针定义语法: 数据类型 * 变量名 ;
int * p;
//指针变量赋值
p = &a; //指针指向变量a的地址
cout << &a << endl; //打印数据a的地址
cout << p << endl; //打印指针变量p
//2、指针的使用
//通过*操作指针变量指向的内存
cout << "*p = " << *p << endl;
return 0;
}
Running/Observing the results: After running, the example will print variable values or addresses; address values depend on the runtime environment, so focus on observing the relative positioning and pointer changes of similar objects.
The difference between pointer variables and ordinary variables is that a pointer variable stores the address of another variable, while an ordinary variable stores the actual data. A pointer allows you to indirectly access and manipulate the data of other variables.
- Ordinary variables store data, while pointer variables store addresses.
- Pointer variables can access the memory space they point to using the "*" operator, a process known as dereferencing.
Summary 1: We can use the & symbol to obtain the address of a variable.
Summary 2: Using pointers to record addresses
Summary 3: Dereferencing a pointer variable allows manipulation of the memory it points to.
The memory space occupied by a pointer depends on the system architecture and the programming language. In most cases:
- On a 32-bit system, a pointer typically occupies 4 bytes.
- On a 64-bit system, a pointer typically occupies 8 bytes.
However, the exact size can vary based on the language implementation, compiler settings, and hardware platform. For example, in some embedded systems or specific configurations, pointer sizes may differ. Always refer to the language specifications or system documentation for precise details.
Question: Pointers are a type of data type, so how much memory space does this data type occupy?
Answer: The size of a pointer in memory depends on the system architecture:
- In a 32-bit system, a pointer typically occupies 4 bytes.
- In a 64-bit system, a pointer typically occupies 8 bytes.
This allows the pointer to store a memory address corresponding to the system’s addressable memory range.
Example:
int main() {
int a = 10;
int * p;
p = &a; //指针指向数据a的地址
cout << *p << endl; //* 解引用
cout << sizeof(p) << endl;
cout << sizeof(char *) << endl;
cout << sizeof(float *) << endl;
cout << sizeof(double *) << endl;
return 0;
}
Running/Observing the results: After running, the example will print variable values or addresses; address values depend on the runtime environment, so focus on observing the relative positioning and pointer changes of similar objects.
Summary: All pointer types are 4 bytes in a 32-bit operating system.
Null Pointer and Dangling Pointer
Null pointer: A pointer variable pointing to memory address 0
Purpose: Initializing pointer variables
Note: The memory pointed to by a null pointer cannot be accessed.
Example 1: Null pointer
int main() {
//指针变量p指向内存地址编号为0的空间
int * p = NULL;
//访问空指针报错
//内存编号0 ~255为系统占用内存,不允许用户访问
cout << *p << endl;
return 0;
}
Running/Observing the results: After running, the example will print variable values or addresses; address values depend on the runtime environment, so focus on observing the relative positioning and pointer changes of similar objects.
Dangling pointer: A pointer variable that points to illegal memory space.
Example 2: Wild pointer
int main() {
//指针变量p指向内存地址编号为0x1100的空间
int * p = (int *)0x1100;
//访问野指针报错
cout << *p << endl;
return 0;
}
Running/Observing the results: After running, the example will print variable values or addresses; address values depend on the runtime environment, so focus on observing the relative positioning and pointer changes of similar objects.
Summary: Null pointers and wild pointers are not allocated memory spaces we requested, so never dereference them.
const modifier for pointers in C/C++ creates different pointer constness scenarios. Here's the breakdown:
1. Pointer to non-const (const modifies what's pointed to):
const int* ptr; // or int const* ptr;
- The data pointed to cannot be modified through this pointer.
- The pointer itself can be changed to point elsewhere.
*ptr = 10; // Error: cannot modify the value
ptr = &anotherInt; // OK: can change the pointer's target
2. Const pointer (const modifies the pointer itself):
int* const ptr = &someInt;
- The pointer itself cannot be changed; it must be initialized.
- The data it points to can be modified.
ptr = &anotherInt; // Error: cannot change the pointer
*ptr = 10; // OK: can modify the pointed-to value
3. Const pointer to const data (both are const):
const int* const ptr = &someInt;
- Neither the pointer nor the data can be modified through this pointer.
ptr = &anotherInt; // Error
*ptr = 10; // Error
Key Point: The const applies to whatever is immediately to its left. If nothing is to its left (as in const int*), it modifies the next item (the int).
Quick Reference Table:
| Declaration | Can modify *ptr? | Can modify ptr? | Meaning |
|---|---|---|---|
int* ptr | Yes | Yes | Normal pointer to non-const data. |
const int* ptr | No | Yes | Pointer to const data. |
int* const ptr | Yes | No | Const pointer to non-const data. |
const int* const ptr | No | No | Const pointer to const data. |
This distinction is crucial for API design, function parameters (to prevent accidental modification), and ensuring data integrity.
There are three cases of const-modifying pointers.
- Const-modified pointer --- constant pointer
- const-modified constant --- pointer constant
- const qualifies both pointers and constants.
Example:
int main() {
int a = 10;
int b = 10;
//const修饰的是指针,指针指向可以改,指针指向的值不可以更改
const int * p1 = &a;
p1 = &b; //正确
//*p1 = 100; 报错
//const修饰的是常量,指针指向不可以改,指针指向的值可以更改
int * const p2 = &a;
//p2 = &b; //错误
*p2 = 100; //正确
//const既修饰指针又修饰常量
const int * const p3 = &a;
//p3 = &b; //错误
//*p3 = 100; //错误
return 0;
}
Running/Observing Results: This is a syntax or interface example, focus on the writing style; run and verify after incorporating it into a complete program.
Tip: Look at what immediately follows the const. If it's a pointer, it's a constant pointer; if it's a constant, it's a pointer constant.
pointers and arrays
Purpose: Access elements in an array using a pointer.
Example:
int main() {
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int * p = arr; //指向数组的指针
cout << "第一个元素: " << arr[0] << endl;
cout << "指针访问第一个元素: " << *p << endl;
for (int i = 0; i < 10; i++)
{
//利用指针遍历数组
cout << *p << endl;
p++;
}
return 0;
}
Running/Observation Results: After running, the corresponding content will be printed according to the output statements. The variable values can be inferred based on the order of initialization, assignment, and function calls.
Pointers and functions
Purpose: Using pointers as function parameters allows modification of the actual parameters' values.
Example:
//值传递
void swap1(int a ,int b)
{
int temp = a;
a = b;
b = temp;
}
//地址传递
void swap2(int * p1, int *p2)
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
int main() {
int a = 10;
int b = 20;
swap1(a, b); // 值传递不会改变实参
swap2(&a, &b); //地址传递会改变实参
cout << "a = " << a << endl;
cout << "b = " << b << endl;
return 0;
}
Running/Observing the results: After running, the example will print variable values or addresses; address values depend on the runtime environment, so focus on observing the relative positioning and pointer changes of similar objects.
Summary: If you don't want to modify the actual parameter, use value passing; if you want to modify the actual parameter, use pass-by-reference.
pointers, arrays, functions
Case Study: Encapsulate a function that uses bubble sort to sort an integer array in ascending order.
For example, the array: int arr10 = { 4,3,6,9,1,2,10,8,7,5 };
Example:
//冒泡排序函数
void bubbleSort(int * arr, int len) //int * arr 也可以写为int arr[]
{
for (int i = 0; i < len - 1; i++)
{
for (int j = 0; j < len - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
//打印数组函数
void printArray(int arr[], int len)
{
for (int i = 0; i < len; i++)
{
cout << arr[i] << endl;
}
}
int main() {
int arr[10] = { 4,3,6,9,1,2,10,8,7,5 };
int len = sizeof(arr) / sizeof(int);
bubbleSort(arr, len);
printArray(arr, len);
return 0;
}
Running/Observation Results: After running, the corresponding content will be printed according to the output statements. The variable values can be inferred based on the order of initialization, assignment, and function calls.
Summary: When an array name is passed as an argument to a function, it degenerates into a pointer to the first element.