<刷题记录>C++程序设计练习题

 一、选择

1.下列程序段的运行结果是,strlen 函数不包括\0
char c[]="\t\v\\0will\n";

cout<<strlen(c);

1.\t 2.\v 3.\\ 4.0 5.w 6.i 7.l 8.l 9.\n

#include<iostream>
#include<cstring>
using namespace std;
int main()
{
	char c[]="\t\v\\0will\n";
	cout<<strlen(c)<<endl;//9
	for(int i=0;i<strlen(c);i++)
	{
		cout<<c[i]<<endl;
	}
	printf("%d \n", strlen("IBM\n012\1\\"));//9
	printf("%d \n",strlen("\t\"\065\xff\n"));//5
	printf("%d \n",strlen("stop\0\n\""));//4
 } 

char str[]="\tab\n\012\\\""

字符1: \t 转义字符:水平制表符 ,其ASCII 值9(十进制)

程序在输出时将光标移动到下一个制表符位置,这通常是下一个8的倍数的位置(但这也取决于具体的文本编辑器或终端设置)。在文本输出中,"\t" 的作用类似于在键盘上按下 Tab 键

字符2、3:ab

字符4:\n 转义字符,换行符,其ASCII 值10(十进制) (\r表示回车)

字符5:\012 转义字符,其中012是8进制数,其ASCII值 同\n.

字符6:\\ 转义字符 反斜杠\,其ASCII值 92(十进制)

字符7:\" 转义字符 双引号",其ASCII值 34(十进制)

2.  printf("%d \n", strlen("IBM\n012\1\\"));

字符1、2、3: IBM

字符4:\n 转义字符

字符5、6、7:012

字符8:\1 其ASCII值 1(8进制).

字符9:\\ 转义字符 反斜杠\,其ASCII值 92(十进制)

3. printf("%d \n",strlen("\t\"\065\xff\n"));

字符1: \t 转义字符:水平制表符 ,其ASCII 值9(十进制)

字符2:\" 转义字符 双引号",其ASCII值 34(十进制)

字符3:\065 ,代表字符5,其中065为8进制 格式,其ASCII为53(十进制)

字符4:\xff (这个我不知道怎么解释,请其它老师帮助解释)

字符5:\n

4.   printf("%d \n",strlen("stop\0\n\""));

字符1、2、3、4:stop

因为strlen()函数遇到\0 就结束了,后面的字符就不去判断了。

C语言中的字符串 是用\0作为 结束符。

转载:weixin_39681161

2.编译多态基于template(模板)与函数重载,运行多态基于类继承关系和虚函数

 3.类型相同的两个指针不能进行的运算是( A )。
A. +
B. -
C.=
D. ==

A. + - 对于两个指针,不能直接进行加法运算(+)。指针的加法运算没有定义,因为指针指向的是内存中的地址,而地址之间的“加法”没有明确的数学意义。

B. - - 两个类型相同的指针之间可以进行减法运算(-),其结果表示两个指针所指向地址之间的偏移量(以所指向类型的元素为单位)。

C. = - 两个指针之间可以使用赋值运算符(=),将一个指针的值赋给另一个指针。

D. == - 两个指针之间可以使用相等运算符(==)或不等运算符(!=)来比较它们是否指向相同的内存地址。

二、填空:

1.函数参数传递方式有三种,分别为:值传递、地址传递和(引用传递)。
2.面向对象的程序设计的三大特征是: (封装)、 继承性和多态性。
3.假定A为一个类,则语句A(A&x);是此类(拷贝(复制))构造函数的原型说明。
4.在类的继承与派生中,缺省的继承方式是(私有继承)。
5. C++的两种多态性分别是(编译时)多态性和(运行时)多态性。
6.运算符重载有两种实现方法,一种是通过友元函数来实现,另一种通过(成员)函数来实现。
7.根据数据的组织形式不同,可将文件分为二进制文件和(文本 )文件。
8.若希望类中的成员只能被该类的成员函数及该类的派生类的成员函数访问,则应加上访问权限: ( protected)。
9.假定类A中有一个公用属性的静态数据成员b,在类外不通过对象名访问该成员b的写法为( A::b)。


public,protected,private

