指针、数组与指针算术:深入理解C++内存管理
核心概念:指针与数组的等价性
指针和数组基本等价的原因在于指针算术和C++内部处理数组的方式。指针算术的核心规则是:将指针变量加1后,增加的量等于它指向的类型的字节数。
double*pw;// pw + 1 增加8字节(double通常8字节)short*ps;// ps + 1 增加2字节(short通常2字节)指针算术的实战演示
#include<iostream>usingnamespacestd;intmain(){doublewages[3]={10000.0,20000.0,30000.0};shortstacks[3]={3,2,1};double*pw=wages;// 数组名即首元素地址short*ps=&stacks[0];// 等价写法cout<<"pw = "<<pw<<", *pw = "<<*pw<<endl;pw=pw+1;// 增加8字节cout<<"pw = "<<pw<<", *pw = "<<*pw<<endl;cout<<"ps = "<<ps<<", *ps = "<<*ps<<endl;ps=ps+1;// 增加2字节cout<<"ps = "<<ps<<", *ps = "<<*ps<<endl;return0;}数组表示法与指针表示法的等价性
C++编译器将数组表达式转换为指针表达式:
arrayName[i]等价于*(arrayName+i)pointerName[i]等价于*(pointerName+i)关键区别:
pointerName=pointerName+1;// 合法arrayName=arrayName+1;// 非法!数组名是常量指针与字符串的关系
C-风格字符串实际上是字符数组,数组名即字符串首地址:
charflower[10]="rose";cout<<flower;// 输出:roseconstchar*bird="wren";// 字符串字面值是常量cout<<bird;// 输出:wren重要警告:不要使用未初始化的指针或字符串常量接收输入!
使用new创建动态结构
动态结构允许在运行时分配内存:
structInflatable{charname[20];floatvolume;doubleprice;};intmain(){Inflatable*ps=newInflatable;// 动态分配结构// 访问结构成员cin.get(ps->name,20);// 使用箭头运算符cin>>(*ps).volume;// 使用解引用+点运算符cin>>ps->price;deleteps;// 释放内存return0;}内存管理的三种方式
1. 自动存储(栈)
- 函数内部定义的局部变量
- 函数调用时自动创建,函数结束时自动销毁
- 使用栈数据结构(LIFO原则)
2. 静态存储
- 全局变量或使用
static关键字 - 程序整个生命周期都存在
- 编译时分配内存
3. 动态存储(堆/自由存储)
- 使用
new和delete手动管理 - 生命周期由程序员控制
- 更灵活但需要谨慎管理
实用示例:动态字符串管理
char*getname(){chartemp[80];cout<<"Enter name: ";cin>>temp;// 分配刚好足够的内存char*pn=newchar[strlen(temp)+1];strcpy(pn,temp);// 复制字符串returnpn;// 返回动态分配的内存地址}intmain(){char*name=getname();cout<<name<<" at "<<(int*)name<<endl;delete[]name;// 必须释放!return0;}最佳实践总结
区分指针与数组
- 数组名是常量指针
- 指针变量可以重新赋值
正确使用字符串
- 使用
strcpy()或strncpy()复制字符串 - 避免未初始化指针接收输入
- 使用
动态内存管理
- 每个
new必须有对应的delete - 数组使用
delete[] - 指针置空防止悬空指针
- 每个
选择合适的内存类型
- 局部变量用自动存储
- 全局数据用静态存储
- 动态大小数据用堆存储
现代C++建议
虽然理解指针和数组的关系很重要,但在实际开发中:
- 优先使用
std::string而不是C风格字符串 - 优先使用智能指针(
unique_ptr,shared_ptr)而不是原始指针 - 优先使用标准库容器(
vector,array)而不是原始数组
掌握指针和数组的核心概念是成为C++高手的关键一步,希望这篇总结能帮助你更深入地理解C++的内存管理机制!