第十八章 31用复制构造函数实现字符串的初始化

//31用复制构造函数实现字符串的初始化
/*
#include <iostream>
using namespace std;
class String
{
public:
	String(); //默认的构造函数
	String(const char*const ch); //构造带值的string
	int getlen()const { return len;}   //读取长度
	const char *getstr()const{ return str;} //读取字符串


	//这里是可以修改的
	char &operator[](unsigned short int  length);
	char  operator[](unsigned short int  length)const;

	//复制构造函数
	String (const String&r);

private:
	unsigned short int len;
	char *str;
};
//创建一个空的str变量
String::String()
{
    len = 0;
	str = new char[1];
	str[0] = '\0';
};
String::String(const char*const ch)
{
	cout<<"带一个参数的构造函数"<<endl;
	len = strlen(ch);
	str = new char[len+1];
	for(int i=0; i<len; i++){
	   str[i] = ch[i];
	}
	str[len] = '\0';
};

char & String::operator[](unsigned short int length)
{
	    if(length > len){
		   return str[len-1]; //返回可见字符的值
		}else{
		   return str[length];
		}
};

char String::operator[](unsigned short int length)const
{
	    cout<<"下标运算符const执行"<<endl;
		if(length > len){
		   return str[len-1]; //返回可见字符的值
		}else{
		   return str[length];
		}
};

String::String (const String&rs)
{
	len = rs.getlen();
	str = new char[len+1];
	for(int i=0; i<len; i++){
	    str[i] = rs[i]; 
		//这里因为我们构造一个新对象并且用旧对象来为它赋值,很明显,不会修改旧对象的值,所以旧对象rs在调用operator[]const函数的时候,不用将指定字符串的地址返回,只需要要按值返回这个字符即可
		//第二次重载的operator[]运算符函数,按值返回的一个字符,同时在函数体前面加了一个const
		//表示该函数可以操作const对象,也就是rs
		//这样由于2个同名的函数,它的类型不同,一个可操作const对象,一个不可以,这样就可以做到了对函数的重载
	}
	str[len]='\0';
	cout<<"复制构造函数完成:"<<str<<endl;

};
int main()
{
	String str;
	cout<<str.getstr()<<endl;
	cout<<"str:"<<str.getlen()<<endl;

	String s1("hello word");
	//cout<<s1.getlen()<<endl;
	cout<<s1.getstr()<<endl;
	cout<<"s1:"<<s1.getlen()<<endl;

	char*temp = "help me";
	String s3(temp);
	cout<<s3.getstr()<<endl;
	cout<<"s3:"<<s3.getlen()<<endl;
	
	//越界的值
	cout<<"越界的值"<<endl;
	cin>>s3[999];
	cout<<s3.getstr()<<endl;
	cout<<"s3:"<<s3.getlen()<<endl;
	cout<<"s3[999]:"<<s3[999]<<endl;
	cout<<s3.getstr()<<endl;

    cout<<"调用复制构造函数"<<endl;
	String s4 = s3; //调用复制构造函数
	cout<<"s4:"<<s4.getstr()<<endl;
	cout<<"s4:"<<s4.getlen()<<endl;

    return 0;
}*/

/*
#include <iostream>
using namespace std;
class A
{
public: 
	A(int i, int j){ x=i; y=j;}
	void set(int s1, int s2){ x=s1; y=s2;}
	void print(){cout<<x<<endl;}
	void print()const { cout<<y<<endl;
	   //set(1,2); 在const函数内不能调用未const函数
	}
private:
	int x, y;
};
int main()
{
	const A a(2,3); //常量对像
	a.print();
	//a.set(22,33); //常量对像不可修改

	A b(4,5);
	b.print();
	b.set(44,55);
	b.print();

	//总结
	//const对像只能调用const成员函数,并且const对像的值不能被修改,只有const成员函数才有资格操作const对像,没有使用const关键字修饰的成员函数不能用来操作const对像
	//另外我们还需要认识到:
	//const不光可以定义常量,而且可用来修饰函数的参数,返回值,甚至函数定义体
	//const修饰函数参数,表示函数参数不可更改
	//const修改函数返咽值,表示返回值不可改变
	//const修饰函数的定义体,表示函数体内就不能修改对像的何意成员
	//在const成员函数体内试图修改const对像的数据成员的值将会产生语法错误
	//而且在const函数体中调用非const成员函数也会产生语法错误

	//这样做对基类很有用,我们知道基类的成员函数可以被派生类继承并覆盖,那么假如我们将基类的成员函数前加修饰符const的话,可防止派生类的覆盖函数改变数据成员的值


    return 0;
}*/

  

