5.11 笔记-鸟语花香-搜狐博客



内存拷贝


内存是进程范围 or  线程范围: 

CPU调度时,针对进程 or  线程: 

函数调用堆栈,针对进程 or  线程: 



sizeof(short) 2

sizeof(long) 4

sizeof(unsigned int) 4

虚基类的特点:

       虚基类构造函数的参数必须由{zx1}派生出来的类负责初始化(即使不是直接继承);

       虚基类的构造函数先于非虚基类的构造函数执行




   %x, %X          输出无符号十六进制整数 (不输出前缀Ox)


什么是服务器?以及服务器有那些分类

服务器指一个管理资源并为用户提供服务的计算机软件,通常分为文件服务器、数据库服务器和应用程序服务器。运行以上软件的计算机或计算机系统也被称为服务器。相对于普通PC来说,服务器在稳定性、安全性、性能等方面都要求更高,因此CPU、芯片组、内存、磁盘系统、网络等硬件和普通PC有所不


char s1[] = "aaaaaaaaaaaaaaa"; 

char *s2 = "bbbbbbbbbbbbbbbbb"; 

aaaaaaaaaaa是在运行时刻赋值的; 

而bbbbbbbbbbb是在编译时就确定的;


  int a = 0; 全局初始化区 

  char *p1; 全局未初始化区 

  main() 

  { 

  int b; 栈 

  char s[] = "abc"; 栈 

  char *p2; 栈 

  char *p3 = "123456"; 123456\0在常量区,p3在栈上。 

  static int c =0; 全局(静态)初始化区 

  p1 = (char *)malloc(10); 

  p2 = (char *)malloc(20); 

  } 

  分配得来得10和20字节的区域就在堆区。 

  strcpy(p1, "123456"); 123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方


在类的内部,只有用了friend 才可以声明两个参数比如

friend Base operator +(const Base &b1, const Base &b2);

如果在类内部这样Base operator +(const Base &b1, const Base &b2);那就是错误的,



char * strstr1 ( const char * str1, const char * str2 )

