C++程序设计(第四版郑莉)------第六章

发布于:2024-04-29 ⋅ 阅读:(31) ⋅ 点赞:(0)

数组指针与字符串

6.1数组

数组:具有一定顺序关系的若干个对象的集合体

6.1.1数组的声明与使用

6.1.2数组的存储与初始化

1数组的存储

数组元素在内存中时连续存储的

2数组的初始化

在声明时对数组进行赋值,赋值数小于规定数时,未赋值的数组值为0

6.1.3数组作为函数参数(一般不指定第一维大小)

数组名是数组首元素的地址

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
void rowsun(int a[][4], int nrow) {
	for (int i = 0; i < nrow; i++) {
		for (int j = 1; j < 4; j++)
			a[i][0] += a[i][j];
	}
}
int main()
{
	int table[3][4] = { {1,2,3,4},{2,3,4,5},{3,4,5,6} };
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 4; j++)
			cout << table[i][j] << "   ";
		cout << endl;
	}
	rowsun(table, 3);
	for (int i = 0; i < 3; i++)
		cout << "sum of row" << i << "is" << table[i][0] << endl;
	
}

6.1.4对象数组

定义

类名         数组名【常量表达式】;

引用

数组名      【下标表达式】。成员名

实例

point。h

#ifndef _POINT_H
#define _POINT_H
class point {
public:
	point();
		point(int x,int y);
	~point();
	int getx() const{ return x; }
	int gety() const{ return y; }
	void move(int newx, int newy);
	static void showcount();
private:
	int x, y;
};
#endif

point。cpp

#include<iostream>
#include"point.h"
using namespace std;
point::point() {
	x = y = 0;
	cout << "con called" << endl;

}
point::point(int x, int y) :x(x), y(y) {
	cout << "con called" << endl;
}
point::~point() {
	cout << "des called" << endl;
}
void point::move(int newx, int newy) {
	cout << "moving the point to(" << newx << "," << newy << ")" << endl;
	x = newx;
	y = newy;

}

1.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include"point.h"
using namespace std;
int main() {
	point a[2];
	for (int i = 0; i < 2; i++)
		a[i].move(i + 10, 20 + i);
	
}

6.2指针

正确的使用指针可以方便,灵活而有效地组织和表示复杂的数据结构,动态内存分配和管理也离不开指针

6.2.1内存空间的访问方式

计算机的内存储器被划分为一个个的存储单元

存储单元按一定规律编号

编号就是存储单元的地址

地址编码的基本单位是字节

每一字节就是一个基本的内存单元

在C++中两种方式利用内存单元存储数据

1变量名

2地址

具有静态生存期的变量在程序运行前就生成好内存空间

6.2.2指针变量的声明

指针也是一种数据类型,

指针变量用来存放内存单元地址的

6.2.3与地址相关的运算“*”和“&”

6.2.4指针的赋值

数组名称实际上是一个不能被赋值的指针,指针常量

(·1)指向常量的指针

不能通过指针改变所指对象的值,但是可以改变指针

int a;
const int* p1 = &a;
int b;
p1 = &b;
*p1 = 1;//错误
(2)指针类型的常量
int* const p2 = &a;
p2 = &b;//错误
 (3)void类型的指针
#include<iostream>
using namespace std;

int main()
{
	//不能声明viod的常量,void a;
	void* pv;
	int i = 5;
	pv = &i;
	int* pint = static_cast<int*>(pv);
	cout << *pint;
}

6.2.5指针的运算

1p1+整数=p1当前所在位置后方第n个数的地址

2p1—1也一样

3p1++与p1——

4*(p1+n)等价与p1【n】;

6.2.6用指针处理数组元素

数组作为函数参数

三种等价

void f(int p[])
void f(int p[2])
void f(int *p)

6.2.7指针数组

存放指针的数组

#include<iostream>
using namespace std;

int main() {
	int line1[]={1,2,3,4};
	int line2[] = { 0,2,3,4 };
	int line3[] = { 2,2,3,4 };

	int* pline[] = { line1,line2,line3 };
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++)
			cout << pline[i][j] ;//pline[i][j]等价*(pline[i]+j)		
		cout << endl;
	}
}

二维数组

arr2【i】【j】等价*(*(arr2+i)+j)

6.2.8用指针作为函数参数

提高效率