1.类实例(即类对象)不能直接访问类的 private成员和protected成员,但是能直接访问类的public成员。

  • public:可以从任何地方访问该成员,无论是同一个包内还是不同的包。
  • private:只能在该成员所在的类内部访问,类外无法访问。
  • protected:可以在同一个包内的任何类和该成员所在类的子类中访问,即使子类在不同的包中。

2.另外无论哪种继承方式,子类都不能直接访问父类的 private成员;但是能直接访问父类的 protected成员和public成员(注意:是子类,而不是类实例),并且能通过父类的protected成员函数和public成员函数间接访问父类的private成员;这句话强调了类与类之间通过继承方式的访问规则,而非类与实例之间的访问规则。

3.子类通过public方式继承父类,则父类中的public、protected和private属性的成员在 子类 中 依次 是 public、protected和private属性,即通过public继承并不会改变父类原来的数据属性。

4.子类通过protected方式继承父类,则父类中的public、protected和private属性的成员在 子类 中 依次 是 protected、protected和private属性,即通过protected继承原来父类中public属性降级为子类中的protected属性,其余父类属性在子类中不变。

5.子类通过private方式继承父类,则父类中的public、protected和private属性的成员在 子类 中 依次 是 private、private和private属性,即通过private继承原来父类中public属性降级为子类中的private属性,protected属性降级为子类中的private属性,其余父类属性在子类中不变。
                        
参考:https://blog.youkuaiyun.com/xrinosvip/article/details/119191555

三、程序输出 

1. 

#include <iostream>
using namespace std;
//先父类后子类  先成员后函数 
//先A后B后C  A-A B-B C-先成员a-A 后函数C 
class A
{
public:
int n;
A(){cout<<"A";
}
};	
class B:public A{
public:
B(){cout<<"B";
}
};
class C:public B
{
public:
C():a(),B(){cout<<"C";
}A a;
};
int main()
{
	C c; 
}
//ABAC

 2.基类指针指向派生类对象 调用同名函数(基类虚构)实现的是派生类重写的函数(如果存在)

#include <iostream>
using namespace std;
class Base {
	protected:
	int *p;
	public:
	Base(int a=0){p=new int(a);}
	~Base(){delete p;}
	virtual void print(){cout<<"p->"<<*p<<endl;}	
};

class Derived:public Base
{
	static int y;
	public:
	Derived(int b=0){*p=b;y++;} 
	void print(){cout<<*p<<','<<y<<endl;}
};
int Derived::y=100;
int main()
{
	Derived d(50);
	Base* pb=&d;
	pb->print();//50,101
	Derived d1(20);
	d1.print();//20,102
}

3.重载运算符区分前缀++后缀++

#include <iostream>
using namespace std;
class B{
	int a,b;
	public:
	B(int aa=0,int bb=0){ a=aa;b=bb;}
	void operator ++(); //++a
	void operator ++(int); //a++,只能是int
	void show(){cout<<a<<'\t'<<b;}
};
void B:: operator ++()
{	
	a+=2;
	b+=5;	
}
void B:: operator ++(int)
{
	a+=5;
	b+=2;	
}

int main(){
	B x(3,5);
	x++;
	x.show();	
}
//8    7

4.

#include <iostream>
using namespace std;
class A{
	public:
	A(int n){ num=n;}
	int compare(A a)
	{
	if(this->num==a.num)return 1;
	else return 0;
    }
	private:
	int num;
};
int main()
{
	A aa(5);
	A bb(10);
	A cc(5);
	cout<<aa.compare(bb)<<'\t';//0 
	cout << cc.compare(aa)<<endl;//1	
}

四、完善程序

1.下列程序通过重载运算符“*”,直接实现两个一维数组对应元素相乘运算。设数组a,b分别为:
int a[10]={1,2,3,4,5,6,7,8,910};
int b[10]={ 1,2,3,4,5,6,7,8,9,10};
相乘后的结果为{1,4,9,16,25,36,49,64,81,100}。同时通过重载运算符“=”,直接实现两个一维数组的赋值运算。试完善程序。