{

char *cp = (char *) str1;//类型转换


AT&T

美国电话电报公司



论述含参数的宏与函数的优缺点

1.函数调用时,先求出实参表达式的值,然后带入形参。而使用带参的宏只是进行简单的字符替换。

2.函数调用是在程序运行时处理的,分配临时的内存单元;而宏展开则是在编译时进行的,在展开时并不分配内存单元,不进行值的传递处理,也没有“返回值”的概念。

3.对函数中的实参和形参都要定义类型,二者的类型要求一致,如不一致,应进行类型转换;而宏不存在类型问题,宏名无类型,它的参数也无类型,只是一个符号代表,展开时带入指定的字符即可。宏定义时,字符串可以是任何类型的数据。

4.调用函数只可得到一个返回值,而用宏可以设法得到几个结果。

5.使用宏次数多时,宏展开后源程序长,因为每展开一次都使程序增长,而函数调用不使源程序变长。

6.宏替换不占运行时间。而函数调用则占运行时间(分配单元、保留现场、值传递、返回)。

一般来说,用宏来代表简短的表达式比较合适。


设计函数 int atoi(char *s)


1.obj& fun() {obj o;return o;} //返回栈内存 error

2. obj* fun() {obj o;return &o;} //返回栈内存 error

3. obj fun() {obj o;return o;} //无问题


编译一个c/c++程序可以分为以下几个阶段

precompile (处理宏等等)

compile (正式编译)

link (链接



通常,我们声明一个类的实例,如果该实例在stack中分配,当实例对象离开它的作用域的时候系统会自动析构该实例。如果该实例在heap中分配,常见的做法是delete该实例的指针(或者指针数组)。

那么究竟什么时候需要用户显示的调用类的析构函数?C++中提供了这样的一种机制,允许事先分配一块大的内存,然后在这块内存中再实例化对象(注意这时候对象内存分配是在这块大内存中,不在向系统申请),当结束中,必须显示调用对象的析构函数,确保对象的成员中分配的空间都被释放



当用类似指针的指针指向对象,要注意对象的显式析构,(其实对象的构造也是显式的初始化)。第二是使用placement new的时候要显式的析构对象。



void   fun(int   i)   {   

  static   int   value=i++;   

  cout<<value;   

  }   

  static   int   value=i++;//这一句是静态对象的初始化,只在程序{dy}运行到这句的时候首次初始化,以后就不初始化了。 




抽象类与接口紧密相关,它们不能实例化,并且常常部分实现或根本不实现。抽象类和接口之间的一个主要差别是:类可以实现无限个接口,但仅能从一个抽象(或任何其他类型)类继承。从抽象类派生的类仍可实现接口。可以在创建组件时使用抽象类,因为它们使您得以在某些方法中指定不变级功能,但直到需要该类的特定实现之后才实现其他方法。抽象类也制定版本,因为如果在派生类中需要附加功能,则可以将其添加到基类而不中断代码。


在实现抽象类时,必须实现该类中的每一个抽象方法,而每个已实现的方法必须和抽象类中指定的方法一样,接收相同数目和类型的参数,具有同样的返回值。 

抽象类不能被实例化,也就是不能用new关键字去产生对象

   抽象方法只需声明,而不需实现

   抽象类的子类必须覆盖所有的抽象方法后才能被实例化,否则这个子类还是个抽象类.



构造函数中抛出异常时概括性总结

  (1) C++中通知对象构造失败的{wy}方法那就是在构造函数中抛出异常;

  (2) 构造函数中抛出异常将导致对象的析构函数不被执行;

  (3) 当对象发生部分构造时,已经构造完毕的子对象将会逆序地被析构


全局变量和静态变量,试说明两者有何异同:

全局变量具有全局作用域 静态变量具有文件作用域  


_ e x i t立即进入内核,e x i t则先执行一些xx处理然后哦进入内核


int f(int &i)不能传进去一个const的参数



简单的说,由于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 


C++构造函数为什么不能是虚函数?


首先要说的是,执行和继承是两码事。继承是指子类是否具有和父类一样的类成员而不用去重新再把这些成员定义或实现一遍,所以继承的目的就是重用。执行是指在类的内部或外部来使用这些成员。

执行构造函数是指在使用某个类的时候,需要创建该类的对象并为这个对象的所有成员分配内存的过程,如果该类继承了某个父类的话,那首先就要为父类的成员分配内存,当然就会先执行父类的构造函数了。另外,当子类构造时,碰到有override被重写的成员时,则这个曾经在父类构造时被分配的内存地址会在子类构造时被新的地址覆盖掉



一个函数不能同时为虚函数和构造函数

虚函数意味在运行期确定函数的调用地址,内联函数如同宏的用法一样,相当于在编译期把调用内联的地方加上了函数实现的代码。前者是动态的,后者是静态的。

另外,即使编译器通过了编译,那么函数也不可能是内联的 



子类构造函数做2件事

1)调用父类构造函数    //输出“父类构造函数。”

2)初始化子类成员变量  //输出“子类构造函数。” 


文件系统是指操作系统中与管理文件有关的软件和数据,linux的文件系统和windows中的文件系统有很大的区别


当表达式中存在有符号类型和无符号类型的时所有的操作数都自动转换为无符号类型




非C++内建型别 A 和 B,在哪几种情况下B能隐式转化为A?

答:

a. class B : public A { ……} // B公有继承自A,可以是间接继承的

b. class B { operator A( ); } // B实现了隐式转化为A的转化

c. class A { A( const B& ); } // A实现了non-explicit的参数为B(可以有其他带默认值的参数)构造函数

d. A& operator= ( const A& ); // 赋值操作,虽不是xx的隐式类型转换,但也可以勉强算一个


1、进程是一个独立的可调度的活动

2、进程是一个抽象实体,当它执行某个任务时将要分配和释放资源

3、进程是可以并行执行的计算部分


线程是指进程内的一个执行单元,也是进程内的可调度实体. 

与进程的区别: 

