指针允许直接操作内存地址,从而实现对数据的灵活控制。
指针的概念
指针是一个变量,其存储的是另一个变量的内存地址。在C++中,每个变量在内存中都有一个唯一的地址,指针变量可以存储这个地址。声明指针时,需要指定指针所指向的数据类型,例如,int* p;
声明了一个指向整型数据的指针变量p
。
指针运算
- 解引用(Dereferencing):使用
*
操作符获取指针所指向的变量的值。例如,如果p
指向一个整数,那么*p
就是该整数的值。 - 指针加减(Pointer Arithmetic):可以对指针进行加减运算,通常用于遍历数组。例如,
p++
使指针向后移动到下一个元素(假设是数组的话)。 - 比较:指针之间可以进行关系运算,如
<
,>
,<=
,>=
,==
,!=
,用于比较它们所指向的地址。
指针与数组
在C++中,数组名实际上就是一个指向数组首元素的常量指针。这意味着你可以用指针对数组进行操作,比如遍历数组:
int arr[5] = {1, 2, 3, 4, 5}; int* ptr = arr; // ptr现在指向数组arr的首元素 for(int i = 0; i < 5; ++i) { std::cout << *(ptr + i) << std::endl; // 通过指针访问数组元素 }
堆内存分配
C++提供了两种内存分配方式:栈(stack)和堆(heap)。栈内存由编译器自动管理,而堆内存需要手动管理。
- 栈内存分配:局部变量通常存储在栈上,生命周期与定义它的函数或代码块相同。
- 堆内存分配:使用
new
操作符在堆上动态分配内存。当不再需要时,应使用delete
释放内存。
例如,动态分配一个整型数组:
int* heapArr = new int[5]; // 在堆上分配一个大小为5的整型数组 heapArr[0] = 1; // ... 对其他元素赋值 delete[] heapArr; // 使用完毕后释放内存
const指针
const
指针用来表示指针所指向的数据是不可更改的。有两种主要的用法:
- 指向const的指针:指针指向的值不能被改变,但指针本身可以指向另一个值。声明形式如
const int* ptr
,意味着ptr
指向的整数是常量。
const int num = 5; const int* pConst = # // pConst指向一个常量整数 // *pConst = 10; // 错误:不能通过pConst修改num的值
- const指针:指针一旦初始化后,就不能再指向其他地址,但指向的数据可以修改。声明形式如
int* const ptr
。
int num = 5; int* const pConstAddr = # *pConstAddr = 10; // 正确:可以通过指针修改num的值 // pConstAddr = &anotherNum; // 错误:不能改变pConstAddr的地址
指针与函数
- 函数指针:指向函数的指针,可以用来存储函数的地址,进而通过指针调用函数。
void greet() { std::cout << "Hello!" << std::endl; } void (*funcPtr)() = &greet; // 定义一个函数指针并初始化 funcPtr(); // 通过函数指针调用greet函数
- 指针函数:返回值为指针的函数。
int* returnIntPtr() { static int value = 10; return &value; } int main() { int* ptr = returnIntPtr(); std::cout << *ptr << std::endl; // 输出10 }
字符指针
字符指针通常用来指向字符串或者单个字符,可以用来操作字符串。
char str[] = "Hello"; char* cPtr = str; // cPtr指向字符串"Hello" std::cout << cPtr << std::endl; // 输出"Hello"
指针数组
指针数组是一组指向特定类型数据的指针。
int num1 = 1, num2 = 2, num3 = 3; int* ptrArray[3] = {&num1, &num2, &num3}; // 指针数组,每个元素指向一个整数 std::cout << *ptrArray[0] << std::endl; // 输出1
命令行参数
在C++中,main
函数可以接受两个参数,第一个是命令行参数的数量,第二个是一个指向这些参数的指针数组(字符指针数组),这些参数以NULL结束。
#include <iostream> int main(int argc, char* argv[]) { for(int i = 0; i < argc; ++i) { std::cout << "Argument " << i << ": " << argv[i] << std::endl; } return 0; }
函数指针数组
可以创建一个数组,其中每个元素都是指向函数的指针,这样就可以通过索引来调用不同的函数。
void func1() { std::cout << "Function 1 called" << std::endl; } void func2() { std::cout << "Function 2 called" << std::endl; } typedef void (*FuncPtr)(); // 函数指针类型别名 FuncPtr funcPtrArray[] = {func1, func2}; int main() { funcPtrArray[0](); // 调用func1 funcPtrArray[1](); // 调用func2 }
C++中指针的灵活性和强大功能,但也强调了正确使用它们的重要性,以避免常见的编程错误。