//下列程序通过重载运算符“*”,直接实现两个一维数组对应元素相乘运算。设数组a,b分别为:
//int a[10]={1,2,3,4,5,6,7,8,910};
//int b[10]={ 1,2,3,4,5,6,7,8,9,10};
//相乘后的结果为{1,4,9,16,25,36,49,64,81,100}。同时通过重载运算符“=”,直接实现两个一维数组的赋值运算。试完善程序。
#include <iostream>
#include <string >
using namespace std;
class A {
	int x[10];
	public:
	A(){for(int i=0;i<10;i++) x[i]=0;}
	A(int *p)
	{
	for(int i=0;i<10;i++) x[i]=p[i];
	}
	A operator *(A a){
	A t;
	for(int i=0;i<10;i++) t.x[i]=a.x[i]*this->x[i];
	//t.x[i]=a.x[i]*t.x[i];错  这里t是新建初始化都为0 
	//您错误地使用了 t.x[i] 而不是 this->x[i],这样会导致与未初始化的 t 对象的元素相乘
	return t;
	}
	A operator =(A a){
	for(int i=0;i<10;i++) x[i]=a.x[i];
	return *this;
	}
	//使用引用传递,并检查自赋值。 
//	A& operator =(const A& a) {  
//        if (this != &a) {  
//            for(int i = 0; i < 10; i++) x[i] = a.x[i];  
//        }  
//        return *this;  
//    }  
	void show(){ 
	for(int i=0;i<10;i++) 
	cout<<x[i]<<'\t';}
	
};
int main()
{
	int a[10]={1,2,3,4,5,6,7,8,9,10};
	int b[10]={1,2,3,4,5,6,7,8,9,10};
	A a1(a),a2(b),a3;
	a3=a1*a2;
	a3.show();	
}

2.下列函数的功能是将-一个新生成的链表按照从小到大的顺序插入到现有的链表中,请完成函数。

//4.下列函数的功能是将-一个新生成的链表按照从小到大的顺序插入到现有的链表中,请完成函数。
struct node {
	int data;
	node * next;
};
node * Insert(node *head, node *p)//将p指向的结点插入到head代表的链表中
{
	node *p1,*p2;
	if(head==0){//空链表插入到链表首部
		head=p;
		p->next=NULL; 
	    return head;
	}
	if(head->data>=p->data){/非空链表,p的数据项比首节点的数据项小,插入到链首
	p->next=head;
	head=p;
	return head;
	}
	p2=p1=head;
	while(p2!=NULL&&p->data>p2->data){//找到 要插入的位置
	p1=p2;p2=p2->next;
    }
	if(p2->data<p->data){/p代表的结点的数据项最大,插入到表尾
	p2->next=p;p->next=0;
	}
	else
	{
	p->next=p2;
	p1->next=p;
	}//插入到p1和p2指向的结点之间
}

3.下面的程序中定义了圆类Circle、长方形类Rect、圆角长方形类RoundRect,其中RoudRect共有继承于Circle 和Rect类。试完成程序。

//下面的程序中定义了圆类Circle、长方形类Rect、圆角长方形类RoundRect,其中RoudRect共有继承于Circle 和Rect类。试完成程序。
#include <iostream>
#include <cstring>
using namespace std;
class Circle{
	double radius;
	public:
	Circle(double r):radius(r) {}
	double area(){ return 3.14*radius* radius;}
	};
class Rect{
	double width, height;
	public:
	Rect(double w, double h){width=w,height=h;}
	double area(){ return height*width;}
    };
class RoundRect:public Circle,public Rect{
	char color[5];
	public:
	RoundRect(double r,double w, double h,char *c):Circle(r),Rect(w,h)
	{
		strcpy(color,c);
	}
	char *getcolor( ){ return color;}
};
int main()
{
	RoundRect r(0.8,1,0.25,"白色");
	cout<<r.getcolor()<<endl;
}


