c 语言 底层 笔记

来源:互联网 发布:淘宝营销词有哪些 编辑:程序博客网 时间:2024/04/28 22:11

unix的口令加密所用的des算法和标准的des算法有什么不同的地方?一个可逆,一个不可逆,是重名了吧?

$

__builtin_expect__builtin_expect仅仅是告诉编译器优化,

¥¥

 同等充盈率条件下,b+树的分支就会多,所以相应的高度就会矮。这是优势。看了下在张铭老师对B树的讲解,讲了插入和删除操作也不麻烦。

¥¥

介绍内存池很好的文章。。http://www.blogbus.com/gcoder-logs/219127906.html

对比垃圾回收(GC)来看:具有GC的语言,可以这么理解,整个机器的内存,就是一个大的内存池。当内存吃紧时,GC会根据一定的原则,释放不再使用的内存。内存池是最简易的GC,需要手工调用函数才能“GC”,并且只能按照内存池为单位来“GC”。


以WEB服务器举例来说:解析http协议有大量的小块内存需求,更重要的是,内存的生命周期很明确。内存的生命周期是和请求绑定的,请求一结束,和该请求相关的内存就都可以释放了。如果内存使用没有界限鲜明的生命周期,那么使用内存池就比较困难,因为不知道什么时候释放内存(销毁内存池)。

static的作用就是隐藏。 

¥¥

为什么其他语言没有指针,也能完成c语言指针的功能呢。因为其他语言的可以用引用或者变量来代替指针的内容,具体操作内存的地址由语言本身实现。这样由语言本身操作会减少出错,但是效率上自然比不上c语言。从这里可以看出c的底层了吧。

¥innodb采用聚簇索引的好处是都是按顺序 存储在磁盘,减少了io次数。myisam不是聚簇索引,不一定按照顺序存储,增多io次数。

¥数据库系统是分页存储的。一般每页8k,可能多个行占用一页,也可能一行占用多页。

¥文件系统是数据库系统的底层,推测分析,数据库系统的索引也不可能是一个索引节点就正好占用一个磁盘块(文件系统索引节点确实占用一个磁盘块),数据库系统的索引利用文件系统做底层,存放到文件系统中。节点指针映射到磁盘的节点和偏移,可能节点之间在同一个磁盘块,也可能不在同一个磁盘块,这个应该是文件系统来负责映射和查找吧。

¥  文件系统的逻辑存储方式,采用的是和内存存储的逻辑分配方式一样的,分页或分段,避免碎片。

widows文件系统的物理存储方式是链接分配方式。而unix都是索引分配方式。

     数据库系统是一种格式化的文件系统。如果是单独的写一个文件这类简单的操作,操作系统采用分页或分段已经实现了,并提供给接口。但是对于数据库这类复杂的格式化的数据存储,数据库的存储引擎自己编程实现的这个逻辑。比如 innodb主键索引存储就不是普通写文件那么简单实现了,而是把结构化的一行数据带着生产的主键一块存到一个页里。多行记录存够一个页,再新启一个页。可以将行的物理存储方式当透明处理吗?貌似存储引擎得自己实现多个页的管理吧 

B树和操作系统的索引模模糊糊的是一个东西。字典的索引,是一个深度为1的B-树。mysql的优化的索引,如果按照树的定义,它也是深度为一的B树。mysql的索引的存储方式确实B+树,而且是深度为多个。表现形式深度为1,存储方式深度为多个。

¥)

流式文件:文件中的数据是没有结构的一串字符

¥)

c 的宏定义在预编译阶段就进行替换,不用像其他形式那样定义变量,这样节省变量的内存,同时又提升了速度。

¥)

extern一般用在头文件中。比如一个结构体的定义在头文件中,可以加extern,也可以不加。因为extern也可以用于定义。

static代表隐藏作用域,同时代表静态存储(ps,全局变量也必定是静态存储)。

¥)

c的结构体太灵活了,什么都能放,比其他语言的hash数组还方便。

(1)多线程的编写,监听一个线程,处理方法一个线程,通过一个main方法就可以生成这些操作。

(2)监听流程就想一条道路上的收费站,我每次accept就检查一辆车,用while循环挨个处理,如果请求数太大,道路堵塞。所以出现了,多个监听线程,linux出现了监听事件处理的方法,比如epoll,select等操作。

¥)linux和windows编译器的理解。

猜测windows的开发语言是用的是方言,不是标准的再就是操作系统的函数不一样。才会出现与*nus的移植问题。

mingw和gcc的关系,mingw起到一个标准语言和方言的翻译工作。(编译器只能针对特定语法进行翻译成机器码,所以windows的vc和linux的gcc不一样)

其实windows的语法跟gcc不一样是一种方言,用mingw就可以在windows写基于gcc的代码了,mingw会将gcc的标准语言翻译成windows方言。所以mingw生成windows格式的文件。

mingw是在cygwin基础上发展而来,对应其名称的由来。

可在windows 下 使用Linux 环境进行gcc编程,但是生成的是windows格式文件。

mingw就像VC一样是一个IDE(不是ide),
GCC就像MicroSoft Cl一样,是编译器,
Mingw调用GCC来编译代码.当然和你直接用GCC编译一个效果.
$
java引用和c指针的区别之一是引用不能自加  

