C++Day7 类和对象2,实现String类和双向链表习题

[C++语法规则很多,要落实下来,得通过多敲代码来理解,看N遍不如写一次;在写代码的过程中,会碰到其它你不曾碰到过的编译问题,切记程序是调试出来的;再就是通过练习,把敲代码的速度提升上来,熟悉键盘,培养写代码的感觉]

一、简答题

1、当定义类时,编译器会为类自动生成哪些函数?这些函数各自都有什么特点?

名称特点
构造函数1.默认情况下,编译器会自动生成构造函数 。形式上是函数名与类名相同,没有返回值,但是可以传参数,故构造函数可以重载 。 2 .全局对象和全局静态对象的构造函数在main()函数执行之前就被调用,局部静态对象的构造函数是程序第一次执行到才被调用。
析构函数1.函数名为~类名、没有返回值、没有返回类型,当程序执行后,系统将自动调用自动创建的析构函数,将对象释放。 2.默认的析构函数不能删除new在自由存储器中分配的对象和对象成员,需要自己自定义析构函数,然后显示使用delete运算符来释放new运算符分配的内存
拷贝函数调用时机:1. 当用一个已经存在的对象初始化另一个新对象时,会调用拷贝构造函数。 2. 当实参和形参都是对象,进行实参与形参的结合时,会调用拷贝构造函数。 3. 当函数的返回值是对象,函数调用完成返回时,会调用拷贝构造函数。注意:(const Computer & rhs) 中 const一般不可去掉,而&不可去掉。
赋值运算符函数1.函数名为operator=、返回值为类名、参数为const类&,用来对已存在的对象进行赋值。 2.定义类时引用符号不可以去掉,若去掉会多执行一次拷贝构造函数,效率会降低。不可去掉const,若右操作数是右值(不可取地址),会产生废const左值引用不大于右值的报错 3.返回类型不能是void型,否则函数连载会发生错误

2、什么是左值与右值,拷贝构造函数中的引用与const为什么不能去掉?

左值:可以取地址,内存中有实际存储
​
右值:不能取地址,例如临时对象、匿名对象、临时变量、字面值常量(如10)都属于右值

3、this指针是什么?

1.指针常量;
​
2.用来指向对象本身,隐藏于非静态成员函数的第一个参数位置

二、写出下面程序结果。

1、写出以下程序运行的结果。

#include <math.h>
#include <iostream>
​
using std::cout;
using std::endl;
​
class Point 
{
public:
    Point(int xx = 0, int yy = 0) 
    {
        X = xx;
        Y = yy;
        cout << "point构造函数被调用" << endl;
    }
    
​
    Point(Point &p);
    
    int GetX() 
    {
        return X;
    }
    
    int GetY() 
    {
        return Y;
    }
​
private:
    int X,Y;
};
​
Point::Point(Point &p)  
{
    X = p.X;
    Y = p.Y;
    cout << "X = " << X << " Y=" << Y << "Point拷贝构造函数被调用" << endl;
}
​
class Distance  
{
public: 
    Distance(Point xp1, Point xp2);
    double GetDis()
    {
        return dist;
    }
private:    
    Point p1,p2;    
    double dist;    
};
​
Distance::Distance(Point xp1, Point xp2)
: p1(xp1)
,p2(xp2)
{
    cout << "Distance构造函数被调用" << endl;
    double x = double(p1.GetX() - p2.GetX());
    double y = double(p1.GetY() - p2.GetY());
    dist = sqrt(x * x + y * y);
}
​
int main()
{
    Point myp1(1,1), myp2(4,5);
    Distance myd(myp1, myp2);
    cout << "The distance is:" ;
    cout << myd.GetDis() << endl;
    
    return 0;
}
point构造函数被调用
point构造函数被调用
X = 4 Y = 5 Point拷贝构造函数被调用
X = 1 Y = 1 Point拷贝构造函数被调用
X = 1 Y = 1 
X = 4 Y = 5 Point拷贝构造函数被调用
Distance构造函数被调用
The distance is:5
​
​
​
​
(本题题点:   )  Distance::Distance(Point xp1, Point xp2)
                : p1(xp1)
                ,p2(xp2)
                
                形参实参结合要调用一次拷贝构造函数,初始化赋值也要调用一次拷贝构造函数

