`

《程序员宝典》读书笔记

阅读更多

1.i+++j  从左向右结合

2.unsigned int类型的数据和int类型的数据运算,自动转化为unsigned int。
  在进行整数提升时,char、signed char、unsigned char、short int 都会自动转化为int。

3.在C++程序中,调用被C编译器编译的函数,为什么加extend "C"

  C++支持函数重载,C不支持函数重载。函数在C++编译后在库中的名字和C语言的不同。假设某个函数的原型为
  void foo(int x,int y) ,被C编译器编译后在库中的名字为_foo,而C++中编译器会产生如_foo_int_int之类的名字。
  C++提供了C连接交换指定符号extend "C" 解决名字匹配问题。

4.头文件中indef/define/endif的作用:防止头文件被重复引用

5.#include<filename.h>和#include "filename.h"的区别
#include<filename.h>系统检索头文件时 会先从系统标准库路径里开始找filename.h ,再找其他地方。用于系统文件较快。
#include"filename.h"系统检索头文件时先从程序所处目录亦即用户工作路径开始查找。用于自定义文件较快。

6.如何判断一段程序是C编译的还是C++编译的?
编译器类型,就判断_cplusplus或_STDC_宏
简单的说,由于C语言是没有重载函数的概念的,所以C编译器编译的程序里,所有函数只有函数名对应的入口。而由于C++语言有重载函数的概念,如果只有函数名对应入口,则会出线混淆。所以C++编译器编译的程序,应该是函数名+参数类型列表对应到入口。 
  注意,因为main函数是整个程序的入口,所以main是不能重载的,所以,如果一个程序只有main函数,是无法确认是C还是C++编译器编译的。 
  可以通过nm来查看函数名入口。 
  如一个函数 
  int   foo(int   i,float   j) 
  C编译的程序通过nm查看 
  f                   0x567xxxxxx     (地址) 
  C++编译程序,通过nm 
  f(int,float)             0x567xxxxxx

7.main函数执行完毕后,是否可能会在执行一段代码?如果你需要加入一段在main退出后执行的代码,可以使用atexit()函数,注册一个函数。

8.用预处理命令#define 定义一年中有多少秒
  #define MIUNTES_PER_YEAR=(365*24*60*60)UL  无符号长整型

9.写一个宏,用输出两个参数中较小的一个   #define MIN(A,B) ((A<=B)?A :B)

10.在C中const用途 : 可以定义const常量,限定一个变量不允许被改变。使用const在一定程度上可以提高程序的健壮性;修饰函数的参数、返回值甚至是函数的定义体

11.const和#define有何不同:
   都可以定义常量,但是前者优点更多:const常量有数据类型,而#define无数据类型,编译器可以对前者进行安全监察,对后者只是进行替换,没有类型安全检查,而且字符替换中可能出现意想不到错误;有些调试工具可以对前者进行调试,但不能对宏常量进行调试

12.sizeof为计算字节数。
字符串指针大小为4;字符串数组后面有一位隐含的“\0”;为了方便对结构体内元素的访问和管理,当结构体内元素的长度小于处理器的位数时,便以结构体内最长的数据元素为对其单位,
亦即结构体长度一定是最长数据元素的整数倍;如果结构体内元素存在长度大于处理器位数,则以处理器的位数为对齐单位。

数据对齐:数据所在的内存地址必须是该数据长度的整数倍。

对于一个类,即使为空,其字节数目仍为1;多重继承空类的大小还为1   指针的字节数目均为4;

13.sizeof和strlen深入理解:
sizeof是求的所建立的对象的最大字节大小;sizeof是运算符,而strlen是函数;sizeof可以用类型做参数,而strlen只能用Char*作参数,且需以“\0”结尾。strlen在运行时才计算出来,
用来计算字符串的长度非类型所占内存的大小。sizeof后边跟类型需加括号;

sizeof的适用场合:1. sizeof 一个主要用途是与 存储分配 和 I/O系统 那样的例程进行通信 2. 用 sizeof 来查看某种类型的对象在内存中所占的单元字节,

3. 动态内存分配对象时,可以让系统知道要分配多少内存。

4. 便于一些类型的扩充。在 Windows 中有许多结构类型就有一个专用的字段用来存放该类型的字节大小。

5. 由于操作数的字节数在实现时可能出现变化,建议在涉及操作数字节大小时使用 sizeof 代替常量计算。

6. 如果操作数是函数中的数组形参或函数类型的形参,sizeof 给出其指针的大小。


14.内联函数和宏的区别:
内联函数和普通函数 相比可以加快程序运行的速度,因为不需要中断调用,在编译的时候内联函数可以直接被镶嵌到目标代码中,而宏只是简单的替换。内联函数要进行参数类型检查,宏不做检查。


内联函数使用情况:一个函数被不断重复调用;函数只有简单几行,且函数不包括for  while switch等语句。
一般而言,写小程序不会用内联函数,但要完成一个工程项目,当一个简单函数多次调用时,可以写成内联函数。

宏在C中很重要,但C++只用的少;宏的规则之一是:绝不应该去使用它,除非不得不。

宏不是函数,只是在编译前将程序中有关字符串替换成宏。   内联函数是函数,但不单独产生代码,而是将有关代码嵌入到调用处。


15.指针和引用的区别:
1.从现象上看:指针在运行时可以改变其所指向的值,而引用一旦和某个对象绑定后就不再改变
2.从内存分配上看:程序为指针变量分配内存区域,而引用不分配内存区域
3.从编译上看:程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变量名及变量所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值。符号表生成后就不会再改,因此指针可以改变指向的对象(指针变量中的值可以改),而引用对象不能改。
4.非空区别:任何情况下引用都不能为空,一个引用必修总指向某些对象。
5.合法性区别:引用无需检测合法性;但指针总被测试,防止为空
6.可修改区别:指针可以被重新赋新值指向另一个不同的对象;而引用在初始化时被指定对象并不能修改。


16.this指针是在实例化一个对象后产生的,并指向本身。可以在成员函数里明确声明
类中this指针的特点:
(1)this指针只能在成员函数中使用,全局函数,静态函数中均不能使用。成员函数默认的第一个参数是T* const this
(2)this指针在成员函数开始前构造,在结束后清除。这个生命周期和任何一个函数的参数是一样的。
(3)this指针因编译器的不同而放在不同的位置。栈,寄存器,全局变量都可能。
(4)大多数编译器通过ecx寄存器传递指针。一般来说,不同的编译器都会遵从统一的传参规则,否则不同编译器产生的obj就无法匹配了。
     在调用call之前,编译器会把对象的地址放入ecx,this通过函数参数的首参数来传递。this指针在调用前生成。类在实例化时,只分配类中的变量空间
     不为函数分配空间。
(5)在C++中类和结构体只有一个区别:类的成员默认是private,结构体的默认是public
(6)this指针指在成员函数中定义,获得一个对象后,不能通过对象使用this指针。因此无法知道一个对象的this指针地址。在成员函数中可以。
(7)普通函数(成员函数,静态函数)不会创建函数表来保存函数指针。只有虚函数才会被放到函数表中。但即便是虚函数,如果编译器知道调用的是哪个函数,
    编译器不会通过函数表中指针来调用,而是直接调用该函数。
(8)不允许给指针分配地址 如 int* ptr;ptr=(int *)OX800


17.写出函数指针、函数返回指针、const指针、指向const的指针、指向const 的const指针
 void (*f)()、void* f()、const int*、 int* const、const int* const

18.迷途指针也叫悬浮指针或失控指针,是当对一个指针进行delete后,释放它指向的内存,并没有把它设置为空时产生。

19.C++有malloc/free,为什么还要new/delete?
   前者是标准库函数,后者是运算符。都用于动态申请内存和释放内存。
   对于非内部数据类型而言,光用前者无法满足动态对象的要求。对象在创建的同时自动执行构造函数,在消亡前自动执行析构函数。
  由于前者是库函数,不在编译器控制权限之内,不能把执行构造函数和析构函数的任务强加给二者。因此需要后者。

20.指针和句柄的区别和联系?
   句柄是一个32为的整数,实际上是Windows在内存中维护的一个对象(窗口等)内存物理地址列表的整数索引。因为Windows的内存管理经常会将当前空闲对象的内存释放掉,当需要时访问再重新提交到物理内存,所以对象的物理地址是变化的,不允许程序直接通过物理地址来访问对象。程序将想访问的对象的句柄传递给系统,系统根据句柄检索自己维护的对象列表就能知道程序想访问的对象及其物理地址了。
   句柄是一种指向指针的指针。我们知道,所谓指针是一种内存地址。应用程序启动后,组成这个程序的各对象是驻留在内存的。如果简单的理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址访问对象。但是,如果您真的这样认为,那么您就大错特错了。我们知道,Windows是一个以虚拟内存为基础的操作系统。在这种系统环境下,Windows内存管理器经常在内存中来回移动对象,一次来满足各种应用程序的内存需要。对象被移动意味着它的地址变化了。如果地址总是如此变化,我们该到哪里去找该对象呢?为了解决这个问题,Windows操作系统为各应用程序腾出一些内存地址,用来专门登记各应用对象在内存中的地址变化,而这个地址(存储单元的位置)本身是不变的。Win内存管理器移动对象在内存中的位置后,把对象新的地址告知这个句柄地址来保存。这样我们只需记住这个句柄地址就可以间接地知道对象具体在内存中的哪个位置。这个地址是在对象装载时由系统分配的,当系统卸载时又释放给系统。句柄地址(稳定)->记载着对象在内存中的地址->对象在内存中的地址(不稳定)->实际对象。但是,必须注意的是,程序每次重新启动,系统不能保证分配给这个程序的句柄还是原来的那个句柄,而且绝大多数情况下的确不一样。假如我们把进入电影院看电影看成是一个应用程序的启动运行,那么系统给应用程序分配的句柄总是不一样,这和每次电影院售给我们的门票总是不同的座位是一样的道理。

       HDC是设备描述表句柄。

       CDC是设备描述表类。

       用GetSafeHwnd和FromHandle可以互相转换。

       句柄和指针其实是两个截然不同的概念。Windows系统用句柄标记系统资源,用句柄隐藏系统的信息。你只要知道有这个东西,然后去调用就行了,它是个32bit的uint。指针则标记某个物理内存地址,是不同的概念


21.递归96、98页

------------------------------------------------------------

对等实体再一次交互作用中传递的信息单位是协议控制单元;分为控制信息和用户信息。
网络层的服务访问节点称为网络地址,包括网络号和主机地址。

交换和路由的区别?VLAN的特点:

路由和交换机是我们在网络上见到最多的两个硬件。路由是网际层硬件设备,主要任务是对IP包的处理并用IP地址进行路由选路,而交换机是链路层硬件设备,它主要处理帧,通过帧的物理地址来交换信息的。并选择把信息发给那个网络。其实从概念上来讲这很好区别的一个是通过IP选路,一个是通过物理地址来选路的,人们通常用HUB(集线器)来和交换机比较,而交换机和HUB的最大不同就是能隔离冲突域,这个过程必然要对物理地址进行选路。

交换是指转发和过滤侦,是交换机的工作,它在二层,而路由是指网络线路当中非直连的链路,它是路由器的工作,在三层。交换和路由的区别很多,首先,交换是不需要IP的,而路由需要,因为IP就是三层的协议,二层需要的是MAC地址;再有,二层的技术和三层不一样,二层可以做VLAN、端口捆绑等等,三层可以做NAT、ACL、QOS等。
    VLAN是虚拟局域网的英文缩写,它是一个纯二层的技术,它的特点有三:控制广播、安全、灵活性和可扩展性。


一个IP数据包到达一个目的地前,可能称为碎片但不会重组。TCP/IP协议里,堵塞网络可能出现丢包。

文件传输基于TCP协议。C类网址254个主机。以太网转换控制包基于目的IP地址。

TCP服务器在数据发出前奔溃,TCP栈会返回SYN。

Win2000系统中配置IP命令:ipconfig;测试本机是否安装TCP/IP协议命令:ping 127.0.0.1;列出本机当前的连接命令:netstat -a

什么是SNMP协议?它有什么特点?
简单网络管理协议(SNMP:Simple Network Management Protocol)是由互联网工程任务组(IETF:Internet Engineering Task Force )定义的一套网络管理协议。该协议基于简单网关监视协议(SGMP:Simple Gateway Monitor Protocol)。利用SNMP,一个管理工作站可以远程管理所有支持这种协议的网络设备,包括监视网络状态、修改网络设备配置、接收网络事件警告等。虽然SNMP开始是面向基于IP的网络管理,但作为一个工业标准也被成功用于电话网络管理。

特点:易于实现;开放免费;资料详实;可用于控制各种设备。

 

SNMP协议需要专门的连接吗?无

存储过程和函数的区别是什么:存储过程是用户定义的一系列SQL语句的集合,设计特定的表,用户可以调用存储过程,函数是数据库已经定义的方法,接收参数并返回某类型的值,不涉及特定的表。

游标的作用:用于定位结果集的行。
如何知道游标到了最后:通过判断全局变量@@FETCH_STATUS可以判断是否到了最后,通常此变量不等于0表示出错或到了最后

触发器分事前触发和事后触发,这两者触发的区别是:事前触发器运行于触发事件发生之前,而事后触发器运行于触发事件发生之后。通常事前触发器可以获取事件之前和新的字段值。

语句级触发和行级触发有何区别:语句级触发器可以在语句执行前或后执行,而行级触发在触发器所影响的每一行触发一次。

SQL注入攻击:攻击者把SQl命令插入到web表单的输入或页面请求的查询字符串中,欺骗服务器执行SQL命令。

P286开始的SQL题目,宜看看
------------------------------------------------------------
1.进程和线程的区别:
进程是程序的一次执行,线程可以理解为进程中的执行的一个程序片段。在多任务环境下,二者的区别更大:
进程间是独立的,这表现在内存空间、上下文环境上;线程运行在进程空间之中。
一般而言,进程无法突破进程的边界存取其他进程内的存储空间;线程由于处于进程空间之中,统一进程内
的线程共享同一内存空间
统一进程内的两端代码不能同时执行;
线程属于进程,当进程退出时,该进程所产生的线程也会强制退出并清除。
线程占用的资源少于进程,都可以有优先级。
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.

一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行

2.进程间的通信如何实现?
最常用的进程通信方式是信号,信号量、消息队列、共享内存。
信号和信号量机制不同,虽然都能实现同步和互斥。前者使用信号处理器实现,后者是P、V操作实现。
消息队列是高级的通讯方式。可以呗多个进程共享,一个进程的消息过多也可以放在多个消息队列。

3.在网络编程设计并发服务器,使用多线程和多进程的区别:
多进程时每个进程都有自己的地址空间,线程则共享地址空间。
速度:线程产生的速度快,线程间的通信快,切换快,因为处于同一地址空间;
资源利用率:线程的资源利用率好,因为处于同一地址空间;
同步问题:线程使用公共变量/内存时需要同步机制,因为处于同一地址空间;

4.互斥器mutex是进程间的互斥;而临界区是线程的互斥。

5.进程进入等待状态的方式:CPU调度优先级更高的线程,原线程进入等待;阻塞的线程获得资源或者信号,进入等待;时间片轮转,时间片到了,进入等待。

6.垃圾回收的优点和原理:
使java程序员在编写程序的时候不用考虑内存管理的问题。有了垃圾回收机制,java对象不再有作用域的概念,只有对象的引用才有作用域的概念。
垃圾回收机制可有效的防止内存泄露,有效的使用可供使用的内存。
垃圾回收器通常作为一个单独的低级别的线程运行。在不可预知的情况下对内存堆中的已经死亡的或者长时间没有使用的对象进行清除和回收。
程序员不能实时调用垃圾回收器进程内存回收。回收机制有分代复制垃圾回收、标记垃圾回收、增量垃圾回收。


引:主流语言或环境的内存分配方式:静态分配(静态变量和全局变量)、自动分配(栈中局部变量)、动态分配

7.CPU缓存和操作系统的缓存分别是?
在OS中是快表:在OS中,为了提高系统的存取速度,在地址映射机制中增加一个小容量的联想寄存器,即快表,用来存放当前访问最频繁的少数活动页面的页号。
当用户需要存取数据时,根据数据所在的逻辑页号在快表中找到对应的内存块号,在联系页内地址,形成物理地址。
如果快表中没有相应的逻辑页号,地址映射则通过内存的页表进行,得到空闲块号,将该快放入快表的空闲块,若干快表中没有空闲块,则用淘汰算法淘汰一行
再填入新的页号和块号。

高速缓冲器Cache在CPU中应用,是位于CPU和运算器之间的临时存储器。容量比内存小胆存取速度更快。在Cache中的数据是内存中的一部分,但这一小部分是
CPU在段时间内将访问到的。当CPU调用大量数据时,就可以避开内存直接从Cache中获取,从而加快读取速度,

8.DOS和Win NT权限区别:
DOS是单用户单任务的OS,当打开一台装有DOS系统的计算机时,就有了这个OS的管理员权限。但不支持权限的配置。
NT中用户被分成很多组,组间有不同的权限。一个组的用户和用户间也可以有不同的权限。常见的用户组是:管理员组、高级用户组、普通用户组、来宾组、所有用户组。


------------------------------------------------------------
1.正数转化为字符串:整数一次除10  各个为+'0' 再逆序 或C++中itoa函数
字符串化为正数:减去'0',乘10累加

2.串拷贝(strcpy)和内存拷贝(memcpy)的不同:
strcpy函数只能拷贝字符串。将源字符串中的每个字符拷贝到目标字符串,当遇到null或\0结尾时,删去该字符并结束拷贝。
memcpy函数可以拷贝任意类型的数据,因为并不是所有数据都是以null结尾,所以要为memcpy拷贝指定字符数。
拷贝字符串时通常用前者,而拷贝其他类型通常用后者。

3字符数组并不要求最后一个字符是\0,但字符数组初始化要求最后一个字符是\0,C[5]={'c','h','i','n','a'}定义是错误的


4.char类型的赋值范围是0-255  若char a=256实际a=0

5.如何证明一个表是循环链表:可以设置两个不长不等的游标,如一个是1一个是2,两个游标同时出发 若能再次相遇则证明的
循环链表。

6.全局变量放在数据段(data segment),数据段数据静态分配;.未初始化的全局变量存放在bss段,BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。

指针放在堆栈,指向空间位置的数据段;

C语言有全局变量、本地变量、静态变量、寄存器变量。全局变量和静态变量的分布是连续的,本地变量放在堆栈中,

7.堆栈的区别:
栈的空间有OS自动分配和释放,堆上的空间手动分配和释放,
栈的空间有限,堆是很大的自由存储区

8.直接插入排序最好,快速排序最快。规模小小时,直接插入最好。基本有序时,直接插入 冒泡 快排最好。
较大时,归并 堆排序最好。

9.Map和HashMap的区别:
Map中数据存储方式是HashTable,Map和HashMap的主要区别是接口和类的区别,Map是接口,HashMap是实现类
HashMap是HashTable的改进型主要以key value来存取对象。


------------------------------------------------------------

1.十进制=八进制/10*8+八进制%10

2.C++中四种运算符的转化:数制转化、用于执行向下转换和在继承之间的转换、去掉const、用于执行并不安全的implementation_dependent转换

3.unsigned int 中-1为65535.

虚函数可以呗子类的同名虚函数覆盖  C++中组织一个类被实例化:抽象类或者构造函数为private

面向对象的基本概念是:对象、类、继承

C++空类中默认的成员函数:默认构造函数、析构函数、拷贝构造函数、赋值函数

结构体可以有构造函数和析构函数,可以有继承。静态成员变量要有初值。

C++中不允许main函数返回void

类中常量需将设置为static或者在构造函数的初始化列表中初始化。

4.析构函数可以是内联函数,可以是virtual的。

构造函数不可是virtual,因为虚函数是一种虚调用的方法。虚调用是一种可以在只有部分信息的情况下工作的机制,允许我们只调用一个只知道接口
而不知道其准确对象类型的函数。但是如果要创造一个对象,必须要知道对象的类型,因此构造函数不能为虚函数。


5.不能每个函数都为虚函数:虚函数是有代价的,每个虚函数的对象都要维护一个V表,因此使用虚函数的时候会带来一定的开销。如果仅是一个很小的类,
且不想派生其他的类,则根本无必要使用虚函数。

6.多态:简单地说就是一个接口多个方法。在程序的运行过程中才决定调用的函数。多态性在C++中是通过虚函数来实现的。
多态性允许将父对象设置为和它的一个或多个子对象相等的技术,赋值后,父对象就可以根据当前赋值给它的子对象的特性以不同的运行方式

虚函数就是允许被其子类重新定义的成员函数。子类重新定义父类虚函数的方式叫做覆盖或重写。override

重载是多个同名函数同时存在,只是参数的个数或类型不同。重载和多态无关。与面向对象无关。overload

封装可以隐藏实现细节,使得代码模块化;继承可以拓展已存在的代码块,二者的目的都是代码重用;
多态是为了接口重用。接口是公司最有价值的资源

------------------------------------------------------------

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics