#include<iostream>
using namespace std;
void main()
{
int c = 5;
if (c++ == 5)
{
printf("%d\n", c--);
printf("%d", c);
}
else
{
printf("%d",c++);
}
system("pause");
}答案:6,5
2、int x = 3, y = 4, z = 5, t = 2,n=5;
printf("%d\n", (t > 0) ? (!(x + y) + (z - 1 && y) + t) : n);
答案:3.
C语言中一些运算符之间优先级关系:
简单来说:!>算术运算符>关系运算符>&&>||>赋值运算符
详细的介绍:
1、最高级:出现同级别运算符时的结合方向是从左往右(下面级别没写结合顺序时,默认是从左往右)。
( )圆括号
[ ]下标运算符号
->指向结构体成员运算符
.结构体成员运算符
2、
第二级:这一级都是单目运算符号 !(逻辑非)、~(按位取反)、++(自增)、--(自减)、-(负号)、(类型)(类型转运算符)、*(指针)、&(取值)、sizeof(长度运算符号)。
,这一级的结合方向是从右向左。
比如出现*p++,这时*和++同级别,先算右边,再左边。
所以*p++等价于*(p++),而不是(*p)++。
3、第三级:+、-、*、/、%
这一级都是算术运算符,结合顺序和数学学习中一致的,先乘除取余数,后加减。
4、
第四级:<<、>>
这是左移、右移运算符,位运算时可能需要用到。
5、第五级:<、<=、>、>=、!=、==
这些运算符也称为关系运算符,其中<、<=、>、>=高于!=、==。
6、第六级:&(按位与)、^(按位异或)、|(按位或运算)
这三个符号也是位运算符号,其中内优先级,&>^>|。
7、第七级:&&、||
逻辑与&&优先级大于逻辑或||。
(表达式1&&表达式2)若表达式1不为1,逻辑将直接返回0,跳过表达式2,即使表达式2有重要的运算,也不执行。
(表达式1||表达式2)若表达式1为1,逻辑或将直接返回1,跳过表达式2,即使表达式2有重要的运算,也不执行。
8、
第八级:? :
也称为条件运算符号,是C语言中唯一的一个三目运算符,结合顺序是从右往左。
9、第九级:=、+=、-+、*=、/=、%=
这些运算符也叫做赋值运算符,除此之外>>=、<<=、&=、^=、|=这些赋值运算符内在这一级别内,结合顺序是从右往左。
a=3,b=4,c=5;
a+=b*=c;
结合顺序是从右到左:先计算b ,b=b*c=20;再计算a=a+b=23;
10.
最低级:,
逗号运算符也称为顺序求值运算符,在C语言中,运算级别最低。
逗号表达式=最后一个表达式
int a=1,b=2,c=3;
a=(a,c+=5);
printf("%d%d%d",a,b,c); 8,2,8
总的来说,初级运算符( )、[ ]、->、. 高于 单目运算符 高于 算数运算符(先乘除后加减) 高于 关系运算符 高于 逻辑运算符(不包括!) 高于 条件运算符 高于 赋值运算符 高于 逗号运算符。
位运算符的优先级比较分散。
除了赋值运算符、条件运算符、单目运算符三类的平级运算符之间的结合顺序是从右至左,其他都是从左至右。
3、若调用一个函数时,该函数没有return 语句,那么调用该函数后,将返回什么?
即使函数中没有return语句,若函数不声明为void型,调用函数的时候还是可以得到int型的返回值。但是一个不确定的值
4、派生类中构造函数、析构函数调用顺序
在建立对象时,先调用基类的构造函数,再调用派生类的构造函数;调用析构函数时,顺序恰恰相反。
#include <iostream> using namespace std; class Shape{ public: void Draw() {cout<<"Base::Draw()"<<endl;} void Erase() {cout<<"Base::Erase()"<<endl;} Shape() {Draw();} ~Shape() {Erase();} }; //------------------------------------------------- class Polygon:public Shape{ public: Polygon() {Draw();} void Draw() {cout<<"Polygon::Draw()"<<endl;} void Erase() {cout<<"Polygon Erase()"<<endl;} ~Polygon() {Erase();} }; //-------------------------------------------------- class Rectangle:public Polygon{ public: Rectangle() {Draw();} void Draw() {cout<<"Rectangle::Draw()"<<endl;} void Erase() {cout<<"Rectangle Erase()"<<endl;} ~Rectangle() {Erase();} }; //-------------------------------------------------- class Square:public Rectangle{ public: Square() {Draw();} void Draw() {cout<<"Square::Draw()"<<endl;} void Erase() {cout<<"Square Erase()"<<endl;} ~Square() {Erase();} }; //-------------------------------------------------- int main(){ Polygon c; Rectangle s; Square t; cout<<"------------------------------------------"<<endl; return 0; }
#include<stdio.h>
#include<iostream>
using namespace std;
class A
{
public:
A(int x)
{
cout << "A";
}
~A()
{
cout << "~A";
}
int a;
};
class B
{
public:
B(int y)
{
cout << "B";
y = b;
}
~B()
{
cout << "~B";
}
int b;
};
class C
{
public:
C()
{
cout << "C";
}
~C()
{
cout << "~C";
}
};
class D: public C
{
private:
B b;
A a;
int t;
public:
D(int i, int j, int k) :a(i), b(j), t(k)
{
cout << "D";
}
~D()
{
cout << "~D";
}
};
int main()
{
D d(1,2,3);
C *p = &d;
delete p;
p = NULL;
system("pause");
//return 0;
}
输出结果:CBAD~C ~D~A~B~C
构造函数的调用顺序:先是基类的,然后是自己成员的类构造函数,最后是自己的。(先父类,在客人,最后自己)
6、
#include<stdio.h>
#include<iostream>
using namespace std;
class A
{
public:
A(int x)
{
cout << "A";
a = x;
//cout << a << endl;
}
A()
{
A(0);
}
~A()
{
cout << "~A";
}
int a;
};
class B
{
public:
B(int y)
{
cout << "B";
y = b;
}
~B()
{
cout << "~B";
}
int b;
};
class C
{
public:
C(int aa=0)
{
cout << "C";
a = aa;
}
~C()
{
cout << "~C" << a << endl;;
}
int a;
};
class D: public C
{
private:
public:
D(int aa = 0, int bb = 0) :C(aa), b(bb)
{
cout << "D";
}
~D()
{
cout << "~D" << b << endl;
}
int b;
};
void test()
{
D X(5);
D Y(6, 7);
}
int main()
{
A obj1;
cout << obj1.a << endl;
A obj(19);
cout << obj.a << endl;
test();
system("pause");
return 0;
}
输出结果:A~A-858993460
A19 CDCD~D7~C6~D0~C5
当创建一个类A 的对象时,如果是无参的,则会输出不确定的值;如果是有参函数,变量的值取决于形参。
4、模板函数与函数模板、函数重载的关系
函数 模板的定义形式 template <typename T>
T 函数名(T 形参1,T形参2,.....){}
模板函数 是函数模板的一个特例化。模板函数是指,函数的名称相同,参数个数也相同,不同的仅仅是参数的类型。
根据 函数重载的定义,可以使用函数模板实现的,肯定能使用函数重载来实现,反之,则不成立。
模板函数和函数重载的还有一个区别就是,函数重载时,每个函数可以执行不同的动作;但是函数模板实例化后成模板函数了都必须执行相同的动作。
5、派生类中私有成员、保护成员、公有成员的性质
基类中公有(public)成员的访问权限:
如果是公有继承,那么可以访问的权限如下
1.基类中的函数和对象;2.派生类中的函数和对象;3.基类友元函数和派生类的友元函数;
如果是私有继承和保护继承:
1、.基类中的函数和对象;2.派生类中的函数(对象不可访问);3.基类友元函数和派生类的友元函数;
基类中私有(private)的访问权限:
1.基类中的函数;2.友元函数;
3.其它任何都不能访问,包括基类的对象。
基类中保护(protected) :
无论是什么方式继承:
1.基类中的函数;2.子类中的函数;3.友元函数;4.不能被基类的对象访问。
友元函数不能被继承;
6、类中构造函数、析构函数、友元函数的作用
构造函数主要用于解决对象初始化的问题,构造函数是一类特殊的函数,与其他的成员函数不同的是构造函数构造函数不需要用户来调用它,而是建立对象的时候自动的执行。
析构函数用于在对象撤销时,完成一些清理的工作,如释放内存。
可以实现类之间的数据共享时,减少系统开销,提高效率,即友元函数可以实现使其它类的成员函数直接可以访问该类的私有变量和保护变量,从而实现数据共享。
使用友元函数的缺点:友元函数破坏了封装机制,尽量不使用友元函数。
友元函数的参数:因为友元函数没有 this 指针,所以参数有三种情况:
1、要访问非static成员时,需要对象做参数;2、要访问static或者全局变量是,则不需要对象做参数。3、如果做参数的对象时全局对象,则不需要对象做参数;
友元函数的位置:因为友元函数是类外的函数,所以他的声明可以放在类的私有段或者公有段都可以。
友元函数的调用:可以直接调用,不需要指针或对象
友元函数有三类:普通函数做友元函数、类Y的所有函数都是类X的友元函数、类Y的一个函数是类X 的友元函数。
友元函数和类的成员 函数区别:
成员函数有this指针,而友元函数没有;友元函数是不能继承的。
以下两种情况常常使用:
1、运算符重载2.两个类之间实现数据共享。
8、const 在C++中作用。如果用const修饰函数的形参, const修饰内部变量、修饰指针、与修饰引用之间有什么区别?
(1)const 修饰变量,将变量设为常变量;
(2)const 修饰指针,当const在*的左边时,表示指针指向的内容是不可更改的;当 const在*的右边时,表示指针的指向不可更改。
(3)const修饰函数的参数。
1、如果参数作输出用,不论他是什么数据类型,也不论她是采用指针传递还是引用传递,都不能加const修饰,否则该参数将失去输出功能。
2、const修饰函数参数,是为了防止传入的参数代表的内容在函数内部不可更改。但是仅仅对指针和引用有用。对于内部数据类型的数值来说,没意义。因为如果是按值传递,传给参数的是仅仅是实参的副本,即使在函数内部更改了形参,也不会影响到实参。因此,一般不用const 来修饰内部数值。例如不要,将 void fun(int x) 写成void fun(const int x).或者写成void fun(const int x)。
同理也不要将 void fun(A a)写成 void fun (const A a).其中A是用户自定义的数据类型。对于费内部数据类型参数而言,像定义为void fun(A a)效率是非常低的。因为函数体内将产生A类型的临时对象用于赋值参数a,而临时对象得调用构造函数和析构函数,耗时。因此,一般可以定义为 void fun ( A &a),但是这样定义,也存在缺点,引用传递可以改变参数a,这是我们不期望要的。因此,函数最终定义为 void fun ( const A &a)。对于内部数据类型来说,没必要定义为引用,因为不存在构造函数可析构函数的过程。
因此,对于费内部数据类型的输入参数,应该将“”值传递“”的方式改为“const 引用传递”,目的是提高 效率。
对于内部数据类型来说,不要将“”值传递“”定义为“const 引用传递”,否则即达不到提高效率的目的,又降低了函数的可理解性。
const修饰指针时,代表在函数体内不能修改该指针所指的内容,起到保护的作用。例如在字符串赋值时,形参是定义为const char* str. const指针可以接收非const指针和const指针,但是非const 指针只能接受非从const指针。
3、const 修饰函数的返回值。一般在函数的前面加上const。也是用来修饰返回的引用和指针,保护指针指向的内容或者引用的内容不可变,也常用作运算符重载。
class C
{
public:
C()
{
i = 0;
cout << "C";
}
~C()
{
cout << "~C";
}
int &get()
{
return i;
}
int i;
};
int main()
{
C c;
cout << c.get() << endl;//输出0
c.get() = 4;
cout << c.get() << endl;//输出改为4.函数返回值也可以修改成员的值。所以为了安全起见,将返回值加上 const。是的函数返回值不可以做返回值。
system("pause");
//return 0
}
(4)在成员函数后加const ,表示不可以修改类的成员变量,也即类的成员变量不可以做左值。而且不能调用非const函数。因为非const函数可能修改数据或者成员。而const成员函数是不能修改的。
9、 static 的在C++的作用。
(1) static修饰局部变量,改变局部变量的生存周期和存储区。普通变量存放在栈区,当函数执行完后,就会被清空。但是静态变量存储在静态存储区,但函数执行完后也不会清空。下次再次执行时,还会保存上次的值。
(2)修饰全局边量和普通函数时,改变了全局变量和普通函数的作用域。在模块内的全局变量,只能被模块内函数来访问,不能被模块外的其它函数访问。函数也是,只能被该模板内其它函数调用,不鞥被其它模块的函数调用。
(3)tatic的第三个作用是默认初始化为0(static变量)其实全局变量也具备这一属性,因为全局变量也存储在静态数据区。在静态数据区,内存中所有的字节默认值都是0x00,某些时候这一特点可以减少程序员的工作量。比如初始化一个稀疏矩阵,我们可以一个一个地把所有元素都置0,然后把不是0的几个元素赋值。如果定义成静态的,就省去了一开始置0的操作。再比如要把一个字符数组当字符串来用,但又觉得每次在字符数组末尾加‘\0’;太麻烦。如果把字符串定义成静态的,就省去了这个麻烦,因为那里本来就是‘\0’。
(4) 在类中声明static变量或者函数时,初始化时使用作用域运算符来标明它所属类,因此,静态数据成员是类的成员,而不是对象的成员,这样就出现以下作用:
一:类的静态成员是属于整个类,不依赖某个对象,静态成员函数没有this 指针,只能访问静态成员和函数。
二:不能将静态成员函数定义为虚函数。因为静态函数是属于某个类的,在内存中只有一份。而虚函数是依赖于对象的,必须根据具体的对象来调用,有this指针。而静态函数是没有this指针的。
10、指针与引用的区别。
(1)定义一个指针也是变量,只不过指针存储的是变量的地址,指向内存块的地址;而引用是变量的别名,实质和变量是一个东西,占同一个内存单元。
(2)指针的值可以指向NULL,但是引用不可以,引用在定义时必须初始化绑定一个对象。
(3)指针的值在初始化后可以改变,但是引用不可以。
(4)sizeof(指针)的大小是指针本身的大小;sizeof(引用)的大小是变量的大小。
(5)指针自增加一和引用自增加一不一样;
(6)指针可以多级嵌套,但是引用不可以。
(7)有const指针,但是没有const引用。
11、数据库中索引的作用?什么是索引?索引就如同字典中目录,它是数据库中表中一或者多列的值进行排序的一种结构。
作用:(1)设计良好的索引可以减少磁盘的i/o操作,并且消耗的系统资源比较少,提高查询的性能(2)主要是加快检索数据的速度(3)通过建立索引,可以建立表与表之间的连接。(4)可以建立唯一索引,可以保证数据库每一行数据的唯一性。
缺点:(1)创建索引和维护索引需要耗费时间;(2)索引需要占用空间(3)当对表中数据进行增加。删除和修改时,索引需要动态的维护,这样降低了数据维护速度。
不应该创建索引情况:
(1)对于那些在查询中很少使用或者参考的列不应该创建索引(2)对于数据列比较少的列也不应该创建(3)当修改的性能远远大于检索的性能时,因为修改的性能和检索的性能是互相矛盾的。(4)对于那些定义为text.image等数据类型的列不应该增加索引,因为这些列的数据量要么特别大,要么取值少。
12、左联接与右联接的区别?
左联接是只影响右表,返回的是左表中所有的记录行和右表中匹配的行。右联接返回的右表中所有的记录和左表中匹配的行。
inner join 返回的左表中和右表中均满足的条件的记录行。
内连接:是保证两个表中所有行都要满足的联接条件,而外链接则不然。
外链接又包含左连接、右连接、全连接。
全连接:包含了左表与右表中所有不满足条件的行。
13、数据库联合查找?
14、什么是聚集索引和非聚集索引?
SQL SERVER 中提供了两种索引方式,即聚集索引和非聚集索引。聚集索引表示表中存储的数据按照索引的的顺序存储,即是物理存储。非聚集索引是索引和数据是分开的,索引带有指针指向数据存储的地方,强调的是逻辑存储分类。
区别:
(1)聚集索引:物理存储按照索引排序,好比字典中正文本身就是一个目录,当我们要查找一个认识的字时,就知道在那个大范围找。
非聚集索引:物理存储不按照索引排序,物理存储上是不连续的。
(2)聚集索引的查找效率较高,但是插入数据的效率比较慢(时间花费在物理排序上,先找到位置再插入)。
(3)每个表中只能有一个聚集索引,但是可以有多个非聚集索引。
14、vector和LIST之间的区别?
15、二叉树的建立、遍历、反转,平衡二叉树、红黑二叉树?
16、常见的排序算法
18、图的存储方式?
19、静态成员函数可以访问非静态的成员函数吗?
不可以。因为非静态成员函数是依赖于对象的,通过对象 才能访问,具有this指针。而静态函数是属于整个类的,不依赖与对象,而且没有this指针。
20、重载与重写的区别?
1、重载发生在同一个作用域中,也即同一个类中。
2、函数的名字相同,但是形参(是指形参个数和类型以及参数的顺序必须不同。
**重载函数的返回值类型可以相同也可以不同。不能仅仅依靠返回值类型不同,来判断是否是重载函数。因为仅仅是返回值类型不同,是不能构成函数重载的,会产生重定义的错误。
**但是有一个例外,使用const关键字是可以进行函数重载,使得成员函数变为const 函数。
如同一类中:
string greeting()
{
}和
string greeting () const
{
}
是可以构成函数重载的。调用机制是如果定义的对象时常对象,则调用的是const成员函数;如果定义的对象是非常对象,则调用的是非const的成员函数。
但是:
string greeting () const
{
}和
const string greeting () const
{
}
是不能构成函数重载的。仅仅是返回值类型不同而已。
** int f(int*){}
int f(int const*){} 这两个是可以构成函数重载的。
但是 int f(int*){}
int f(int *const){} 这两个是不可以构成函数重载的。也就是说不能基于指针本身是否是const来实现函数的重载。
(2)重写也叫覆盖。
子类重新定义父类中有相同名称和参数的虚函数。函数特征相同。但是具体实现不同,主要是在继承关系中出现的 。
(1)不同的范围(分别位于派生类与基类);
(2)函数名字相同; 参数相同;
(3)基类函数必须有virtual 关键字;
(3)隐藏(也叫重定义)
(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)有vitual时为覆盖。(重写后的方法有多态性,隐藏没有)
21、关系型数据库与非关系数据库的区别?
关系型数据库就是用一个二维关系模型来组织数据的。它是通过外建来建立表与表之间的联系。常见的关系型数据库有MYSQL/ORACAL/SQL SERVER 等。
非关系数据库是指数据以对象的形式来存储的,而对象之间的联系就是通过对象自身的属性。
22、什么是存储过程?有什么优点?
存储过程就是预编译好的sql语句。(1)存储过程就是一个预编译好的代码块,执行速度比较快。(2)可以保证数据的安全性和完整性。
23、什么是数据库事务?有哪些特性?
数据库事务就是指作为单个逻辑单元执行的一系列操作,要么全部执行要么全部不执行。
(1)原子性
是指事务所包含的操作要么全部执行,要么全部不执行。
(2)一致性
事务完成后,必须使数据保证之前的一致性。
(3)隔离性
是指多个用户并发访问数据库时,多个用户同时操作一张表时,数据库为每一个用户所开启的事务,都不能使其它事务来干扰。多用户并发访问数据库要互相隔离。
(4)持久性
是指一个事务一旦提交后,对数据的改变是持久性的。
24、数据库中的乐观锁与悲观锁?
数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性。
悲观所:假设冲突会发生,屏蔽一切可能会违反事务完整性的操作。
乐观锁:假设冲突不会发发生,只有在提交事务时才会访问是否有破坏事务的完整性。
25、truncate/delete/drop table 有什么区别
trancate table 删除内容,不删除定义,释放空间。
delete table 删除内容,不删除定义,不释放空间。
drop table 删除内容和定义,释放空间。