1 int (*a[10]) (int)
注意指针数组和数组指针的区别:
int(*a[10])(int):a是这样一个数组,它有十个元素,每个元素都是一个函数指针,所指向的函数是带一个int参数返回值也是int。
int(*a)[10](int):a是一个函数指针,它所指向的函数是带一个int参数,返回值是一个有10个int元素的数组。
2 int * (* (*fp1) (int) ) [10]; 右左法则
阅读步骤:
1. 从变量名开始 -------------------------------------------- fp1
2. 往右看,什么也没有,碰到了),因此往左看,碰到一个* ------ 一个指针
3. 跳出括号,碰到了(int) ----------------------------------- 一个带一个int参数的函数
4. 向左看,发现一个* --------------------------------------- (函数)返回一个指针
5. 跳出括号,向右看,碰到[10] ------------------------------ 一个10元素的数组
6. 向左看,发现一个* --------------------------------------- 指针
7. 向左看,发现int ----------------------------------------- int类型
总结:fp1被声明成为一个函数的指针,该函数返回指向指针数组的指针。
http://bbs.csdn.net/topics/380142634引用链接内容
右左法则:首先从最里面的圆括号看起,然后往右看,再往左看。每当遇到圆括号时,就应该掉转阅读方向。一旦解析完圆括号里面所有的东西,就跳出圆括号。重复这个过程直到整个声明解析完毕。
笔者要对这个法则进行一个小小的修正,应该是从未定义的标识符开始阅读,而不是从括号读起,之所以是未定义的标识符,是因为一个声明里面可能有多个标识符,但未定义的标识符只会有一个。
现在通过一些例子来讨论右左法则的应用,先从最简单的开始,逐步加深:
int (*func)(int *p);
首先找到那个未定义的标识符,就是func,它的外面有一对圆括号,而且左边是一个*号,这说明func是一个指针,然后跳出这个圆括号,先看右边,也是一个圆括号,这说明(*func)是一个函数,而func是一个指向这类函数的指针,就是一个函数指针,这类函数具有int*类型的形参,返回值类型是int。
int (*func)(int *p, int (*f)(int*));
func被一对括号包含,且左边有一个*号,说明func是一个指针,跳出括号,右边也有个括号,那么func是一个指向函数的指针,这类函数具有int* 和int(*)(int*) 这样的形参,返回值为int类型。
再来看一看func的形参int(*f)(int*) ,类似前面的解释,f也是一个函数指针,指向的函数具有int*类型的形参,返回值为int。
int (*func[5])(int *p);
func右边是一个[]运算符,说明func是一个具有5个元素的数组,func的左边有一个*,说明func的元素是指针,要注意这里的*不是修饰func的,而是修饰func[5]的,原因是[]运算符优先级比*高,func先跟[]结合,因此*修饰的是func[5]。跳出这个括号,看右边,也是一对圆括号,说明func数组的元素是函数类型的指针,它所指向的函数具有int*类型的形参,返回值类型为int。
int (*(*func)[5])(int *p);
func被一个圆括号包含,左边又有一个*,那么func是一个指针,跳出括号,右边是一个[]运算符号,说明func是一个指向数组的指针,现在往左看,左边有一个*号,说明这个数组的元素是指针,再跳出括号,右边又有一个括号,说明这个数组的元素是指向函数的指针。总结一下,就是:func是一个指向数组的指针,这个数组的元素是函数指针,这些指针指向具有int*形参,返回值为int类型的函数。
int (*(*func)(int *p))[5];
func是一个函数指针,这类函数具有int*类型的形参,返回值是指向数组的指针,所指向的数组的元素是具有5个int元素的数组。
要注意有些复杂指针声明是非法的,例如:
int func(void) [5];
func是一个返回值为具有5个int元素的数组的函数。但C语言的函数返回值不能为数组,这是因为如果允许函数返回值为数组,那么接收这个数组的内容的东西,也必须是一个数组,但C语言的数组名是一个右值,它不能作为左值来接收另一个数组,因此函数返回值不能为数组。
int func[5](void);
func是一个具有5个元素的数组,这个数组的元素都是函数。这也是非法的,因为数组的元素除了类型必须一样外,每个元素所占用的内存空间也必须相同,显然函数是无法达到这个要求的,即使函数的类型一样,但函数所占用的空间通常是不相同的。
作为练习,下面列几个复杂指针声明给读者自己来解析,答案放在第十章里。
int (*(*func)[5][6])[7][8];
int (*(*(*func)(int *))[5])(int *);
int (*(*func[7][8][9])(int*))[5];
实际当中,需要声明一个复杂指针时,如果把整个声明写成上面所示的形式,对程序可读性是一大损害。应该用typedef来对声明逐层分解,增强可读性,例如对于声明:
int (*(*func)(int *p))[5];
可以这样分解:
typedef int (*PARA)[5];
typedef PARA (*func)(int *);
3 int a=100,c=1;int &b=a;b=c; a,b?
int &b=a,b是a的引用,a、b等价,同一玩意儿,故而,a=b=1 。引用一次初始化,不可更换引用的对象,可以改变所引用的对象的值。
4 float x;x与0比较
x-0<0.000001; 0-x<0.000001 。
5 union A{long l; char c[5];char s;} ;
struct B{int i;A a;doublie d;}b ;求sizeof(b)+sizeof(a)的值。
对齐 8+(4+8+8)=28
6 虚函数 ?作用 ?什么函数不可声明为虚函数?
定义:虚函数必须是基类的非静态成员函数,其访问权限可以是protected或public;没有继承特性的函数不能为虚函数
在基类的类定义中定义虚函数的一般形式:virtual 函数返回值类型 虚函数名(形参表) { 函数体 }
作用:
虚函数的作用是实现动态联编——多态,也就是在程序的运行阶段动态地选择合适的成员函数,在定义了虚函数后,可以在基类的派生类中对虚函数重新定义,在派生类中重新定义的函数应与虚函数具有相同的形参个数和形参类型,以实现统一的接口,不同定义过程。如果在派生类中没有对虚函数重新定义,则它继承其基类的虚函数。
当程序发现虚函数名前的关键字virtual后,会自动将其作为动态联编处理,即在程序运行时动态地选择合适的成员函数。
使用方法:
动态联编规定,只能通过指向基类的指针或基类对象的引用来调用虚函数;
其格式: 指向基类的指针变量名->虚函数名(实参表) 或 基类对象的引用名. 虚函数名(实参表)
其它说明:
虚函数是C++多态的一种表现:例如:子类继承了父类的一个函数(方法),而我们把父类的指针指向子类,则必须把父类的该函数(方法)设为virtual(虚函数)。
使用虚函数,我们可以灵活的进行动态绑定,当然是以一定的开销为代价。 如果父类的函数(方法)根本没有必要或者无法实现,完全要依赖子类去实现的话,可以把此函数(方法)设为virtual 函数名=0
我们把这样的函数(方法)称为纯虚函数。如果一个类包含了纯虚函数,称此类为抽象类 。
什么函数不可声明为虚函数?答案: static 友元 构造
一个类中将所有的成员函数都尽可能地设置为虚函数总是有益的。
设置虚函数须注意: http://blog.csdn.net/reille/article/details/6214165
1:只有类的成员函数才能说明为虚函数;
2:静态成员函数不能是虚函数; 只拷贝一份,所有代码共享;
3:内联函数不能为虚函数; 编译时进行代码替换,而虚函数是在运行时实现的;
4:构造函数不能是虚函数; 为了初始化对象变量的,只有在生成一个对象之后才能发挥多态作用,而虚函数是在运行时才起作用;
5:普通函数不能是虚函数;(非成员函数);
6:友元函数不能是虚函数;不是类的成员函数,不能被继承
7:析构函数可以是虚函数,而且通常声明为虚函数。
要想成为虚函数,必须能够被取到地址.内联函数不能被取到地址所以不能成为虚函数;inline virtual void f(),不能保证函数f()一定是内联的,只能保证f()是虚函数;
你不能够确定一个函数到底是不是inline的.inlien关键字只是对编译器的一个建议:"如果有可能,请把此函数搞成inline的"。
7 static 全局 局部 函数与普通函数区别
static全局变量与普通全局变量区别:static只初始化一次,防止在其他文件单元中被引用。
static局部变量与普通局部变量区别:static只被初始化一次,下一次依据上一次结果值。
static函数与普通函数区别:static函数在内存中只有一份,而普通函数在每个被调用中维持一份复制品。
8 存储过程? 作用 优点
事务:在数据库系统上执行并发操作时事务是做为最小的控制单元来使用的;;开始事物:BEGIN TRANSACTION;;提交事物:COMMIT TRANSACTION;;回滚事务:ROLLBACK TRANSACTION
①原子性(Atomicity):事务中的所有元素作为一个整体提交或回滚,是不可折分的,事务是一个完整的操作。
②一致性(Consistemcy):事物完成时,数据必须是一致的,也就是说,和事物开始之前,数据存储中的数据处于一致状态。保证数据的无损。
③隔离性(Isolation):对数据进行修改的多个事务是彼此隔离的。这表明事务必须是独立的,不应该以任何方式来影响其他事务。
④持久性(Durability):事务完成之后,它对于系统的影响是永久的,该修改即使出现系统故障也将一直保留,真实的修改了数据库
(2) 使用存储过程可以提高执行效率。当客户程序需要访问服务器上的数据时,一般要经过5个步骤:
● 查询语句被发送到服务器;
● 服务器编译T-SQL语句;
● 优化产生查询执行计划;
● 数据库引擎执行查询;
● 执行结果发回客户程序。
如果执行存储在客户端本地的T-SQL程序,那么每次执行该程序时,对于程序中的每一条语句都要经过以上5个步骤。而存储过程在创建时就被编译和优化,当存储过程第一次被执行时,SQL Server为其产生查询计划并将其保存在内存中,这样以后在调用该存储过程时就不必再进行编译,即以上5个步骤中的第2步和第3步就被省略了,这能大大改善系统的性能。
(3) 减少网络流量。一个需要数百行T-SQL代码的操作,如果将其创建成存储过程,那么使用一条调用存储过程的语句就可完成该操作。这样就可避免在网络上发送数百行代码,从而减少了网络负荷。
(4) 可作为安全机制使用。管理员可以不授予用户访问存储过程中涉及的表的权限,而只授予执行存储过程的权限。这样,既可以保证用户通过存储过程操纵数据库中的数据,又可以保证用户不能直接访问存储过程中涉及的表。用户通过存储过程来访问表,所能进行的操作是有限制的,从而保证了表中数据的安全性。
构建有参存储过程 CREATE PROCEDURE au_info
@lastname varchar(40),@firstname varchar(20)
AS
SELECT au_lname, au_fname, title, pub_name FROM authors a INNER JOIN titleauthor ta ON a.au_id = ta.au_id
WHERE au_fname = @firstname AND au_lname = @lastname
GO
执行 EXECUTE au_info @lastname = 'Dull', @firstname = 'Ann'
9 模态对话框 非模态对话框
10 编程 判断链表是否有环
11 编程 给定16位二进制数 eg:1101 0101 1011 0111
运算规则:1101+101+1011+111=2324输出
12 什么是COM线程模型
COM即为组件对象模型,他定义一种二进制标准,使得任何编程语言存取它所编写的模块
http://blog.csdn.net/jokes000/article/details/7070520
http://www.cnblogs.com/henryhu/archive/2010/02/20/1669939.html
http://hi.baidu.com/geogrex/item/a982ba0f76273cf7f45ba681
http://blog.csdn.net/lock0812/article/details/2644109
http://www.nowamagic.net/librarys/veda/detail/2245
http://blog.csdn.net/thefutureisour/article/details/8174313
http://blog.sina.com.cn/s/blog_725dd1010100tqwp.html