深拷贝浅拷贝

  • 浅拷贝:(只拷贝指针)浅拷贝是指拷贝对象时仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。换句话说,如果原对象包含对其他对象的引用,那么浅拷贝得到的新对象将仍然包含对原对象中这些引用的指向,而不是指向这些引用的新拷贝。这意味着如果通过新对象修改了这些引用的内容,原对象中的相应内容也会被修改,因为它们实际上指向的是同一个对象。
  • 深拷贝:(生成副本对象深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。也就是说,如果原对象包含对其他对象的引用,深拷贝会创建这些引用的新拷贝,并将新对象的引用指向这些新拷贝,而不是原对象中的引用。这样,新对象和原对象就完全独立了,对新对象的任何修改都不会影响到原对象。
#include <iostream>  
#include <cstring> // 用于memcpy  
  
class MyClass {  
private:  
    int* arr;  
    size_t size;  
  
public:  
    // 构造函数  
    MyClass(size_t size) : size(size) {  
        arr = new int[size];  
        std::memset(arr, 0, sizeof(int) * size); // 初始化数组为0  
    }  
  
    // 浅拷贝构造函数  
    MyClass(const MyClass& other) : size(other.size) {  
        arr = other.arr; // 浅拷贝,只是复制指针,不复制数组内容  
    }  
  
    // 深拷贝构造函数  
    MyClass(const MyClass& other, bool deepCopy) : size(other.size) {  
        if (deepCopy) {  
            arr = new int[size]; // 分配新内存  
            std::memcpy(arr, other.arr, sizeof(int) * size); // 复制数组内容  
        } else {  
            arr = other.arr; // 仍然是浅拷贝  
        }  
    }  
  
    // 析构函数  
    ~MyClass() {  
        delete[] arr; // 释放数组内存  
    }  
  
    // 赋值运算符的浅拷贝重载  
    MyClass& operator=(const MyClass& other) {  
        if (this != &other) {  
            size = other.size;  
            arr = other.arr; // 浅拷贝,只是复制指针  
        }  
        return *this;  
    }  
  
    // 赋值运算符的深拷贝重载(可选实现)  
    MyClass& deepCopyAssign(const MyClass& other) {  
        if (this != &other) {  
            delete[] arr; // 先释放旧内存  
            size = other.size;  
            arr = new int[size]; // 分配新内存  
            std::memcpy(arr, other.arr, sizeof(int) * size); // 复制数组内容  
        }  
        return *this;  
    }  
  
    // 打印数组内容  
    void print() const {  
        for (size_t i = 0; i < size; ++i) {  
            std::cout << arr[i] << ' ';  
        }  
        std::cout << std::endl;  
    }  
};  
  
int main() {  
    // 创建第一个对象  
    MyClass obj1(5);  
    obj1.arr[0] = 1; // 修改数组内容  
  
    // 浅拷贝示例  
    MyClass obj2(obj1); // 使用浅拷贝构造函数  
    obj2.print(); // 输出:1 0 0 0 0  
    obj2.arr[1] = 2; // 修改obj2的数组内容  
    obj1.print(); // 输出:1 2 0 0 0,因为obj1和obj2的arr指向同一块内存  
  
    // 深拷贝示例  
    MyClass obj3(obj1, true); // 使用深拷贝构造函数  
    obj3.print(); // 输出:1 2 0 0 0,此时obj3的内容是obj1的一个完整拷贝  
    obj3.arr[2] = 3; // 修改obj3的数组内容  
    obj1.print(); // 输出:1 2 0 0 0,obj1的内容没有改变,因为obj3有自己的内存拷贝  
  
    // 浅拷贝赋值运算符示例  
    MyClass obj4(5);  
    obj4 = obj3; // 使用浅拷贝赋值运算符  
    obj4.print(); // 输出:1 2 3 0 0  
    obj4.arr[3] = 4; // 修改obj4的数组内容  
    obj3.print(); // 输出:1 2 3 4 0,因为obj3和obj4的arr现在指向同一块内存  
  
    // 注意:这里没有演示深拷贝赋值运算符的使用,因为它需要显式调用deepCopyAssign方法。  
    // 在实际使用中,通常会重载赋值运算符以提供深拷贝功能,而不是提供另一个方法。  
  
    return 0;  
}

译者序 前言 第1章 对象的演化 1.1基本概念 1.1.1对象:特性十行为 1.1.2继承:类型关系 1.1.3多态性 1.1.4操作概念:OOP程序像什么 1.2为什么C++会成功 1.2.1较好的C 1.2.2采用渐进的学习方式 1.2.3运行效率 1.2.4系统更容易表达和理解 1.2.5“库”使你事半功倍 1.2.6错误处理 1.2.7大程序设计 1.3方法学介绍 1.3.1复杂性 1.3.2内部原则 1.3.3外部原则 1.3.4对象设计的五个阶段 1.3.5方法承诺什么 1.3.6方法应当提供什么 1.4起草:最小的方法 1.4.1前提 1.4.2高概念 1.4.3论述(treatment) 1.4.4结构化 1.4.5开发 1.4.6重写 1.4.7逻辑 1.5其他方法 1.5.1Booch 1.5.2责任驱动的设计(RDD) 1.5.3对象建模技术(OMT) 1.6为向OOP转变而采取的策略 1.6.1逐步进入OOP 1.6.2管理障碍 1.7小结 第2章 数据抽象 2.1声明与定义 2.2一个袖珍C库 2.3放在一起:项目创建工具 2.4什么是非正常 2.5基本对象 2.6什么是对象 2.7抽象数据类型 2.8对象细节 2.9头文件形式 2.10嵌套结构 2.11小结 2.12练习 第3章 隐藏实现 3.1设置限制 3.2C++的存取控制 3.3友元 3.3.1嵌套友元 3.3.2它是纯的吗 3.4对象布局 3.5类 3.5.1用存取控制来修改stash 3.5.2用存取控制来修改stack 3.6句柄类(handleclasses) 3.6.1可见的实现部分 3.6.2减少重复编译 3.7小结 3.8练习 第4章 初始化与清除 4.1用构造函数确保初始化 4.2用析构函数确保清除 4.3清除定义块 4.3.1for循环 4.3.2空间分配 4.4含有构造函数和析构函数的stash 4.5含有构造函数和析构函数的stack 4.6集合初始化 4.7缺省构造函数 4.8小结 4.9练习 第5章 函数重载与缺省参数 5.1范围分解 5.1.1用返回值重载 5.1.2安全类型连接 5.2重载的例子 5.3缺省参数 5.4小结 5.5练习 第6章 输入输出流介绍 6.1为什么要用输入输出流 6.2解决输入输出流问题 6.2.1预先了解操作符重载 6.2.2插入符与提取符 6.2.3通常用法 6.2.4面向行的输入 6.3文件输入输出流 6.4输入输出流缓冲 6.5在输入输出流中查找 6.6strstreams 6.6.1为用户分配的存储 6.6.2自动存储分配 6.7输出流格式化 6.7.1内部格式化数据 6.7.2例子 6.8格式化操纵算子 6.9建立操纵算子 6.10输入输出流实例 6.10.1代码生成 6.10.2一个简单的数据记 6.11小结 6.12练习 第7章 常量 7.1值替代 7.1.1头文件里的const 7.1.2const的安全性 7.1.3集合 7.1.4与C语言的区别 7.2指针 7.2.1指向const的指针 7.2.2const指针 7.2.3赋值和类型检查 7.3函数参数和返回值 7.3.1传递const值 7.3.2返回const值 7.3.3传递和返回地址 7.4类 7.4.1类里的const和enum 7.4.2编译期间类里的常量 7.4.3const对象和成员函数 7.4.4只读存储能力 7.5可变的(volatile) 7.6小结 7.7练习 第8章 内联函数 8.1预处理器的缺陷 8.2内联函数 8.2.1类内部的内联函数 8.2.2存取函数 8.3内联函数和编译器 8.3.1局限性 8.3.2赋值顺序 8.3.3在构造函数和析构函数里隐藏行为 8.4减少混乱 8.5预处理器的特点 8.6改进的错误检查 8.7小结 8.8练习 第9章 命名控制 9.1来自C语言中的静态成员 9.1.1函数内部的静态变量 9.1.2控制连接 9.1.3其他的存储类型指定符 9.2名字空间 9.2.1产生一个名字空间 9.2.2使用名字空间 9.3C++中的静态成员 9.3.1定义静态数据成员的存储 9.3.2嵌套类和局部类 9.3.3静态成员函数 9.4静态初始化的依赖因素 9.5转换连接指定 9.6小结 9.7练习 第10章 引用和拷贝构造函数 10.1C++中的指针 10.2C+十中的引用 10.2.1函数中的引用 10.2.2参数传递准则 10.3拷贝构造函数 10.3.1传值方式传递和返回 10.3.2拷贝构造函数 10.3.3缺省拷贝构造函数 10.3.4拷贝构造函数方法的选择 10.4指向成员的指针(简称成员指针) 10.5小结 10.6练习 第11章 运算符重载 1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值