<think>好的,我现在需要解决用户的问题:如何在C++中从下标1开始输入字符串。用户希望得到一个示例和方法。首先,我要回忆C++中字符串输入的不同方式,尤其是字符数组和string类的处理。 用户提到的引用[1]和[2]中提到了C风格字符串(字符数组)和C++的string类。用户可能已经了解基本的输入方法,但需要调整输入的位置,从下标1开始存储,而不是默认的0。这可能是因为用户希望保留下标0的位置用于其他用途,或者在处理某些特定数据结构时需要这样做。首先,考虑C风格字符串的情况。通常,使用cin.get()或cin.getline()输入到字符数组时,数据是从下标0开始填充的。如果要从下标1开始,可能需要调整指针的位置。例如,将数组的地址加1,这样输入的数据就会从下标1开始存储。但需要注意数组的大小,确保不会越界。比如,声明为char arr[20],实际可用空间从1到19,这样输入时最多接收19个字符,避免溢出。 其次,对于C++的string类,情况有所不同。string对象的内容通常也是从下标0开始的,但可以通过先输入到一个临时变量,再将其内容插入到目标string的指定位置。例如,使用getline(cin,temp)读取输入,然后将temp的内容值到目标string的第二个字符位置。不过,需要注意的是,直接操作string的下标可能不够灵活,可能需要先调整string的大小,或者使用insert方法。 接下来,我需要验证这些方法的正确性。对于字符数组,传递arr+1作为参数给cin.get()或cin.getline(),这样输入的数据会从arr[1]开始存放。同时,需要确保数组足够大,比如声明为chararr[21],这样从1开始输入20个字符,不会溢出。同时,输入后要手动在末尾添加空字符'\0'吗?其实,cin.get()和cin.getline()会自动添加终止符,但要注意传递的缓冲区大小是否足够。例如,如果数组是arr[21],传入的大小是20,那么输入最多19个字符,加上终止符正好在arr[20],而起始位置是arr[1],所以没问题。对于string类,可能需要先初始化一个足够大的string,例如使用resize()方法调整大小,然后使用输入函数将数据填充到指定位置。或者,先读取到临时string,再将其内容复制到目标string的指定位置。例如:string s; getline(cin,s);target.insert(1, s); 但这样可能需要目标string已经有足够的空间,或者使用拼接的方式。或者,直接构造一个新的string,将下标0留空,然后从1开始填充。例如:string target;target.resize(100); //预留足够空间cin.getline(&target[1], target.size()-1);但这种方法可能不安全,因为直接操作string的内部缓冲区,尤其是在C++11之前,&target[1]可能不保证是连续的。不过,在C++11及以后,string的字符存储是连续的,所以可以这样做。但需要注意,使用cin.getline()时,需要确保缓冲区的大小正确,并且手动设置终止符,或者调整string的长度。例如,输入后,target的大小可能不会自动调整,需要根据实际输入的字符数来设置。可能需要更详细的示例,比如:stringstr; str.resize(20); //预留空间,从0到19cin.getline(&str[1],19);//从下标1开始输入,最多18个字符,加上终止符在str[19] str.resize(strlen(&str[1])+1);//调整大小,可能需要计算实际长度但这种方法可能比较复杂,且容易出错。另一种方法是使用临时字符数组,输入到数组后,再复制到string的指定位置。总结,用户的问题需要分别处理C风格字符串和C++ string的情况,提供不同的方法,并给出示例代码。需要确保示例代码正确,不会导致缓冲区溢出,并且正确处理终止符。同时,要提醒用户注意数组大小和输入长度的限制,避免常见错误。</think>在C++中实现从下标1开始输入字符串,可以通过调整指针位置或使用`string`类的灵活操作实现。以下是具体方法及示例: --- ### **方法1:C风格字符数组** 通过**指针偏移**将输入流指向数组的第1个元素地址: ```cpp #include <iostream> using namespace std; int main() { char arr[21]; // 总长度21(下标0~20) cout << "输入最多19个字符:"; cin.get(arr + 1, 20); // 从arr[1]开始存储,最多接收19个字符+自动添加'\0' cout << "实际内容: " << &arr[1] << endl; // 输出从arr[1]开始的字符串 return 0; } ``` - **关键点**:`arr + 1`表示从下标1开始写入,`20`表示最多写入19个字符(保留1个位置给终止符`\0`)[^1][^2]。 --- ### **方法2:C++ string类** 通过预分配空间并直接操作内存: ```cpp #include <iostream> #include <string> using namespace std; int main() { string str; str.resize(20); // 预分配空间(下标0~19) cout << "输入字符串:"; cin.getline(&str[1], 19); // 从str[1]开始写入,最多18字符+'\0' str[0] = ' '; // 下标0可单独值(如占位符) cout << "完整内容: " << str << endl; return 0; } ``` - **关键点**:`&str[1]`获取下标1的地址,`19`限制输入长度(需C++11及以上支持连续存储)[^2]。 --- ### **注意事项** 1. **缓冲区大小**:数组/字符串长度需至少为`所需下标 + 最大字符数 + 1`(例如下标1开始存19字符,则总长度≥21)。 2. **输入安全**:使用`cin.get()`或`cin.getline()`避免溢出,优于`cin >>`[^1]。 3. **终止符**:C风格数组会自动添加`\0`,而`string`需要手动调整逻辑长度(如`str.resize()`)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值