1. 全局变量如果加上static关键字,就相当于各自文件的本地全局变量。如果不加static,链接时会出错。
全局变量可以定义在可被多个.c文件包含的头文件中。
2. 下列for循环的循环体执行次数为:0
for(int i=10,j=1;i=j=0;i++,j--)
分析:i=j=0; 是一个赋值语句,位于for的判断位置,就只当成条件真假,C中0为假,非0为真,
所以i=j=0,结果就是i=0,为假,则循环不进入;
如果是 i=j=1,结果就是真,可以进入循环,并且无限。
3. 下列程序输出结果:
#include<iostream>
#include<string.h>
using namespace std;
int main() {
chara[10]={'1','2','3','4','5','6','7','8','9',0},*p;int i;
i=8;
p=a+i;
printf("%s\n",p-3);
}
分析:1)、p指向a[5]
2)、“%s”输出直到'\0'的字符串
3)、最后的0为数字而非字符‘0’,ASIIC码中0为空字符
所以输出的结果是6789而不是67890
4. 在《C++primer》说过如果子类没有显示地调用父类的构造方法,则默认地调用父类的不带参数的构造方法,这里父类定义了带参数的构造方法,则默认构造函数失效了,需要显式地调用父类的构造方法。
当基类构造函数需要外部传递参数才能进行初始化时,派生类必须显式定义构造函数,为基类传递参数;基类如果不需要传递或者可以不传递参数,派生类可以不用显式定义构造函数。
5.
#include<iostream>
#include<string.h>
usingnamespace std;
intmain() {
int a[3];
a[0]=0,a[1]=1,a[2]=2;
int *p,*q;
p=a;
q=&a[2];
cout<<p<<""<<q<<endl;
cout<<q-p<<endl;
}
分析:可以先想想指针指示数组时,移动的情况, 类比得到指针加减其实是加减的类型的字节的大小。
所以:指针 ptr 的类型是 int*, 它指向的类型是 int ,它被初始化为指向整形变量 a 。接下来的第 3 句中,指针 ptr 被加了 1 ,编译器是这样处理的:它把指针 ptr 的值加上了 sizeof(int) ,在 32 位程序中,是被加上了 4。
单独打印p和q都会显示地址,但是加减运算就会变成以指针类型(这里是整型)为基本单位的加减运算。1个整型就是1。
6.在基类和派生类中,派生类可以定义其基类中不具备的数据和操作。对两个有相同名字的数据成员进行访问时,如果没有作用域分隔符限定时,对此数据成员的访问将出现歧义。
7.有如下程序:
#include<iostream>
#include<string.h>
using namespace std;
class A{
public:
int _a;
A(){
_a=1;
}
void print() {
cout<<_a;
}
};
class B:public A {
public:
int _a;
B() {
_a=2;
}
};
int main() {
B b;
b.print();
cout<<b._a;
}
分析:因为在继承的时候,允许子类存在与父类同名的成员变量,但是子类屏蔽父类的同名成员变量,他们同时存在。 因为给孩子类中没有定义print函数,所以会按照就近原则去寻找父类中是否有print函数。恰好父类中有这个函数,于是调用父类的print函数b.print(),而这个函数会调用父类的a变量。
8.
#include<iostream>
#include<string.h>
using namespace std;
int main() {
int b;
char c[10];
scanf("%d%s",&b,c);//scanf("%d%s",&b,&c);都是一样的。
}
9.在64位系统下,根据如下程序,输出结果为:80 8
#include<iostream>
#include<string.h>
using namespace std;
int main() {
char *p[10];
char (*p1)[10];
cout<<sizeof(p)<<""<<sizeof(p1);
}
分析:重点理解p跟谁结合了,跟[]结合,则p就是一个数组;跟*结合,p就是一个指针;
首先[]()的优先级一样,均大于*
char *p[10],p与[]结合,所以p就是一个数组,数组的元素比较特殊,是指针,指针大小为8,所以是10*8=80;
char(*p1)[10],与*结合,所以是一个指针,大小为8
分析二:
char *p[10]是指针数组,数组里存放了10个指针,在64位系统下指针占8个字节,所以sizeof(p)=10*8=80.
char(*p1)[10]是数组指针,p1是一个指向存放10个char类型的数组的指针,所以sizeof(p1)=8.
10.JAVA没有指针的概念,被封装起来了,而C++有;
JAVA不支持类的多继承,但支持接口多继承;C++支持类的多继承;
C++支持操作符重载,JAVA不支持;
JAVA的内存管理比C++方便,而且错误处理也比较好;
C++的速度比JAVA快。
C++更适用于有运行效率要求的情况;JAVA适用于效率要求不高,但维护性要好的情况。
11.在linux+gcc下,关于以下代码正确:ABD
#include<iostream>
#include<string.h>
using namespace std;
std::string& test_str() {
std::stringstr="test";
return str;
}
int main() {
std::string&str_ref=test_str();
std::cout<<str_ref<<std::endl;
return 0;
}
A编译警告 B返回局部变量引用,运行时出现未知错误
C正常编译且运行 D把代码中的&号都去掉,程序正常运行
分析:引用返回的是局部变量本身,而不是复制一份再返回,所以结果难以预料;
其次返回局部自动变量是可以的,只要不是地址或引用就可以,否则需要将变量声明成static类型。
c++中string是一个类,去掉&后return时会调用复制构造函数,因此是可以得到所要的内容。
12.
#include<iostream>
#include<string.h>
using namespace std;
int main() {
inta[10]={0,1,2,3,4,5,6,7,8,9},*p=a;
cout<<*p<<endl;
cout<<p[6]<<""<<*(a+6)<<" "<<*(p+6)<<""<<p+6<<endl;
return 0;
}
分析:p[6]、*(a+6)、*(p+6)是一个意思; a+6与p+6是一个意思,都是取地址。
13. 使用char *p=new char [100]申请一段内存,然后使用delete p释放,会有声明问题?
不会有内存泄露,但不建议用。
分析:C++告诉我们在回收用 new 分配的单个对象的内存空间的时候用 delete,回收用new[]分配的一组对象的内存空间的时候用delete[]。
关于new[]和delete[],其中又分为两种情况:(1) 为基本数据类型分配和回收空间;(2) 为自定义类型分配和回收空间。
基本类型的对象没有析构函数,所以回收基本类型组成的数组空间用delete和delete[]都是应该可以的;但是对于类对象数组,只能用delete[]。
所以一个简单的使用原则就是:new 和delete、new[]和 delete[]对应使用。
14.面向对象的五大基本原则:
单一职责、开放封闭、里氏替换、依赖倒置、接口隔离
五个基本原则:
单一职责原则(Single-ResposibilityPrinciple):一个类,最好只做一件事,只有一个引起它的变化。单一职责原则可以看做是低耦合、高内聚在面向对象原则上的引申,将职责定义为引起变化的原因,以提高内聚性来减少引起变化的原因。
开放封闭原则(Open-Closed principle):软件实体应该是可扩展的,而不可修改的。也就是,对扩展开放,对修改封闭的。
Liskov替换原则(Liskov-Substituion Principle):子类必须能够替换其基类。这一思想体现为对继承机制的约束规范,只有子类能够替换基类时,才能保证系统在运行期内识别子类,这是保证继承复用的基础。
依赖倒置原则(Dependecy-InversionPrinciple):依赖于抽象。具体而言就是高层模块不依赖于底层模块,二者都同依赖于抽象;抽象不依赖于具体,具体依赖于抽象。
接口隔离原则(Interface-SegregationPrinciple):使用多个小的专门的接口,而不要使用一个大的总接口
15.
#include<iostream>
#include<string.h>
using namespace std;
struct st_t{
int status;
short *pdata;
char errstr[32];
};
int main() {
st_t st[16];
char *p=(char*)(st[2].errstr+32); //第3个的errstr字符串+32后是第4个结构体的首指针
cout<<sizeof(st_t)<<endl; //sizeof(st_t)是40
printf("%d",(p-(char*)(st))); //p减去第0个指针就求4-0中间有多少字节,就是40*3=120
16.
auto fn=[](unsigned char a) {
cout<<std::hex<<(int)a<<endl;
};
fn(-1);
分析:-1=1000 0001
存储的是补码形式
①反码是1111 1110【符号位不变,其他位取反】
②补码是1111 1111【反码加1】
然后std::hex以十六进制显示【1111 1111】
17.抽象类的指针可以指向不同的派生类。
用关键字virtual修饰的成员函数叫做虚函数,虚函数是为了实现多态而存在的,必须有函数体;
纯虚函数的声明,是在虚函数声明的结尾加0,没有函数体。在派生类中没有重新定义虚函数之前是不能调用的;
如果一个类中至少含有一个纯虚函数,此时称之为抽象类。所以抽象类一定有纯虚函数;
基类类型的指针可以指向任何基类对象或派生类对象;