文章目录
程序的输出是什么?
1. 关于static的应用:
加static就是静态局部变量: 在函数调用结束后,值不消失保留原值,占用的存储单元不释放;下一次调用该函数时,静态局部变量仍保留上一次函数调用结束时的值,静态局部变量只能被初始化一次。
不加static就是默认的自动变量: 函数调用结束自动释放内存空间,不保留上一次调用函数的值。
例题1:
static int fun(int j)
{
int i = j;
return ++i;
}
int main()
{
int i = 0;
int j = 5;
for (; j != 0; --j)
i = fun(j);
cout << i << endl;
while (1);
return 0;
}
输出:2
例题2:
static int fun(int j)
{
static int i = j;//只能被初始化一次
return ++i;
}
int main()
{
int i = 0;
int j = 5;
for (; j != 0; --j)
i = fun(j);
cout << i << endl;
while (1);
return 0;
}
输出:10
2. 关于取值符&
与指针*
:
*
: 间接运算符。 用来说明该变量是指针变量。&
: 取址运算符。*&
:表示地址值所代表的内存块的内容。int *p;
中,我们称int是指针变量p的基类型。
- 给指针变量赋值
int k=1,*p; p = &k;//将变量k的地址赋给了p,也就是p指向了变量k。int j = *p;
这个例子中&k
表示取出变量k
的地址赋给p
,*p
表示取出p
也就是取地址&k
中的内容给了变量j
。 - 给指针变量赋空值
p=NULL;
等价于p='\0';
或p=0;
- 像
*&i
、(*p)++
、++*p
、*p++
:这些都是自右向左计算的。 *p +1
表取指针变量p所指存储单元中的内容后加1*p+=1
可写成(*p)++
或++*p
*++p
表示指针地址向后移一位之后返回该位置的值;++*p
表示指针所指的值+1后返回,比如以下例题很经典:
例题:
int a = 3;
int *p = &a;
cout << *p;
输出:3
3. 基类、派生类的概念、继承的概念、函数的隐藏
- 继承的概念
继承: 通过继承联系在一起的类构成一种层次关系。
- 通常在层次关系的根部有一个基类, 也称为父类。
- 其他类直接或间接地从基类继承而来, 这些继承得到的类称为派生类, 也称为子类。
- 基类负责定义在层次关系中所有类共同拥有的成员, 而每个派生类定义各自特有的成员。
- 函数的隐藏指的是:派生类的函数屏蔽了与其同名的基类函数。
- 补充复习:
虚函数(函数最左边加上一个virtual): 作用是为了实现多态性:即同一类族中不同类的对象,对同一调用做出不同的响应。
析构函数(函数名之前加一个取反符号~): 当对象的生命周期结束时,会自动执行析构函数。
class A//基类A
{
public:
virtual int fun(int i = 1 )
{
return i + 1;
}
virtual~A(){}//基类的虚函数,~"析构函数
};
class B :public A{//派生类B继承自基类A
public:
virtual int fun(int i = 10){//派生类的虚函数
return i ;
}
};
int main()
{
A* p = new B;//定义了一个类型为A类的指针p,其内容为派生类B,拥有A的所有属性
cout << p->fun() << endl;//打印的是派生类的虚函数,派生类B隐藏了与其同名的基类A中的函数,但基类A的析构函数会在A结束后边自动执行,使得i=1
delete p;
while (1);
return 0;
}
输出:1
简答题:分别给出bool,int,float,指针变量 与“零值”比较的 if 语句(假设变量名为var)
- bool型变量:
if(!var)
- int型变量:
if(var==0)
- float型变量:
</font color=red>注意:不可将float变量直接用==
或!=
与数字进行比较,应设法转换成>=
或<=
的形式, 如果写成if (x == 0.0),则不得分
const float EPSINON = 0.00001;
if ((var >= - EPSINON) && (var <= EPSINON)
- 指针变量:
if(var==NULL)
注意:
C++中NULL
为整数0,nullptr
为空指针常量;
C中NULL
为(void*)0。
常见的linux系统目录结构
-
查看系统目录结构:
ls /
-
目录的一些解释:
/bin
:bin是Binary的缩写, 这个目录存放着最经常使用的命令。
/dev
:dev是Device(设备)的缩写, 该目录下存放的是Linux的外部设备,在Linux中访问设备的方式和访问文件的方式是相同的。
/etc
:这个目录用来存放所有的系统管理所需要的配置文件和子目录。
/lib
:这个目录里存放着系统最基本的动态连接共享库,其作用类似于Windows里的DLL文件。几乎所有的应用程序都需要用到这些共享库。 -
例题:
在linux操作系统中把外部设备当做文件统一管理,外部设备通常放在那个目录下?
答:/dev目录文件下
有关测试的知识
例题:
- 导致软件缺陷最大的原因是: 规格说明书
(因为需求没搞清楚就开始设计问题肯定很多)- 下面哪些属于动态分析(BC)
A.代码覆盖率
B.模块功能检查
C.系统压力测试
D.程序数据流分析
-
静态分析:代码运行之前,通过阅读评审文档、阅读代码等方式测试软件。
主要包括:桌面检查与代码会审、代码走查、技术评审、子模块接口调用图、静态结构分析、数据流分析图、软件质量度量法; -
动态分析:代码运行之后,分析结果与预期的差异,对模块功能检查和系统压力测试,分析运行效率和健壮- 性。
主要包括黑盒测试(又称功能测试)、白盒测试(又称结构测试)、灰盒测试(介于黑白之间的测试方法)
白盒法(白盒测试的方法:语句、条件、判定、判定\条件、条件组合、路径)
黑盒法(等值划分,边界分析,因果法,决策表,错误推测)
灰盒法(介于白黑盒法之间)) -
黑盒测试方法:就是根据软件的规格说明对软件进行测试,这类测试不考虑软件内部运作原理,因此软件对用户来说就像一个黑盒子。就是通过各种输入和输出结果观察软件是否存在缺陷,而不关心程序具体是如何实现的。主要方法有:
黑盒测试往往会造成测试用例之间可能存在严重的冗余和未测试的功能漏洞。 -
α测试和β测试:
阿尔法测试时把用户请到开发场所来测试,一般由终极用户或其他职员来完成,试图发现并修改错误;
贝塔测试是软件的多个用户在一个或者多个实际使用环境场所下进行的测试。
阿尔法测试优先于贝塔测试。
关于计算机网络相关
HTTP协议复习
HTTP是超文本传输协议(Hyper Text Transfer Protocol),主要用于从万维网(WWW)服务器传输超文本到本地浏览器的传送协议。
HTTP是基于TCP/IP协议的关于数据如何在万维网中通信的协议。
- HTTP/0.9
命令GET /index.html
表示:TCP连接建立后,客户端向服务器请求网页index.html,这个时候协议规定服务器只能回应HTML格式的字符串,不能回应别的格式。 - HTTP/1.0
这个时候任何格式的内容都可以发送。文字、图片、视频、二进制文件等都可以。
还引入了POST和HEAD命令。
- 请求格式如:
第一行是请求命令,必须在尾部添加协议版本。后面就是多行头信息,描述客户端的情况。
GET / HTTP/1.0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5)
Accept: /
- 回应格式如:
回应的格式是“头信息+一个空行+数据”,第一行是协议版本+状态码+状态描述。
HTTP/1.0 200 OK
Content-Type: text/plain
Content-Length: 137582
Expires: Thu, 05 Dec 1997 16:00:00 GMT
Last-Modified: Wed, 5 August 1996 15:55:28 GMT
Server: Apache 0.84
.
< html>
< body>Hello World< /body>
< /html>
-
CMD模拟HTTP请求
Telnet
命令是进行远程登录的标准协议和主要方式它为用户提供了在本地计算机上完成远程主机工作的能力。可以用telnet命令来测试端口号是否正常打开还是关闭状态。 -
HTTP/1.0版的缺点是,每个TCP链接只能发送一个请求。 发送数据完毕,连接就关闭,若还要请求其他资源,就必须再新建一个链接。
TCP链接的新建成本很高,因为需要客户端和服务器三次握手,并且开始时发送速率较慢,以你这个版本性能较差。
- HTTP/1.1
HTTP1.1 新增了六种请求方法:OPTIONS、PUT、PATCH、DELETE、TRACE 和 CONNECT 方法。
客户端请求头信息新增了HOST字段,用来指定服务器的域名。
这个版本引入了持久连接,即TCP链接默认不关闭,可以被多个请求复用。
还引入了管道机制(pipelining),即在同一个TCP链接里面,客户端可以同时发送多个请求。进一步改进了HTTP协议的效率。
TCP如何保证可靠性?
答:TCP协议保证数据传输可靠性的方式主要有:
校验和
序列号
确认应答
超时重传
连接管理
流量控制
拥塞控制
简答题:
1. C++中一个空类的大小为多少?为什么?
来源
答:C++中一个空类的大小为1;
因为类的实例化就是在内存中分配一块地址,那空类同样也可以被实例化,每个实例在内存中都有独一无二的地址,为了达到这一目的,编译器往往会给一个空类隐含的加一个字节,这样空类在实例化后在内存得到了独一无二的地址。
所以以下代码中的a,b大小是1;
而类c是由类a派生而来的,它里面有一个纯虚函数,由于有虚函数的原因,有了一个指向虚函数的指针,在32位的系统分配给指针的大小为4个字节,所以最后得到c类的大小为4。
类d的大小是8,这是由于类似的struct对齐原则。比如对于class x{int t1; char t2;};
,int 占4字节,char占一字节,需要补齐3字节.
#include<iostream.h>
class a {};
class b{};
class c:public a{
virtual void fun()=0;
};
class d:public b,public c{};
int main()
{
cout<<"sizeof(a)"<<sizeof(a)<<endl;
cout<<"sizeof(b)"<<sizeof(b)<<endl;
cout<<"sizeof(c)"<<sizeof(c)<<endl;
cout<<"sizeof(d)"<<sizeof(d)<<endl;
return 0;}
程序执行的输出结果为:
sizeof(a) =1
sizeof(b)=1
sizeof©=4
sizeof(d)=8
- 【重要】总结规律:
1.类的大小为类的非静态成员数据的类型大小之和,也就是说静态成员数据不作考虑。
2.普通成员函数与sizeof无关。
3.虚函数由于要维护在虚函数表,所以要占据一个指针大小,也就是4字节。
4.类的总大小也遵守类似class字节对齐的,调整规则。
2. const与#define比较,谁更有优势?
答:const更有优势;
原因:
(1)const常量有数据类型,而#define定义的常量没有数据类型。因此const常量可以进行类型检查,而后者只是进行字符替换;
(2)const支持一些编译器的断点调试,而#define不支持
(3)const可节省空间,避免不必要的内存分配,提高效率。
编程题
1. 设计一个日期类Date,包括年、月、日等私有数据成员。要求实现日期的基本运算,如某日期加上天数、某日期减去天数、两日期相差的天数等
- 题目描述:
题目描述:
设计一个日期类Date,包括年、月、日等私有数据成员。要求实现日期的基本运算,如某日期加上天数、某日期减去天数、两日期相差的天数等。只有一个文本框,不能使用外部IDE。
要求:
为Date类定义如下运算符重载函数:
Date operator+(int days):返回某日期加上天数得到的日期
Date operator-(int days):返回某日期减去天数得到的日期
int operator-(Date& b):返回两日期相差的天数
定义“<<”和“>>”运算符重载函数,实现日期的输入输出。**
2. 继承与派生练习:定义一个基类Shape,在次基础上派生出Rectangle和Circle。二者都有GetArea()函数计算对象的面积
- 题目描述:
定义一个基类Shape,在次基础上派生出Rectangle和Circle。二者都有GetArea()函数计算对象的面积
- 分析:
咋说呢,第一次遇到让写一个类的编程题,还挺迷的。
关于vlrtual~
的具体解释还见这里 - 代码:
#include<iostream>
#include<string>
using namespace std;
class Shape
{
public:
Shape() {} //构造函数(函数名必须和类名一样,目的是为函数参数设置初值)
virtual ~Shape(){} //虚方法的析构函数【简称虚析构】(调用的时候编译器会看调用的究竟是谁的实例化对象,这样就实现了多态的效果)
virtual float getArea() const {return 0;} //虚函数(使得允许在派生类中定义与基类同名的函数,多态性)
};
//长方形
class Rectangle: public Shape
{
public:
Rectangle(float Length, float Width): length(Length), width(Width){}//构造函数
//得到长方形的长、宽或面积
float getArea() const { return length*width; }
float getLength() const { return length; }
float getWidth() const { return width; }
//设置长方形的长宽
void setLength(float Length) { length = Length; }
void setWidth(float Width) { width = Width; }
private://定义成员变量
float length;
float width;
};
//圆形
class Circle: public Shape
{
public:
Circle(float Radius):radius(Radius){}//构造函数
//得到圆形的面积与半径
float getArea() const { return radius*radius*3.14; }
float getRadius() const { return radius; }
//设置圆的半径
void setRadius(float Radius) { radius = Radius; }
private:
float radius;
};
//练习1:使用Squre派生一个正方形Sqare
class Sqare: public Shape
{
public:
Sqare(float Side): side(Side){}//构造函数
//得到正方形的边长与面积
float getSide() const { return side; }
float getArea() const { return side*side; }
//设置正方形的边长
void setSide(float Side) {side = Side; }
private:
float side;
};
//练习2:使用Rectangle派生一个正方形Sqare
class Sqare1: public Rectangle
{
public:
Sqare1(float Side):Rectangle(Side,Side){}//构造函数,继承自基类函数Rectangle
//得到边长与面积
float getSide() const{ return getWidth(); }
float getArea() const{ return Rectangle::getArea();}
//获取正方形的长与宽,直接用Rectangle中已有的函数
void setSide(float Side)
{
setLength(Side);
setWidth(Side);
}
};
int main()
{
Shape *p1, *p2, *q, *l;
p1 = new Sqare(2); //像默认的这些参数值直接就传到了构造函数里,用来初始化对象中的数据成员
cout<<"正方形1的面积是:"<<p1->getArea()<<endl;
p2 = new Rectangle(10,10);
cout<<"正方形2的面积是:"<<p2->getArea()<<endl;
q = new Circle(3);
cout<<"圆的面积是:"<<q->getArea()<<endl;
l = new Rectangle(4,5);
cout<<"长方形的面积是:"<<l->getArea()<<endl;
return 0;
}
3. 设计一个单例模式:定义一个类让其只能实例化一个对象
- 分析:
只允许被实例化一次的叫做单例模式,是程序设计模式里面的。
定义一个单例类,使用类的私有静态指针变量指向类的唯一实例,并用一个公有的静态方法获取该实例。 - 代码:
class CSingleton
{
private:
CSingleton() //构造函数是私有的
{
}
static CSingleton *m_pInstance;
public:
static CSingleton * GetInstance()
{
if(m_pInstance == NULL) //判断是否第一次调用
{
m_pInstance = new CSingleton();
return m_pInstance;
}
else
return NULL;
}
};
4. 找两个链表的共同节点
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
{
struct ListNode *pa=headA,*pb=headB;
int len1=0,len2=0,dist=0;
while(pa!=NULL){
len1++;
pa=pa->next;
}
while(pb!=NULL){
len2++;
pb=pb->next;
}
struct ListNode *longList,*shortList;
if(len1>len2){
longList=headA,shortList=headB;
dist=len1-len2;
}else{
longList=headB,shortList=headA;
dist=len2-len1;
}
while(dist--) longList=longList->next;
while(longList!=NULL){
if(longList==shortList) return longList;
longList=longList->next;
shortList=shortList->next;
}
return NULL;
}