《C++语言程序设计基础》学习之数组指针与字符串附

指针和数组是有很多关系的,函数的形参可以是指针,返回类型也可以是指针,申请内存空间可以使用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();

扫描二维码关注公众号,回复: 3450885 查看本文章
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;

猜你喜欢

转载自blog.csdn.net/shiheyingzhe/article/details/82934621
今日推荐