2)strcpy的源码解释
认为引用可以替代指针,所谓的指针灵活体现在什么地方,指针灵活之处之一为指针可以进行自加,自减等,但是引用不可能实现。比如strcpy的c++语言实现用指针操作很简单。为什么没有给strDest进行内存空间的分配,使用sizeof呢?原因是在函数外部已经预先分配给大小为strSrc的内存空间,然后再调用这个函数的,这样不易出现内存泄露吧,调用完strcpy后,还需手动释放内存空间!因为库函数设计的原则是高效,所以很多操作需要用户自己搞定!受java程序的影响,开始以为是判断strDest和strSrc是否为空值,被分配好的指针地址绝不可能为空值啊。所以只能通过判断‘\0’字符
char * strcpy(char * strDest,const char * strSrc)
  {
  char * strDestCopy=strDest; //[3]
  if ((strDest==NULL)||(strSrc==NULL)) //[1]
  throw "Invalid argument(s)"; //[2]
  while ((*strDest++=*strSrc++)!='\0'); //[4]
  return strDestCopy;
  }

如果使用java的话,就不会使用指针操作了,需要用charat()让机器自己找到地址,然后通过地址加+1,再操作,c++的指针相当于取消了这一步,直接通过内存地址访问。
循环写成while (*strSrc!='\0') *strDest++=*strSrc++;,说明答题者对边界条件的检查不力。循环体结束后,strDest字符串的末尾没有正确地加上'\0'。
代码解释:(摘自百度知道)首先++(自增)的优先级高于*(间接访问),所以先*s++=*t++相当于*(s++)=*(t++),s++是将s指向下一个字符,但s++的值还是指向第一个字符,也就是说将t的第一个字符赋给s的第一个字符,同时两个指针同时后移,而表达式(*(s++)=*(t++))的值就是(*(t++))的值,也就是*s,也就是当前的字符,如果值为'\0'自然就结束了,因此while((*(s++)=*(t++))!='\0');第四种:'\0'的ASC马值为0,因此第3例可写为while((*(s++)=*(t++))!=0);而这正是第四例while(*(s++)=*(t++));

$
涉及到字符串的操作,比如实现strcpy()
int  fun(char *s,char *t)
{
{if(s==0||t==0)return 0;//或者说s=NULL,t==NULL;这样比较好,边界处理很重要啊
 while(*s&&*t&&*s==*t)s++,t++;//字符'\0'的ascII为0,所以可以这么写
 return *s-*t;
}
void main()
{
 char s[100],t[100];
 printf("输入字符串:");
 gets(s);
 printf("输入字符串:");
 gets(t);
 printf("%d\n",fun(s,t));
}

 return *s-*t;
}
void main()
{
 char s[100],t[100];
 printf("输入字符串:");
 gets(s);
 printf("输入字符串:");
 gets(t);
 printf("%d\n",fun2(s,t));
}

$
main()
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
}
输出:2,5

*(a+1)就是a[1],*(ptr-1)就是a[4],执行结果是2,5
&a+1不是首地址+1,系统会认为加一个a数组的偏移,是偏移了一个数组的大小(本例是5个int)
int *ptr=(int *)(&a+1);
则ptr实际是&(a[5]),也就是a+5

原因如下:

&a是数组指针,其类型为 int (*)[5];

而指针加1要根据指针类型加上一定的值,
不同类型的指针+1之后增加的大小不同
a是长度为5的int数组指针,所以要加 5*sizeof(int)
所以ptr实际是a[5]
但是prt与(&a+1)类型是不一样的(这点很重要)
所以prt-1只会减去sizeof(int*)

a,&a的地址是一样的,但意思不一样,a是数组首地址,也就是a[0]的地址,&a是对象(数组)首地址,a+1是数组下一元素的地址,即a[1],&a+1是下一个对象的地址,即a[5]

如何避免使用c++的拷贝构造函数

1、不采用值拷贝(尽量用引用拷贝)

2、禁用拷贝构造含数据,方法是将构造函数私有化

(1)delete p;分两步,一步是调用p所指向对象的析构函数,另一步是释放p所在地址所指向的内存空间

由此可以解释以下代码:

[cpp] view plaincopy
  1. class A   
  2. {   
  3. public:   
  4.   A() { p=this; }   
  5.   ~A() { if(p!=NULL) { delete p; p=NULL; } }  
  6.   A* p;   
  7. };  
  8.   
  9. 答:  
  10. 会引起无限递归 //为什么呢?请具体解释下  

(2)有几次都不能正确理解,其实应该是最大类型所占字节的整数倍。以前都认为是固定4字节的整数倍,完全理解错误了!
[cpp] view plaincopy
  1. class A  
  2.   {  
  3.       char a;  
  4.       int  b;  
  5.       double c;  
  6.   };  
  7.   cout<<"A :"<<sizeof(A)<<endl;//16???  
解释:因为double占8个字节,在分配空间时,找到有个double占8个字节,所以前两个类型占前8个字节的前5个字节。但是如果是没有double类型,那么分配8个字节,但是char a和int b不是挨在一块的。而前者是挨在一块的。。