C++入门笔记(四)数组、指针与字符串

1、对象数组

     声明一个一维对象数组的语句形式是:

     类名 数组名[常量表达式];

     每个数组元素对象都可以访问它的公有成员,一般形式是:

     数组名[下标表达式].成员名

     如果在声明数组时给每一个数组元素指定初始值,在数组初始化过程中就会调用与形参类型相匹配的构造函数,例如:

 Location a[2]={ Location(1,2), Location(3,4)};

   实例:

Point.h:

#ifndef _POINT_H
#define _POINT_H

class Point{
public:
    Point();
    Point(int x, int y);
    ~Point();
    void move(int newX, int newY);
    int getX() const {return x;}
    int getY() const {return y;}
    static void showCount();
private:
    int x, y;
};

#endif

Point.cpp:

#include<iostream>
#include"Point.h"
using namespace std;

Point::Point() 
{
    x = y = 0;
    cout << "Default Constructor called. " << endl;
}

Point::Point(int x, int y):x(x), y(y) //构造函数实现(列表初始化)
{
    cout << "Constructor called. " << endl;
}

Point::~Point() //析构函数实现
{
    cout << "Destructor called. " << endl;
}

void Point::move(int newX, int newY)
{
    cout<<"Moving the point to("<<newX<<","<<newY<<")"<<endl;
    x = newX;
    y = newY;
}

main.cpp:

#include<iostream>
#include"Point.h"
using namespace std;

int main()
{
    cout << "Entering main..." << endl;
    Point a[2];
    for (int i=0;i<2;i++)
        a[i].move(i+10,i+20);
    cout << "Exiting main..." << endl;
    return 0;
}

运行结果:


  

2、对象指针

      对象指针就是用于存放对象地址的变量,语法形式:

      类名 * 对象指针名;

      例如:Point * pointPtr;  //声明 Point 类的对象指针变量 PointPtr

      使用对象指针也可以方便的访问对象的成员: 对象指针名 -> 成员名      (  * 对象指针名 ) . 成员名  等价

3、this指针

     this指针是隐含于每一个类的非静态成员函数中的特殊指针(包括构造函数和析构函数),它用于指向正在被成员函数操作的对象。

4、指向类的非静态成员的指针

     一般格式:

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

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

     对数据成员指针赋值的一般语法形式为: 指针名 = &类名::数据成员名;

     访问数据成员方式: 对象名 . * 类成员指针名   或   对象指针名  ->  * 类成员指针名

     成员函数指针在声明之后要对其赋值: 指针名 = &类名::函数成员名;

     利用指针调用成员函数: (对象名 . *类成员指针名)(参数表)   (对象指针名 -> *类成员指针名)(参数表)

     实例:

int main()
{
    Point a(4,5);//定义对象 a
    Point *p1 = &a; //定义对象指针并初始化
    int (Point::*funcPtr)()const = &Point::getX;//定义成员函数指针并初始化
    
    cout << (a.*funcPtr)() << endl;//成员函数指针和对象名访问成员函数
    cout << (P1->*funcPtr)() << endl; //成员函数指针对象指针访问成员函数
    cout << a.getX() << endl;//对象名访问成员函数
    cout << p1->getX() << endl;//对象指针访问成员函数
    
    return 0;
}

5、指向类的静态成员的指针

      对类的静态成员的访问是不依赖于对象的,因此可以用普通的指针来指向和访问静态成员。

      实例1:通过指针访问类的静态数据成员

#include<iostream>
using namespace std;

class Point
{
public:
    Point(int x=0,int y=0):x(x),y(y) //构造函数

    {
        count++;
    }
    Point(const Point &p):x(p.x),y(p.y)//拷贝构造函数
    {
        count++;
    }
    ~Point(){count--;}//析构函数
    int getX() const {return x;}
    int getY() const {return y;}
    static int count; //静态数据成员声明
private:
    int x,y;
};

int Point::count=0; //静态数据成员定义和初始化

int main()
{
    int * ptr=&Point::count; //定义指向类的静态成员的指针
    Point a(4,5);
    cout << "Point A: " << a.getX() << "," << a.getY();
    cout << " Object count=" << *ptr << endl; //直接通过指针访问静态数据成员

    return 0;
}


运行结果:

        实例2:通过指针访问类的静态函数成员

#include<iostream>
using namespace std;

class Point
{
public:
    Point(int x=0,int y=0):x(x),y(y) //构造函数

    {
        count++;
    }
    Point(const 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 << "  Object count=" << count << endl;
    }
private:
    int x,y;
    static int count;
};

int Point::count=0; //静态数据成员定义和初始化

int main()
{
    void (*funcPtr)()=Point::showCount; //定义一个指向函数的指针,指向类的静态成员函数
    Point a(4,5);
    cout << "Point A: " << a.getX() << "," << a.getY();
    funcPtr();//输出对象个数,直接通过指针访问静态函数成员

    Point b(a);
    cout << "Point B: " << b.getX() << "," << b.getY();
    funcPtr(); //输出对象个数,直接通过指针访问静态函数成员

    return 0;
}


运行结果:



6、动态内存分配

      在 C++ 中,动态内存分配技术可以保证程序在运行过程中按照实际需要申请适量的内存,使用结束后还可以释放,这种在程序运行过程

中申请和释放的存储单元也称堆对象,建立和删除堆对象使用两个运算符: new 和 delete 。

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

     该语句在程序运行过程中申请分配用于存放指定类型数据的内存空间,并根据初始化参数列表中给出的值进行初始化,如果内存申请成

功,返回一个指向新分配内存首地址的类型的指针,申请失败会抛出异常。

   实例:

int * point;
point = new int(2);

//动态分配了用于存放 int 类型数据的内存空间,并将初值2存入该空间中

    delete 指针名;

    如果被删除的是对象,该对象的析构函数将被调用。对于用 new 建立的对象,只能使用 delete 进行一次删除操作。

    实例:简单的动态数组类


#include<iostream>
#include<cassert>
using namespace std;
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;
        delete[] points;
    }
    Point &element(int index)//获得下标为index的数组元素
    {
        assert(index>=0 && index<size);//如果下标越界,程序终止
        return points[index];
    }
private:
    Point *points;
    int size;
};

int main()
{
    int count;
    cout<<"Please enter the count of point: ";
    cin>>count;
    ArrayOfPoints points(count);
    points.element(0).move(5,10);
    points.element(1).move(15,20);
    return 0;
}

运行结果:

 


    多维数组实例:

float * fp;//错误
float (* cp)[25][10];//正确
cp = new float[10][25][10];

   这里 new 操作产生的是指向一个 25X10 的二维 float 类型数组的指针,所以定义 fp 应该是指向同种类型的指针


7、用 vector 创建数组对象

      C++ 标准库提供了被封装的动态数组:vector

      用 vector 定义动态数组的形式为:

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

      对 vector 数组对象元素的访问方式,与普通数组具有相同的形式:

       数组对象名 [ 下标表达式 ]

      但是 vector 数组对象的名字表示的就是一个数组对象,而非数组的首地址,因为数组对象不是数组,而是封装了数组的对象

      vector 定义的数组对象具有一个重要的成员函数 size(),用于返回数组的大小

      实例:

#include<iostream>
#include<vector>
using namespace std;
//计算数组 arr 中元素的平均值
double average(const vector<double>&arr)
{
    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;
}

运行结果:

        本例中,在主函数里创建了动态数组对象 arr,然后通过键盘输入的方式为数组元素赋值,再调用 average 函数

进行计算数组元组的平均值。vector还具有很多强大的功能,后面还会再详细介绍。

8、字符串

       使用数组来存放字符串,调用系统函数来处理字符串,毕竟显得不方便,而且数据与处理数据的函数分离也不符

合面向对象方法的要求,为此,C++ 标准类库预定义了字符串类(string类)。使用类时需要包含头文件 string,string

类封装了串的属性并提供了一系列允许访问这些属性的函数。

         为简明起见,下面函数原型是经过简化的,与头文件中的形式不完全一样

       (1)构造函数的原型

string(); //默认构造函数,建立一个长度为0的串
string(const string& rhs);//拷贝构造函数
string(const char* s);//用指针s所指向的字符串常量初始化string类的对象

//将对象rhs中的串从位置pos开始取n个字符,用来初始化string类的对象
string(const string &rhs,unsigned int pos,unsigned int n);

//用指针s所指向的字符串中的前n个字符初始化string类的对象
string(const char*s,unsigned int n);

//将参数c中的字符重复n次,用来初始化string类的对象
string(unsigned int n,char c);

       (2)string 类的操作符


        之所以能够通过上面的操作符来操作 string 对象,是因为 string 类对这些操作符进行了重载。

       (3)常用成员函数功能简介

string append(const char* s);//将字符串s添加在本串尾
string assign(const char* s);//赋值,将s所指向的字符串赋值给本对象

//比较本串与str中串大小,本串小返回负数,大返回整数,相等返回0
int compare(const string &str)const;

//将s所指向的字符串插入在本串中位置p0之前
string & insert(unsigned int p0,const char* s);

//取子串,取本串中位置pos开始的n个字符,构成新的string类对象作为返回值
string substr(unsigned int pos,unsigned int n)const;

//查找并返回str在本串中第一次出现的位置
unsigned int find(const basic_string &str)const;

unsigned int length() const;//返回串的长度(字符个数)
void swap(string& str);//将本串与str中的字符串进行交换

           实例:


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

//根据value的值输出true或false,title为提示文字
inline void test(const char* title,bool value)
{
    cout<<title<<" return "<<(value?"ture":"false")<<endl;
}

int main()
{
    string s1="DEF";
    cout<<"s1 is "<<s1<<endl;

    string s2;
    cout<<"Please enter s2: ";
    cin>>s2;
    cout<<"lenght of s2: "<<s2.length()<<endl;

    test("s1<=\"ABC\"",s1<="ABC");
    test("\"DEF\"<=s1","DEF"<=s1);

    s2 += s1;
    cout<<"s2=s2+s1: "<<s2<<endl;
    cout<<"length of s2: "<<s2.length()<<endl;

    return 0;
}

运行结果:




郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。