#include<iostream>
void a(float x, int* f, float* j);
using namespace std;
int main() {
	for (int i = 0; i < 3; i++) {
		float x, j;
		int f;
		cin >> x;
		a(x, &f, &j);
		cout << f << "  " << j << endl ;

	}
}
void a(float x, int* f, float* j) {
	*f = static_cast<int>(x);
	*j = x - *f;
}

用·引用做参数也一样

#include<iostream>
void a(float x, int& f, float&j);
using namespace std;
int main() {
	for (int i = 0; i < 3; i++) {
		float x, j;
		int f;
		cin >> x;
		a(x, f, j);
		cout << f << "  " << j << endl ;

	}
}
void a(float x, int& f, float&j) {
	f = static_cast<int>(x);
	j = x - f;
}

6.2.9指针型函数

数据类型        *函数名(参数){

函数体

}

6.2.10指向函数的指针

语法:

数据类型        (*函数指针名)(形参表)

也可以加上typedef

用法

函数指针名=函数名;

#include<iostream>
using namespace std;

void a(float) {
	cout << "a" << endl;
}
void b(float data) {
	cout << "b" << data << endl;
}
void c(float data) {
	cout << "c" << data << endl;
}
const float PI = 3.14159f;
const float TOW_PI = PI * 2.0;
int main() {
	void  ( *  d)(float);
	a(PI);
	d=a;
	d(PI);
	d = b;
	d(TOW_PI);
	d(13.0);
	d = c;
	d(PI);
	c(PI);

}

6.2.11对象指针

1对象指针的一般概念

可以通过对象地址访问对象,对象所占据的内存空间只存放数据成员

语法

类名        *对象指针名

point* pp1;
point p1;
pp1 = &p1;

对象指针名->成员名;

#include<iostream>
using namespace std;
class point {
public:
point(int x=0,int y=0):x(x),y(y){}
int getx() { return x; }
int gety() { return y; }
private:
		int x, y;
};
int main() {
	point a(4, 5);
	point* p1 = &a;
	cout << p1->getx() << endl;
	cout << a.getx() << endl;
}
2this指针

是一个隐含与每一个类的非静态成员函数的特殊指针,用于指向被成员函数操作的对现象

比如point有a,b,c三个对象,调用getx函数时都是返回x,在对象调用函数时就将对象地址通过参数传递给成员函数,成员函数对对象的数据成员进行操作时,就隐含使用this指针

return this->x

3指向类的非静态成员函数的指针

语法

:类型说明符        类名::*指针名;//指向数据成员的指针

    类型说明符        (类名::*指针名)(参数表);//指向函数成员的指针

赋值

指针名=&类名::数据成员名;

对象。*类成员指针名

对象指针名->*类成员指针名

指针名=&类名::函数成员名;

(对象。*类成员指针名)()

(对象指针名->*类成员指针名)()

#include<iostream>
using namespace std;
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(4, 5);
	point* p1;//对象指针
	int (point:: * func)()const = &point::getx;//成员函数指针并且初始化
	cout << (a.*func)() << endl;//使用成员函数指针和对象名访问成员函数
	cout << (p1->*func)() << endl;//使用成员函数指针和对象指针访问成员函数
	cout << a.getx() << endl;//对象名访问成员函数
	cout << p1->getx() << endl;	//对象指针访问成员函数
}
4指向类的静态成员函数

指向类的静态成员

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class point {
public:
	point(int x, int y) :x(x), y(y) {
		count++;
	}
	point(point& p) :x(p.x), y(p.y) {
		count++;
	}
	~point() { count--; }
	int getx()const { return x; }
	int gety()const { return y; }
	void showcount() {
		cout << count << endl;
	}
	static int  count;
private:
	int x, y;
};
int point::count = 0;
int main() {
	point a(4, 5);
	int* p = &point::count;//指针指向类的静态成员
	cout << a.getx() << "," << a.gety() << endl;
	cout << *p << endl;
	point b(a);
	cout << b.getx() << "," << b.gety() << endl;
	cout << *p << endl;
}

指向静态函数成员