2、写出以下程序运行的结果。

#include<iostream>
using namespace std;
class MyClass
{
public:
    MyClass(int i = 0)
    {
        cout << i;
    }
    MyClass(const MyClass &x)
    {
        cout << 2;
    }
    MyClass &     operator=(const MyClass &x)
    {
        cout << 3;
        return *this;
    }
    ~MyClass()
    {
        cout << 4;
    }
};
int main()
{
    MyClass obj1(1), obj2(2);
    MyClass obj3 = obj1;
    obj2 = obj1   
    return 0;
}
122444

3、不考虑任何编译器优化(如:NRVO),下述代码的第10#会发生

#include <iostream>
​
using std::cout;
using std::endl;
​
classB
{
public:
    B()  //构造函数
    {
        cout << "B()" << endl;
    }
​
    ~B()  //析构函数
    {
        cout << "~B()" << endl;
    }
    
    B(const B &rhs)  //拷贝构造函数
    {
        cout << "B(const B&)" << endl;
    }
    
    B &operator=(const B &rhs)   //运算符重载函数
    {
        cout << "B &operator=(const B &s)" << endl;
    
        return  *this;
    }
};
​
B func(const B &rhs)
{
    cout << "B func(const B &)" << endl;
    return rhs;
}
​
​
int main(int argc, char **argv)
{
    B b1,b2;
    b2=func(b1);//10#
​
    return 0;
}
​
b1 是实参,将值传给func()函数的形参rhs, func()函数输出  B func(const B &) ,再将rhs的值作为func()的值,这个过程调用了拷贝构造函数,将rhs传给func(),最后赋值给b2,复制的过程调用的运算符重载函数,输出B &operator=(const B &s),最后b2本身赋值b2
​
​

三、编程题。

1、实现一个自定义的String类,保证main函数对正确执行

#include <iostream>
#include <string.h>
#include <string>
using std::cout;
using std::endl;

class String
{
public:
	String();
	String(const char *pstr);
	String(const String &rhs);
	String &operator=(const String &rhs);
	~String();
	void print();

private:
	char * _pstr;
};

int main()
{
	String str1;
	str1.print();
	

	String str2 = "Hello,world";
	String str3("wangdao");
	
	str2.print();		
	str3.print();	
	
	String str4 = str3;
	
	str4.print();
	cout<<"111111111111111111111111"<<endl;
	str4 = str2;
	str4.print();
	
	return 0;
}

/*下面为实现过程*/
//构造函数 
String::String()
{
	_pstr = new char[1]();
}

//重载构造函数 
String::String(const char *pstr) {
	if(pstr==NULL){
        _pstr=new char[1]();
    }else{
        _pstr=new char[strlen(pstr)+1];
        strcpy(_pstr,pstr);
    }
}

//拷贝构造函数 
String::String(const String &rhs) {
	_pstr = new char[strlen(rhs._pstr) + 1] ();
	strcpy(_pstr , rhs._pstr); 
}

//赋值函数 
String & String::operator=(const String &rhs) {
	if(this!=&rhs){
		delete [] rhs._pstr;
		_pstr=NULL;
		_pstr = new char[strlen(rhs._pstr) + 1] (); 
		strcpy(_pstr , rhs._pstr); 
	}
	return *this;
}

//析构函数
String::~String(){
	delete[] _pstr;
	cout << "析构函数!" << endl;
}

//打印成员函数
void String::print(){
	if(NULL==_pstr){
		//没有信息就不需要打印
		return;
	}
	puts(this->_pstr);
}

老师标准答案:

#include <string.h>
#include <iostream>

using std::cout;
using std::endl;

class String
{
public:
    String()
    : _pstr(nullptr)
    /* : _pstr(new char[1]()) */
    {
        cout << "String()" << endl;
    }

    String(const char *pstr)
    : _pstr(new char[strlen(pstr) + 1]())
    {
        cout << "String(const char *)" << endl;
        strcpy(_pstr, pstr);
    }

    String(const String &rhs)
    : _pstr(new char[strlen(rhs._pstr) + 1]())
    {
        cout << "String(const String &)" << endl;
        strcpy(_pstr, rhs._pstr);
    }

