数组指针与字符串
6.1数组
数组:具有一定顺序关系的若干个对象的集合体
6.1.1数组的声明与使用
6.1.2数组的存储与初始化
1数组的存储
数组元素在内存中时连续存储的
2数组的初始化
在声明时对数组进行赋值,赋值数小于规定数时,未赋值的数组值为0
6.1.3数组作为函数参数(一般不指定第一维大小)
数组名是数组首元素的地址
cpp
#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
cpp
#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
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
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)指向常量的指针
不能通过指针改变所指对象的值,但是可以改变指针
cpp
int a;
const int* p1 = &a;
int b;
p1 = &b;
*p1 = 1;//错误
(2)指针类型的常量
cpp
int* const p2 = &a;
p2 = &b;//错误
(3)void类型的指针
cpp
#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用指针处理数组元素
数组作为函数参数
三种等价
cpp
void f(int p[])
void f(int p[2])
void f(int *p)
6.2.7指针数组
存放指针的数组
cpp
#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用指针作为函数参数
提高效率
cpp
#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;
}
用·引用做参数也一样
cpp
#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
用法
函数指针名=函数名;
cpp
#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对象指针的一般概念
可以通过对象地址访问对象,对象所占据的内存空间只存放数据成员
语法
类名 *对象指针名
cpp
point* pp1;
point p1;
pp1 = &p1;
对象指针名->成员名;
cpp
#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指向类的非静态成员函数的指针
语法
:类型说明符 类名::*指针名;//指向数据成员的指针
类型说明符 (类名::*指针名)(参数表);//指向函数成员的指针
赋值
指针名=&类名::数据成员名;
对象。*类成员指针名
对象指针名->*类成员指针名
指针名=&类名::函数成员名;
(对象。*类成员指针名)()
(对象指针名->*类成员指针名)()
cpp
#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指向类的静态成员函数
指向类的静态成员
cpp
#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;
}
指向静态函数成员
cpp
#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数据类型(初始化参表)
cpp
//申请空间存放int类型初始化为2,将首地址赋值给指针point
int* point;
point = new int(2);
int* point = new int;//不初始化
int* point = new int();//初始化0
delete删除
delete 指针名
动态创建对象
cpp
#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 【】指针名
动态创建对象数组
cpp
#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;
}
动态数组类
cpp
#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数组对象名字是一个数组对象,不是首地址,数组对象不是数组而是封装数组的对象
例子
cpp
#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用字符数组存储和处理字符串
cpp
const char*p1="asacaca";
cout<<p1;
6.6.2string类
1构造函数的原型
2string类的操作符
比较大小
(1)相等
(2)完全不同,比较的一个字符ascii码值
(3)前面完全一样,长度不一样,n1《n2