#include<iostream>
using namespace std;
class point {
public:
	point(int x, int y) :x(x), y(y) {
		count++;
	}
	point(point& p) :x(p.x), y(p.y) {
		count++;
	}
	~point() { count--; }
	int getx()const { return x; }
	int gety()const { return y; }
	static void showcount() {
		cout << count << endl;
	}
	
private:
	int x, y;
	static int  count;
};
int point::count = 0;
int main() {
	void(*func)() = point::showcount;//定义一个指向函数的指针,指向类的静态函数成员
	point a(4, 5);
	cout << a.getx() << "," << a.gety() << endl;
	func();
	point b(a);
	cout << b.getx() << "," << b.gety() << endl;
	func();


}

6.3动态内存分配

虽然通过数组,可以对大量的数据和对象进行有效管理,但是大多数情况,程序运行前,不能自知道数组有多少个元素,C++种,动态内存分配技术可以保证程序运行过程种按需要申请适量的内存,结束时还可以释放,这种在程序运行过程中申请和释放的存储单元也称堆对象,申请与释放一般称建立与删除

new数据类型(初始化参表)

//申请空间存放int类型初始化为2,将首地址赋值给指针point
int* point;
point = new int(2);
int* point = new int;//不初始化
int* point = new int();//初始化0

delete删除

delete         指针名

动态创建对象

#include<iostream>
using namespace std;
class point {
public:
	point() :x(0), y(0) {
		cout << "1" << endl;
	}
	point(int x, int y) :x(x), y(y) {
		cout << "2" << endl;
	}
	~point() { cout << "3" << 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() {
	point* p1 = new point;//动态创建对象,没有参数列表,调用默认函数
	delete p1;//删除对象,调用析构函数

	p1 = new point(1,2);//调用有形参的构造函数
	delete p1;
}

new 类型名 {数组长度}

delete 【】指针名

动态创建对象数组

#include<iostream>
using namespace std;
class point {
public:
	point() :x(0), y(0) {
		cout << "1" << endl;
	}
	point(int x, int y) :x(x), y(y) {
		cout << "2" << endl;
	}
	~point() { cout << "3" << 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() {
	point* p1 = new point[2];//对象数组
	p1[0].move(4, 5);//通过指针访问数组成员
	p1[1].move(15, 20);
	delete[] p1;

}

动态数组类

#include<iostream>
#include<cassert>
using namespace std;
class point {
public:
	point() :x(0), y(0) {
		cout << "1" << endl;
	}
	point(int x, int y) :x(x), y(y) {
		cout << "2" << endl;
	}
	~point() { cout << "3" << 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 b {
public:
	b(int size) :size(size) {
		p1 = new point[size];
	}
	~b() {
		cout << "1" << endl;
		delete[] p1;
	}
	point& elemet(int index) {
		assert(index >= 0 && index < size);
		return p1[index];
	}
private:
	point* p1;
	int size;
};
int main() {
	int count;
	cin >> count;
	b p1(count);//创建对象数组
	p1.elemet(0). move(5, 0);
	p1.elemet(1).move(15, 20);

}

动态创建多维数组

6.4用vector创建数组对象

被封装的动态数组vector

语法

vctor<元素类型>数组对象名(数组长度);

vector定义的数组都会被初始化,0或者构造函数

也可以自己指定但是得指定相同的初始值

vctor<元素类型>数组对象名(数组长度,初始值);

访问方式

数组对象名 【下标表达式】

但是vector数组对象名字是一个数组对象,不是首地址,数组对象不是数组而是封装数组的对象

例子

#include<iostream>
#include<vector>
using namespace std;

double average(const vector<double>& arr) {
	double sum = 0;
	for (unsigned i = 0; i < arr.size(); i++)
		sum = sum + arr[i];
	return sum / arr.size();
}
int main() {
	unsigned n;
	cout << "n=";
	cin >> n;
	vector<double>arr(n);
	cout << "输入数" << endl;
	for (unsigned i = 0; i < n; i++)
		cin >> arr[i];
	cout << "平均值" << average(arr) << endl;

}

6.5深复制与浅复制

浅复制对象的数据项是同一个地址

改变1就会改变2(2复制1)

深复制

6。6字符串

6.6.1用字符数组存储和处理字符串

const char*p1="asacaca";
cout<<p1;

6.6.2string类

1构造函数的原型
2string类的操作符

比较大小

(1)相等

(2)完全不同,比较的一个字符ascii码值

(3)前面完全一样,长度不一样,n1《n2

3常用成员函数功能简绍


网站公告

今日签到

点亮在社区的每一天
去签到