    String &operator=(const String &rhs)
    {
        cout << "String &operator=(const String &)" << endl;
        if(this != &rhs)
        {
            delete [] _pstr;
            _pstr = nullptr;

            _pstr = new char[strlen(rhs._pstr) + 1]();
            strcpy(_pstr, rhs._pstr);
        }

        return *this;
    }

    ~String()
    {
        cout << "~String()" << endl;
        if(_pstr)
        {
            delete [] _pstr;
            _pstr = nullptr;
        }
    }

    void print() const
    {
        if(_pstr)
        {
            cout << _pstr << endl;
        }
        else
        {
            cout << "nullptr == _pstr " << endl;
        }
    }

private:
    char *_pstr;
};

int main(void)
{
    String str1;
    str1.print();

    cout << endl;
    //C++           C
    String str2 = "Hello,world";//String("Hello,world")
    String str3("wangdao");

    /* String b();//函数声明 */
    /* String s1; */

    str2.print();       
    str3.print();   

    cout << endl;
    String str4 = str3;
    str4.print();

    cout << endl;
    str4 = str2;
    str4.print();

    return 0;
}

2、用C++实现一个双向链表

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

struct Node
{
	int data;
 	Node * pre;
 	Node * next;
}; 

class List
{
public:
	List();
 	~List();
				
     void push_front(int data);//在头部进行插入         
     void push_back(int data);//在尾部进行插入
                 
     void pop_front();//在链表头部进行删除          
     void pop_back();//在链表的尾部进行删除
     
     bool find(int data);//在链表中进行查找
     void insert(int pos, int data);//在指定位置后面插入pos 
     void display() const; //打印链表	
     void erase(int data);//删除一个指定的节点			 		

private:
	Node * _head;
 	Node * _tail;
 	int    _size;
};
//构造函数 
List::List() :_head(NULL),_tail(NULL),_size(0)   
{

}    
//头插法插入节点 
void List::push_front(int data) {
	Node *p = new Node[1]();
	p->data = data;
	p->next = NULL;
	p->pre = NULL;
	if(NULL == _head) {
		_head = p;
		_tail = p;
	}else {
		p->next = _head;
		_head->pre = p;
		_head = p;
	}
	_size++;
}

//尾部插入
 void List::push_back(int data) {
 	Node *p = new Node[1];
 	p->data = data;
	p->next = NULL;
	p->pre = NULL;
	if(NULL == _tail) {
		_tail = p;
		_head = p;
	}else {
		p->pre = _tail;
		_tail->next = p;
		_tail = p;
	}
	_size--;
 }
 
 //在链表头部进行删除
 void List::pop_front() {
 	if(_size != 0) {  //链表不空时,进行删除 
		Node *s = _head;   //定义一个指针指向第一个元素 
 		s->next->pre = NULL;  //
 		_head = s->next;
		s->next = NULL;
		delete s;//
		s = NULL;
		_size--;
	 }
 }
 
 void List::pop_back() {
 	if(_size != 0) {  //链表不空时,进行删除 
 		Node *s = _tail;
 		s->pre->next = NULL;
 		_tail = s->pre;
 		s->pre = NULL;
 		delete s;
 		_size--;
	 }
 }
 
 bool List::find(int data) {
 	if(_size != 0) {
 		Node *s = _head;
 		while(s) {
 			if(s->data == data) {
 				cout << "找到!"  << endl;
 				return true;
			 }
			 s = s->next;
		 }
		 cout << "没找到!" << endl; 
	 }
 }
 
 void List::insert(int pos, int data)  {
 	int n = 1;
	Node *s = _head;
 	while (n != pos ) {
 		s = s->next;
 		n++;
	}
	//分头中尾插入 
	Node *p = new Node[1]();
	p->data = data;
 }

四、算法题

1、矩阵中的路径

题目:请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用下划线标出)。但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。

2、剪绳子

题目:给你一根长度为n绳子,请把绳子剪成m段(m、n都是整数,n>1并且m≥1)。每段的绳子的长度记为k[0]、k[1]、……、k[m]。k[0]*k[1]*…*k[m]可能的最大乘积是多少?例如当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到最大的乘积18。

3、二进制中1的个数

题目:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如:把9表示成二进制是1001,有2位是1。因此如果输入9,该函数输出2。

4、数组中出现次数超过一半的数字

题目:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1, 2, 3, 2, 2, 2, 5, 4, 2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值