(1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位 

(2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行 

(3)拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源. 

(4)系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。


pthread_attr_getdetachstate(pthread_attr_t *attr, int detachstate)

pthread_attr_getstacksize(pthread_attr_t *attr, int detachstate)



gets and fgets the most different is ,gets don't save new '\n' to buffer

ssize_t read(int, void*, size_t)


fread(void *buffer, int size, int count, FILE *stream)


静态数组和动态数组


set tabstop=4

set softtabstop=4

set shiftwidth=4

set nu

set cident




就操作系统的功能来说,MS-DOS是单任务的操作系统,一旦用户运行了一个MS-

DOS的应用程序,它就独占了系统的资源,用户不可能再同时运行其他应用程序。而Linux是 

多任务的操作系统,用户可以同时运行多个应用程序。 


1 行代码大概(平均)是 30 字节,64k 的源代码是 2184

行,如果代码风格好一点,再多一些空行的话,差不多也

就是 3000 行上下。 



(1)  getc的参数不应当是具有副作用的表达式。

(2) 因为f g e t c一定是个函数,所以可以得到其地址。这就允许将 f g e t c的地址作为一个参数

传送给另一个函数。

(3) 调用f g e t c所需时间很可能长于调用g e t c ,因为调用函数通常所需的时间长于调用宏。检

验一下< s t d i o . h >头文件的大多数实现,从中可见g e t c是一个宏,其编码具有较高的工作效率



由于malloc和free是库函数而不是运算符,不在编译器控制权限之内,不能把执行构造函数和析构函数的任务强加于malloc和free

int 变量在 16 位系统下是 2 个字节,在 32 位下是 4 个字节;而 float 变量在 16 位系统下是 4 个字节,在32 位下也是 4 个字节


void *malloc(int)

void free(void*)


运算符 new 使用起来要比函数 malloc 简单得多,例如: 

int  *p1 = (int *)malloc(sizeof(int) * length); 

int  *p2 = new int[length]; 

这是因为 new 内置了 sizeof、类型转换和类型安全检查功能


(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无 virtual

关键字,基类的函数将被隐藏(注意别与重载混淆) 。 

(2) 如果派生类的函数与基类的函数同名, 并且参数也相同, 但是基类函数没有 virtual

关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)



参数缺省值只能出现在函数的声明中,而不能出现在定义体中。 

例如: 

  void Foo(int x=0, int y=0);  // 正确,缺省值出现在函数的声明中 

 

  void Foo(int x=0, int y=0)   // 错误,缺省值出现在函数的定义体中 

 { 

… 

 } 

为什么会这样?我想是有两个原因:一是函数的实现(定义)本来就与参数是否有

缺省值无关,所以没有必要让缺省值出现在函数的定义体中。二是参数的缺省值可能会

改动,显然修改函数的声明比修改函数的定义要方便。 



要注意,使用参数的缺省值并没有赋予函数新的功能,仅仅是使书写变得简洁一些。

它可能会提高函数的易用性,但是也可能会降低函数的可理解性。所以我们只能适当地

使用参数的缺省值,要防止使用不当产生负面效果



  如果运算符被重载为全局函数,那么只有一个参数的运算符叫做一元运算符,有两

个参数的运算符叫做二元运算符。 

  如果运算符被重载为类的成员函数,那么一元运算符没有参数,二元运算符只有一

个右侧参数,因为对象自己成了左侧参数。 


赋值构造函数和普通构造函数的区别是赋值构造函数在进入函数体后不于指针进行比较,因为引用不村存在NULL



.c                 c语言源代码

.C .cc             c++语言源代码

.i                 预处理后的c源代码

.ii                预处理后的c++源代码

.S .s              汇编语言代码

.o                  编译后的目标代码

.a .so               编译后的库代码



which   查看可执行档案的位置 

whereis 查看档案的位置 

locate  配合数据库查看档案位置 

find    实际搜寻硬盘去查询文件名称




程序是静态的,它是一些保存在磁盘上的指令的有序集合,没有任何执行的概念,而进程是一个动态概念,它是程序执行的过程,包括动态创建、调度和消亡的整个过程,它是程序执行和资源分配的最小单位,


wait函数是用于使父进程(也就是调用wait的进程)阻塞,知道一个子进程结束或者该进程接到一个指令的信号为止,如果该父进程没有子进程或者其他子进程已经结束,则wait就会立即返回

waitpid的作用和wait一样,但是她并不是一定要等待{dy}个终止的子进程,它还有若干选项,如可以提供一个非阻塞版本的wait功能,也能只是作业控制,实际上wait函数只是waitpid的一个特例,在linux内部时直接调用的就是waitpid函数



常见的内存分配错误以及对策如下:

1、内存分配未成功却使用了它

2、内存虽然分配成功但是尚未初始化就引用它

3、分配成功并且已经初始化但是操作越界

4、忘了释放内存,造成内存泄露

5、释放了内存却继续使用它

(1)程序中的对象调用关系过于复杂,实在难以搞清楚某个对象究竟是否已经释放了

内存,此时应该重新设计数据结构,从根本上解决对象管理的混乱局面。 

(2)函数的 return 语句写错了,注意不要返回指向“栈内存”的“指针”或者“引用” ,

因为该内存在函数体结束时被自动销毁。 

(3)使用 free 或 delete 释放了内存后,没有将指针设置为 NULL。导致产生“野指针” 。





char *strcpy(char *dest, char *source)

{

if (dest == NULL && source == NULL)

return NULL;

if (dest == source )

return dest

char *tempptr = dest;

while (*(dest++) = *(source++) != '\0')

;

tempptr = '\0';

return tempptr;

}



递归的可读性比较高


c = ((a+b)+abs(a-b))/2;用来得出a,b两个数中{zd0}的那个



scanf和printf及其系列还可以做些改进。尤其是,他们不是类型安全的,而且没有扩展性。因为类型安全和扩展性是C++的基石。


30. 比较C++中的4种类型转换方式?

请参考:http://blog.csdn.net/wfwd/archive/2006/05/30/763785.aspx,重点是static_cast, dynamic_cast和reinterpret_cast的区别和应用


int pthread_create(pthread_t *tid, const pthread_arrt_t *attr, void*(*fun)(void), void *arg);

int ptherad_join(pthread_ttid, void **status)线程阻塞函数

int pthread_t pthead_self(void);

int pthread_detach(pthread_t tid);


进程控制块包含了进程的描述信息,控制信息以及资源信息,它是一个进程的静态描述


由于线程共享进程的资源和地址空间,因此在对这些资源进行操作的时候,必须考虑线程间资源访问的{wy}性问题,这里主要介绍POSIX中线程同步的方法,主要有互斥锁和信号量


互斥锁可以分为快速互斥锁、递归互斥锁、检错互斥锁




void GetMemory(char **p,int num) 

*p=(char *)malloc(num); 


int main() 

char *str=NULL; 


GetMemory(&str,100); 


strcpy(str,"hello"); 


free(str); 


if(str!=NULL) 

strcpy(str,"world"); 


printf("\n str is %s",str); 

getchar(); 


输出str is world。 

free 只是释放的str指向的内存空间,它本身的值还是存在的. 

所以free之后,有一个好的习惯就是将str=NULL. 

此时str指向空间的内存已被回收,如果输出语句之前还存在分配空间的操作的话,这段存储空间是可能被重新分配给其他变量的, 

尽管这段程序确实是存在大大的问题(上面各位已经说得很清楚了),但是通常会打印出world来。 

这是因为,进程中的内存管理一般不是由操作系统完成的,而是由库函数自己完成的。 

当你malloc一块内存的时候,管理库向操作系统申请一块空间(可能会比你申请的大一些),然后在这块空间中记录一些管理信息(一般是在你申请的内存前面一点),并将可用内存的地址返回。但是释放内存的时候,管理库通常都不会将内存还给操作系统,因此你是可以继续访问这块地址的,只不过。。。。。。。。楼上都说过了,{zh0}别这么干


FILE *file = fopen("c:\ABC\Poo.txt", "w+");


#define PATH "C:\ABC"


FILE *file = fopen(PATH"Poo.txt");


sizeof()和初不初始化,没有关系; 

strlen()和初始化有关。 

char aa[10];

  printf("%d", strlen(aa));

  printf("\n%d", sizeof(aa));



如果有人说const是常量的话我们可以断定他是一个业余者,以前Dan Saks已经在他的文章里xx概括了const的用法,即使你没有读过只要你能说出const以为着只读就可以尽管这不是xx的答案,但是我接收它是一个正确的答案


对于f g e t s,必须指定缓存的长度n。此函数一直读到下一个新行符为止,但是不超过 n-1

个字符,读入的字符被送入缓存。该缓存以 n u l l字符结尾。如若该行,包括{zh1}一个新行符的

字符数超过n-1,则只返回一个不完整的行,而且缓存总是以 n u l l字符结尾。对f g e t s的下一次

调用会继续读该行。

g e t s是一个不推荐使用的函数。问题是调用者在使用 g e t s时不能指定缓存的长度。这样就

可能造成缓存越界(如若该行长于缓存长度) ,写到缓存之后的存储空间中,从而产生不可预

料的后果。


郑重声明:资讯 【5.11 笔记-鸟语花香-搜狐博客】由 发布,版权归原作者及其所在单位,其原创性以及文中陈述文字和内容未经(企业库qiyeku.com)证实,请读者仅作参考,并请自行核实相关内容。若本文有侵犯到您的版权, 请你提供相关证明及申请并与我们联系(qiyeku # qq.com)或【在线投诉】,我们审核后将会尽快处理。
—— 相关资讯 ——