一、
以下String类的友员函数完成C串与String串的“+”运算,将程序补充完整。
String operator+ (const char* c, const String& s){
String w;
int len = ① ;
delete []w.str;
w.str = ② ;
if(w.str == NULL) s.error("overflow");
③ ;
④ ;
w.size = len;
⑤ ;}
①strlen(c) + s.size;
②new char[len +1];
③strcpy(w.str, c);
④strcat(w.str, s.str);
⑤return w;
对于为什么String s不能使用strlen()来计算大小:
String s是一个String类的对象,它拥有一个私有成员变量size来表示字符串的长度。在构造String对象时,已经将字符串的长度保存在size变量中,不需要再使用strlen()来计算长度。
在以上的代码中,已经通过s.size获取了String对象s的长度,因此不需要再使用strlen()去计算c字符串的长度。直接使用s.size即可得到两个字符串连接后的总长度。这样可以避免重复计算,提高代码的效率。
char *c可以使用strlen()来计算长度
是因为c是一个字符串字面量(即由双引号包围的字符序列)。在C/C++中,字符串字面量被视为以空字符(\0)结尾的字符数组,因此可以使用strlen()来计算其长度,即不包括空字符在内的字符数。
在以上代码中,通过strlen(c)可以得到字符串字面量c的长度,然后与String对象s的size相加,得到连接后的字符串的总长度。这样可以动态地分配足够的内存空间来存储连接后的字符串。
需要注意的是
在连接字符串的过程中,需要先删除之前分配的内存空间(delete []w.str),然后再动态分配新的内存空间(new char[len+1]),以确保可以存储连接后的字符串。同时还需要检查内存是否分配成功,如果内存分配失败,则使用error()函数进行相应的处理。最后,使用strcpy()函数将c字符串复制到w.str中,然后使用strcat()函数将s.str拼接到w.str的末尾,最后更新w的size,包装成String对象并返回。
字符串函数
二、实现Vector的成员函数
#ifndef VECTOR_H
#define VECTOR_H
#include <stdlib.h>
template<class T>
class Vector
{
private:
T *data; //指向动态数组指针
int size; //数组的数据元素个数
int max; //数组容量
void Error(const char* cs)const { cout << cs << endl; exit(1); }//错误信息报告
public:
enum { SPARE_MAX = 16 }; //枚举常量表示数组最小长度
explicit Vector(int n = 0) :size(0), max(n + SPARE_MAX)
{
if (max > 0) data = new T[max];
}
Vector(const Vector& v) :data(NULL), max(0) { operator=(v); }//复制构造函数
~Vector() { delete[]data; }
Vector& operator=(const Vector<T>& v); //复制赋值函数
T& operator[](int id) { return data[id]; } //下标运算符函数
const T& operator[](int id)const { return data[id]; }//常量型下标运算符函数
bool Empty()const { return size == 0; } //判空
bool isFull() const { return size == max; } //判满
int Size()const { return size; } //求数据个数
int Max()const { return max; } //求数组容量
void Clear() { size = 0; } //清空。删除所有数据元素
//迭代器类型
typedef T* iterator; //迭代器
typedef const T* const_iterator; //指向const常量的迭代器
iterator Begin() { return data; } //使迭代器指向容器起始位置
const_iterator Begin()const { return data; }
iterator End() { return data + size; } //使迭代器指向容器最后一个数据元素的后继
const_iterator End()const { return data + size; }
const T& Front()const { return data[0]; } //返回首元素的引用(可以返回*begin())
T& Front() { return data[0]; }
const T& Back()const { return data[size - 1]; } //返回尾元素的引用(不能返回*--end())
T& Back() { return data[size - 1]; }
void Push_back(const T& item); //尾插
void Pop_back() { size--; } //尾删
void Reserve(int newMax); //扩大数组容量为newmax,保留原来数据
void Resize(int newSize, const T& item = T()); //把数据个数增加为newsize,保留原来的数据,其余的值为item
iterator Insert(iterator itr, const T& item);
iterator Erase(iterator itr);
iterator Erase(iterator first, iterator last); //删除[first,last)区间的数据,返回当前数据的位置。
void Insert(iterator pos, iterator first, iterator last);//在pos处插入另一个Vector容器指定区间[first, last)的数据
void Swap(Vector<T>& v); //交换两个Vector中的数据。
};
template<class T>
Vector<T>& Vector<T>::operator=(const Vector<T>& v)//复制赋值函数
{
if (max != v.Max())
{
delete[]data;
max = v.max;
data = new T[max];
}
size = v.Size();
for (int i = 0; i < size; i++)
data[i] = v.data[i];
return *this;
}
template<class T> //模板参数表
typename Vector<T>::iterator //返回值类型
Vector<T>::Erase(iterator itr) //删除指示器指向的元素
{
for (iterator p = itr, q = itr + 1; q != data + size; ++p, ++q)
*p = *q;
size--;
return itr;
}
template<class T> //
把元素item插入到迭代器itr的位置
typename Vector<T>::iterator Vector<T>::Insert(iterator itr, const T& item)
{
/*******************请在此处写出成员函数的定义***********************/
if(size==max)
{
int n = itr-Begin();
Reserve(2*max+1);
itr = Begin() + n;
}
for(iterator p = data +size,q = data+size-1;p!=itr;--p,--q)
{
*p=*q;
}
*itr = item;
size++;
return itr;/***********************************************************************/
}
这三行代码什么意思:int n = itr - Begin(); Reserve(2 * max + 1); itr = Begin() + n;
int n = itr - Begin();
:计算迭代器itr
相对于Begin()
的偏移量,并将结果赋值给整型变量n
。这里假设Begin()
是一个返回容器起始位置迭代器的函数。
Reserve(2 * max + 1);
:调用Reserve
函数,将容量扩展为当前容量的两倍加1。这个函数用来确保容器有足够的空间来存储新增的元素。
itr = Begin() + n;
:根据之前计算得到的偏移量n
,通过Begin()
函数获取容器起始位置迭代器,然后将其与偏移量相加,更新迭代器itr
的值。这样做的目的是保证插入位置不会受到扩容操作的影响,始终指向插入前的位置。
上述代码返回值类型为什么是int:int n = itr - Begin();
对于
int n = itr - Begin();
这行代码,返回值类型是int
。
itr - Begin()
返回的是两个迭代器之间的距离,而且针对指针迭代器,其结果类型是一个整数。在这种情况下,
itr
是一个指向容器中的元素的迭代器,Begin()
是指向容器起始位置的迭代器,所以itr - Begin()
的结果会返回两个迭代器之间的元素个数或距离,对于指针迭代器来说,结果是一个整数。因此,
int n = itr - Begin();
将会把itr
和Begin()
之间的距离赋值给n
,所以返回值类型是int
。
代码原来data+size位置的元素是不是被覆盖了
是的,代码中将插入位置之后的元素向后移动一位来腾出空间,并将要插入的元素赋值给插入位置。这样做会覆盖原来data+size位置的元素。具体来说:
首先,使用两个迭代器
p
和q
分别指向数据的末尾和末尾前一个位置(即data+size
和data+size-1
)。接着,使用循环从后向前遍历,将
q
位置上的元素赋值给p
位置上的元素,即将元素向后移动一位。在循环结束后,让
itr
位置上的元素等于要插入的元素item
,完成插入操作。最后,增加
size
的值,表示容器中元素的数量增加了一个。因此,原来
data+size
位置上的元素确实会被覆盖。
图示:
template<class T>
void Vector<T>::Push_back(const T& item)
{
if (size < max) {
data[size] = item;
}
else {
T* old = data;
int len = 2 * max + 1;
data = new T[len];
int i = 0;
for (; i < size; i++) {
data[i] = old[i];
}
data[i] = item;
max = len;
delete[] old;
}
size++; //数据个数增1
}
template<class T>
void Vector<T>::Reserve(int newmax)
{
if(newmax<max) //如果数组容量已满,则返回
return;
T* old=data; //保留原数组
data=new T[newmax]; //重新分配新数组
for(int i=0;i<size;i++) //把原数组中的数据复制到新数组
data[i]=old[i];
max=newmax; //修改数组容量
delete[]old; //释放原数组空间
}
template<class T>//数据个数增为newsize,原数据保留,增加的数据元素初始化为item
void Vector<T>::Resize(int newsize,const T& item)
{
if(newsize>max) //如果数据元素个数大于数组容量
Reserve(newsize*2+1); //扩大数组容量
for(int i=size;i<newsize;i++) //把增加的数据元素初始化为item
data[i]=item;
size=newsize;
}
iterator Erase(iterator first, iterator last); //删除[first,last)区间的数据,返回当前数据的位置。
template<class T>
typename Vector<T>::iterator Vector<T>::Erase(iterator first, iterator last)
{
/*******************请在此处写出成员函数的定义*********************/
While(first!=last)
{
Erase(first);
last--
}
return last;
/******************************************************************/
}
template<class T>
void Vector<T>::Insert(iterator pos, iterator first, iterator last)
{
/*******************请在此处写出成员函数的定义*********************/
for(iterator it=first;it!=last;++it)
{
pos=Insert(pos,*it);
pos++;
}
/******************************************************************/
}
template<class T>
void Vector<T>::Swap(Vector<T>& v)
{
Vector<T> temp = v;
v = *this;
*this = temp;
}
测试代码
#include<iostream>
#include"Vector.h"
using namespace std;
template<class Iterator> //在指定范围内输出元素
void display_vector(Iterator first, Iterator last)
{
for (; first != last; ++first)
cout << *first << '\t';
cout << endl;
}
int main()
{
Vector<int> V1;
for(int i=0;i<10;i++)
{
V1.Push_back(i);
}
cout << "original V1:\t";
display_vector(V1.Begin(), V1.End());
Vector<int> V2;
for (int i = 0; i < 10; i++)
{
V2.Push_back(i * 2 + 1);
}
cout << " original V2:\t ";
display_vector(V2.Begin(), V2.End());
// 不是 V1.XX ,直接函数用
V1.Swap(V2);
cout << "After swap, V1:";
display_vector(V1.Begin(), V1.End());
cout << "V2: ";
display_vector(V2.Begin(), V2.End());
Vector<int>::iterator itr = V1.Begin()+ 3;
V1.Insert(itr, V2.Begin(), V2.End());
cout << "After insert v2 into v1:\n";
display_vector(V1.Begin(), V1.End());
V1.Erase(V1.Begin(), V1.Begin() + 5);
// 删除[V1.Begin(),V1.Begin+5)
cout << "After erase 5 elements, v1:\n";
display_vector(V1.Begin(), V1.End());
return 0;
}