指针和数组是有很多关系的,函数的形参可以是指针,返回类型也可以是指针,申请内存空间可以使用new关键字,也可以使用free释放内存空间
用指针访问数组元素
数组是一组连续存储的同类型数据,可以通过指针的算术运算,使指针依次指向数组的各个元素,进而可以遍历数组。
定义指向数组元素的指针
定义与赋值 例:int a[10], *pa; pa=&a[0]; 或 pa=a; 是等效的形式
经过上述定义及赋值后,(pa+1)的跨度是sizeof(int), *pa就是a[0],*(pa+1)就是a[1],... ,*(pa+i)就是a[i]. a[i], *(pa+i), *(a+i), pa[i]都是等效的。
不能写 a++,因为a是数组首地址、是常量。
使用数组名和下标访问数组元素
#include
using namespace std;
int main() {
int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
for (int i = 0; i < 10; i++)
cout << a[i] << " ";
cout << endl;
return 0;
}
使用数组名和指针运算访问数组元素
#include
using namespace std;
int main() {
int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
for (int i = 0; i < 10; i++)
cout << *(a+i) << " "; //*(a+1)的跨度是sizeof(int)
cout << endl;
return 0;
}
使用指针变量访问数组元素
#include
using namespace std;
int main() {
int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
//p++的跨度是sizeof(int)=4
//数组长度可以用sizeof(a)/sizeof(int)或者sizeof(a)/sizeof(a[0])计算得到的
for (int *p = a; p < (a + 10); p++)
cout << *p << " ";
cout << endl;
return 0;
}
指针数组:不是连续的,二维数组是连续的内存空间
int main() {
int line1[] = { 1, 0, 0 }; //矩阵的第一行
int line2[] = { 0, 1, 0 }; //矩阵的第二行
int line3[] = { 0, 0, 1 }; //矩阵的第三行
//定义整型指针数组并初始化
int *pLine[3] = { line1, line2, line3 };
cout << "Matrix test:" << endl;
//输出矩阵
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++)
cout << pLine[i][j] << " ";
cout << endl;
}
return 0;
}
以指针作为函数参数:为什么需要用指针做参数?
需要数据双向传递时(引用也可以达到此效果)
用指针作为函数的参数,可以使被调函数通过形参指针存取主调函数中实参指针指向的数据,实现数据的双向传递
需要传递一组数据,只传首地址运行效率比较高,实参是数组名时形参可以是指针
void splitFloat(float x, int *intPart, float* fracPart) {
*intPart = static_cast<int>(x);//取x得整数部分
*fracPart = x - *intPart;
}
int main(){
cout << "Enter 3 float point numbers; " << endl;
for (int i = 0; i < 3; i++) {
float x, f;
int n;
cin >> x;
splitFloat(x, &n, &f);//变量地址作为实参 没有返回值
cout << "Integer Part = " <<n<< " Fraction Part = " << f << endl;
}
return 0;
}
指针函数的定义形式:
存储类型 数据类型 *函数名() { //函数体语句 }
注意:不要将非静态局部地址用作函数的返回值
错误的例子:在子函数中定义局部变量后将其地址返回给主函数,就是非法地址,返回的指针要确保在主调函数中是有效、合法的地址,这个例子就是错误的,返回值是局部变量的地址,但是局部变量已经被释放
int main() {
int* function();
int* ptr = function();
*prt = 5; //危险的访问!
return 0;
}
int* function() {
int local = 0; //非静态局部变量作用域和寿命都仅限于本函数体内
return &local;
}//函数运行结束时,变量local被释
正确的例子:主函数中定义的数组,在子函数中对该数组元素进行某种操作后,返回其中一个元素的地址,这就是合法有效的地址,返回的指针要确保在主调函数中是有效、合法的地址
int main() {
int array[10]; //主函数中定义的数组
int* search(int* a, int num);
for (int i = 0; i < 10; i++)
cin >> array[i];
int* zeroptr = search(array, 10); //将主函数中数组的首地址传给子函数
cout << zeroptr << endl;;
return 0;
}
int* search(int* a, int num) { //指针a指向主函数中定义的数组
for (int i = 0; i < num; i++)
if (a[i] == 0)
return &a[i]; //返回的地址指向的元素是在主函数中定义的
}//函数运行结束时,a[i]的地址仍有
正确的例子:在子函数中通过动态内存分配new操作取得的内存地址返回给主函数是合法有效的,但是内存分配和释放不在同一级别,要注意不能忘记释放,避免内存泄漏
int main() {
int* newintvar();
int* intptr = newintvar();
*intptr = 5; //访问的是合法有效的地址
delete intptr; //如果忘记在这里释放,会造成内存泄漏
return 0;
}
int* newintvar() {
int* p = new int();
return p; //返回的地址指向的是动态分配的空间
}//函数运行结束时,p中的地址仍有效
指向函数的指针,函数指针的定义:
定义形式 :存储类型 数据类型 (*函数指针名)(参数类型表);
int* func( ):返回值是指针;int (*func)():指向函数的指针
含义:函数指针指向的是程序代码存储区
通过函数指针调用的函数,例如将函数的指针作为参数传递给一个函数,使得在处理相似事件的时候可以灵活的使用不同的方法。
int compute(int a, int b, int(*func)(int, int)) { return func(a, b);}
int max(int a, int b) { return ((a > b) ? a : b); }//求最大值
int min(int a, int b) { return ((a > b) ? b : a); }//求最小值
int sum(int a, int b) { return a + b; }//求和
int main(){
int a, b, res;
cout << "请输入整数a:"; cin >> a;
cout << "请输入整数b:"; cin >> b;
res = compute(a, b, &max);
cout << "Max of " << a << " and " << b << " is " << res << endl;
res = compute(a, b, &min);
cout << "Min of " << a << " and " << b << " is " << res << endl;
res = compute(a, b, &sum);
cout << "Sum of " << a << " and " << b << " is " << res << endl;
return 0;
}
对象指针:对象指针定义形式 类名 *对象指针名;
Point a(5,10);
Piont *ptr;
ptr=&a;
通过指针访问对象成员 对象指针名->成员名 例:ptr->getx() 相当于 (*ptr).getx();
class Point {
public:
Point(int x = 0, int y = 0) : x(x), y(y) { }
int getX() const { return x; }
int getY() const { return y; }
private:
int x, y;
};
int main() {
Point a(9, 10);
Point *p1 = &a; //定义对象指针,用a的地址初始化
cout << p1->getX() << endl;//用指针访问对象成员
cout << a.getX() << endl; //用对象名访问对象成员
return 0;
}
this指针,指向当前对象自己
隐含于类的每一个非静态成员函数中,指出成员函数所操作的对象。
当通过一个对象调用成员函数时,系统先将该对象的地址赋给this指针,然后调用成员函数,成员函数对对象的数据成员进行操作时,就隐含使用了this指针。
例如:Point类的getX函数中的语句:return x; 相当于:return this->x;
错误的程序
class Fred; //前向引用声明
class Barney {
Fred x; //错误:类Fred的声明尚不完善
};
class Fred {
Barney y;
};
正确的程序
class Fred; //前向引用声明
class Barney {
Fred *x;
};
class Fred {
Barney y;
};
动态申请内存操作符: new
new 类型名T(初始化参数列表)
功能:在程序执行期间,申请用于存放T类型对象的内存空间,并依初值列表赋以初值。
结果值:成功:T类型的指针,指向新分配的内存;失败:抛出异常。
释放内存操作符delete,delete 指针p
功能:释放指针p所指向的内存。不是删除指针p,p必须是new操作的返回值。
class Point {
public:
Point() :x(0), y(0) { cout << "Default Constructor called." << endl; }
Point(int x,int y):x(x),y(y){cout<< "Constructor called." << endl; }
~Point() { cout << "Destructor called." << endl; }
int getX()const { return x; }//常函数成员处理常对象
int getY()const { return y; }
void move(int newX, int newY) {
x = newX;
y = newY;
}
private:
int x, y;
};
int main(){
cout<< "Step one: " << endl;
Point *ptr1 = new Point;//调用默认构造函数
delete ptr1; //删除对象,删除的是指针对应的内存内容,自动调用析构函数
cout << "Step two: " << endl;
ptr1 = new Point(1, 2); //已经声明过ptr1
delete ptr1;
return 0;
}
分配和释放动态数组:
分配:new 类型名T [ 数组长度 ],数组长度可以是任何表达式,在运行时计算
释放:delete[] 数组名p,释放指针p所指向的数组。p必须是用new分配得到的数组首地址。如果delete不写[],只会释放数组首元素的地址,写[],会释放整个数组的空间
Point *ptr = new Point[2];//创建对象数组
ptr[0].move(5, 10);//通过指针访问数组元素的成员
ptr[1].move(15, 20);//通过指针访问数组元素的成员
cout << "Deleting..." << endl;
delete[] ptr;
动态创建多维数组:
new 类型名T[第1维长度][第2维长度]…;如果内存申请成功,new运算返回一个指向新分配内存首地址的指针。
char (*fp)[3]; fp = new char[2][3];
a = new int*[3]; /*第一次动态内存分配,生成的是一个指针数组,每个数组元素都将指向一个一维数组首地址*/
for (int i = 0; i < 3; i++) a[i] = new int[3];/*第二次内存分配,用循环依次生成三个一维数组,a[i]指向的是第i行的首地址*/
//矩阵的转置
void swap(int&a, int&b) {
int temp = a;
a = b;
b = temp;
}
int main() {
//指向指针的指针
int **a;
/*第一次动态内存分配,生成的是一个指针数组,
每个数组元素都将指向一个一维数组首地址*/
a = new int*[3];
/*第二次内存分配,
用循环依次生成三个一维数组,
a[i]指向的是第i行的首地址*/
for (int i = 0; i < 3; i++)
a[i] = new int[3];
//int (*a)[3] = new int[3][3];
cout << "输入9个整数作为矩阵元素值" << endl;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
cin >> a[i][j];
cout << "初始矩阵:" << endl;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++)
cout << a[i][j] << ' ';
cout << endl;
}
for (int i = 0; i < 3; i++)
for (int j = 0; j < i; j++)
swap(a[i][j], a[j][i]);
cout << "转置后的矩阵:" << endl;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++)
cout << a[i][j] << ' ';
cout << endl;
}
return 0;
}
int main(){
int(*cp)[9][8] = new int[7][9][8];
for (int i = 0; i < 7; i++)
for (int j = 0; j < 9; j++)
for (int k = 0; k < 8; k++)
*(*(*(cp + i) + j) + k) = (i * 100 + j * 10 + k);
for (int i = 0; i < 7; i++) {
for (int j = 0; j < 9; j++) {
for (int k = 0; k < 8; k++)
cout << cp[i][j][k] << " ";
cout << endl;
}
cout << endl;
}
delete[] cp;
return 0;
}
申请和释放动态数组示例:
class Point {
public:
Point() :x(0), y(0) { cout << "Default Constructor called." << endl; }
Point(int x, int y) :x(x), y(y) { cout << "Constructor called." << endl; }
~Point() { cout << "Destructor called." << endl; }
int getX()const { return x; }//常函数成员处理常对象
int getY()const { return y; }
void move(int newX, int newY) {
x = newX;
y = newY;
}
private:
int x, y;
};
class ArrayOfPoints { //动态数组类
public:
ArrayOfPoints(int size) :size(size) { points = new Point[size]; }
~ArrayOfPoints(){
cout << "Deleting..." << endl;
}
Point& element(int index) { //返回数组元素的引用
assert(index >= 0 && index < size);
return points[index];
}
private:
Point *points;//指向动态数组首地址
int size; //数组大小
};
int main(){
int count;
cout << "Please enter the count of points:";
cin >> count;
ArrayOfPoints points(count);//创建数组对象
//points.element(0)调用类函数,返回对象数组中的元素的引用,访问数组元素的成员
points.element(0).move(5, 0);
points.element(1).move(15, 20);//访问数组元素的成员
return 0;
}
vector动态数组对象:封装任何类型的动态数组,自动创建和删除。数组下标越界检查。
使用:vector<元素类型> 数组对象名(数组长度); vector<int> arr(5) //建立大小为5的int数组
对数组元素的引用,与普通数组具有相同形式:vector对象名 [ 下标表达式 ]
vector数组对象名不表示数组首地址,获得数组长度,用size函数,数组对象名.size()
#include<vector>
using namespace std;
double average(const vector<double> &arr) {//参数为vector常类型
double sum = 0;
for (unsigned i = 0; i < arr.size(); i++)
sum += arr[i];
return sum / arr.size();
}
int main(){
unsigned n;
cout << "n = ";
cin >> n;
vector<double>arr(n);//创建数组对象
cout << "Please input " << n << " real numbers:" << endl;
for (unsigned i = 0; i < n; i++)
cin >> arr[i];
cout << "Average = " << average(arr) << endl;
return 0;
}
基于范围的for循环配合auto举例:
vector<int> v = { 1,2,3 };
for (auto i = v.begin(); i != v.end(); ++i) //基于范围的for循环配合auto举例
cout << *i << endl;
for (auto e : v)
cout << e << endl;