php和c,c++的区别是什么?

发布网友 发布时间:2022-04-22 09:04

我来回答

1个回答

热心网友 时间:2023-09-10 00:18

一、编程语言

1.根据熟悉的语言,谈谈两种语言的区别?

主要浅谈下C/C++和PHP语言的区别:

1)PHP弱类型语言,一种脚本语言,对数据的类型不要求过多,较多的应用于Web应用开发,现在好多互联网开发公司的主流web后台开发语言,主要框架为mvc模型,如smarty,yaf,升级的PHP7速度较快,对服务器的压力要小很多,在新浪微博已经有应用,对比很明显。

2)C/C++开发语言,C语言更偏向硬件底层开发,C++语言是目前为止我认为语法内容最多的一种语言。C/C++在执行速度上要快很多,毕竟其他类型的语言大都是C开发的,更多应用于网络编程和嵌入式编程。

2.volatile是干啥用的,(必须将cpu的寄存器缓存机制回答得很透彻),使用实例有哪些?(重点)

1)访问寄存器比访问内存单元要快,编译器会优化减少内存的读取,可能会读脏数据。声明变量为volatile,编译器不再对访问该变量的代码优化,仍然从内存读取,使访问稳定。

总结:volatile关键词影响编译器编译的结果,用volatile声明的变量表示该变量随时可能发生变化,与该变量有关的运算,不再编译优化,以免出错。

2)使用实例如下(区分C程序员和嵌入式系统程序员的最基本的问题。):

并行设备的硬件寄存器(如:状态寄存器)
一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
多线程应用中被几个任务共享的变量
3)一个参数既可以是const还可以是volatile吗?解释为什么。

可以。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。
4)一个指针可以是volatile 吗?解释为什么。
可以。尽管这并不是很常见。一个例子当中断服务子程序修改一个指向一个buffer的指针时。

下面的函数有什么错误:
int square(volatile int *ptr) {
return *ptr * *ptr;
}
下面是答案:
这段代码有点*。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:
int square(volatile int *ptr){
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
由于*ptr的值可能被意想不到地改变,因此a和b可能是不同的。结果,这段代码可能并不是你所期望的平方值!正确的代码如下:
long square(volatile int *ptr){
int a;
a = *ptr;
return a * a;
}

更多linux内核视频教程文本资料免费获取后台私信【内核】。

3.static const等等的用法,(能说出越多越好)(重点)

² 首先说说const的用法(绝对不能说是常数)

1)在定义的时候必须进行初始化

2)指针可以是const 指针,也可以是指向const对象的指针

3)定义为const的形参,即在函数内部是不能被修改的

4)类的成员函数可以被声明为正常成员函数,不能修改类的成员变量

5)类的成员函数可以返回的是常对象,即被const声明的对象

6)类的成员变量是指成员变量不能在声明时初始化,必须在构造函数的列表里进行初始化

(注:千万不要说const是个常数,会被认为是外行人的!!!!哪怕说个只读也行)

下面的声明都是什么意思?
const int a; a是一个正常整型数
int const a; a是一个正常整型数
const int *a; a是一个指向常整型数的指针,整型数是不可修改的,但指针可以
int * const a; a为指向整型数的常指针,指针指向的整型数可以修改,但指针是不可修改的
int const * a const; a是一个指向常整型数的常指针,指针指向的整型数是不可修改的,同时指针也是不可修改的
通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现。

Const如何做到只读?

这些在编译期间完成,对于内置类型,如int, 编译器可能使用常数直接替换掉对此变量的引用。而对于结构体不一定。

² 再说说static的用法(三个明显的作用一定要答出来)

1)在函数体内,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
2)在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
3)在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被*在声明它的模块的本地范围内使用

4)类内的static成员变量属于整个类所拥有,不能在类内进行定义,只能在类的作用域内进行定义

5)类内的static成员函数属于整个类所拥有,不能包含this指针,只能调用static成员函数

static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?

static全局变量与普通的全局变量有什么区别:static全局变量只初始化一次,防止在其他文件单元中被引用;
static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值;
static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝

4.extern c 作用

告诉编译器该段代码以C语言进行编译。

5.指针和引用的区别

1)引用是直接访问,指针是间接访问。

2)引用是变量的别名,本身不单独分配自己的内存空间,而指针有自己的内存空间

3)引用绑定内存空间(必须赋初值),是一个变量别名不能更改绑定,可以改变对象的值。

总的来说:引用既具有指针的效率,又具有变量使用的方便性和直观性

6. 关于静态内存分配和动态内存分配的区别及过程

1) 静态内存分配是在编译时完成的,不占用CPU资源;动态分配内存运行时完成,分配与释放需要占用CPU资源;

2)静态内存分配是在栈上分配的,动态内存是堆上分配的;

3)动态内存分配需要指针或引用数据类型的支持,而静态内存分配不需要;

4)静态内存分配是按计划分配,在编译前确定内存块的大小,动态内存分配运行时按需分配。

5)静态分配内存是把内存的控制权交给了编译器,动态内存把内存的控制权交给了程序员;

6)静态分配内存的运行效率要比动态分配内存的效率要高,因为动态内存分配与释放需要额外的开销;动态内存管理水平严重依赖于程序员的水平,处理不当容易造成内存泄漏。

7. 头文件中的 ifndef/define/endif 干什么用

预处理,防止头文件被重复使用,包括pragma once都是这样的

8. 宏定义求两个元素的最小值

#define MIN(A,B) ((A) next;

}

else

{

return NULL;

}

}

Node* pFind = pHead;

while (pCurrent) {

pFind = pFind->next;

pCurrent = pCurrent->next;

}

return pFind;

}

2. 给定一个单向链表(长度未知),请遍历一次就找到中间的指针,假设该链表存储在只读存储器,不能被修改

设置两个指针,一个每次移动两个位置,一个每次移动一个位置,当第一个指针到达尾节点时,第二个指针就达到了中间节点的位置

处理链表问题时,”快行指针“是一种很常见的技巧,快行指针指的是同时用两个指针来迭代访问链表,只不过其中一个比另一个超前一些。快指针往往先行几步,或与慢指针相差固定的步数。

node *create() {

node *p1, *p2, *head;

int cycle = 1, x;

head = (node*)malloc(sizeof(node));

p1 = head;

while (cycle)

{

cout >x;

if (x != 0)

{

p2 = (node*)malloc(sizeof(node));

p2->data = x;

p1->next = p2;

p1 = p2;

}

else

{

cycle = 0;

}

}

head = head->next;

p1->next = NULL;

return head;

}

void findmid(node* head) {

node *p1, *p2, *mid;

p1 = head;

p2 = head;

while (p1->next->next != NULL)

{

p1 = p1->next->next;

p2 = p2->next;

mid = p2;

}

}

3. 将一个数组生成二叉排序树

排序,选数组中间的一个元素作为根节点,左边的元素构造左子树,右边的节点构造有子树。

4. 查找数组中第k大的数字?

因为快排每次将数组划分为两组加一个枢纽元素,每一趟划分你只需要将k与枢纽元素的下标进行比较,如果比枢纽元素下标大就从右边的子数组中找,如果比枢纽元素下标小从左边的子数组中找,如果一样则就是枢纽元素,找到,如果需要从左边或者右边的子数组中再查找的话,只需要递归一边查找即可,无需像快排一样两边都需要递归,所以复杂度必然降低。

最差情况如下:假设快排每次都平均划分,但是都不在枢纽元素上找到第k大第一趟快排没找到,时间复杂度为O(n),第二趟也没找到,时间复杂度为O(n/2),第k趟找到,时间复杂度为O(n/2k),所以总的时间复杂度为O(n(1+1/2+....+1/2k))=O(n),明显比冒泡快,虽然递归深度是一样的,但是每一趟时间复杂度降低。

5. 红黑树的定义和解释?B树的基本性质?

红黑树:

性质1. 节点是红色或黑色。
性质2. 根节点是黑色。
性质3. 每个叶子结点都带有两个空的黑色结点(被称为黑哨兵),如果一个结点n的只有一个左孩子,那么n的右孩子是一个黑哨兵;如果结点n只有一个右孩子,那么n的左孩子是一个黑哨兵。
性质4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

B树:

1.所有非叶子结点至多拥有两个儿子(Left和Right);

2.所有结点存储一个关键字;

3.非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树;

6. 常见的加密算法?

对称式加密就是加密和解密使用同一个密钥。
非对称式加密就是加密和解密所使用的不是同一个密钥,通常有两个密钥,称为“公钥”和“私钥”,它们两个必需配对使用。
DES:对称算法,数据加密标准,速度较快,适用于加密大量数据的场合;
MD5的典型应用是对一段Message产生fingerprint(指纹),以防止被“篡改”。
RSA是第一个既能用于数据加密也能用于数字签名的算法。

7. https?

HTTP下加入SSL层,HTTPS的安全基础是SSL。

8.有一个IP库,给你一个IP,如何能够快速的从中查找到对应的IP段?不用数据库如何实现?要求省空间
9.简述一致性hash算法。

1)首先求memcached服务器(节点)的哈希值,并将其配置到0 232的圆(continuum)。

2)然后采用同样的方法求出存储数据的键的哈希值,并映射到相同的圆上。

3)然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。如果超过232仍然找不到服务器,就会保存到第一台memcached服务器上。
11.描述一种hash table的实现方法

1) 除法散列法: p ,令 h(k ) = k mod p ,这里, p 如果选取的是比较大的素数,效果比较好。而且此法非常容易实现,因此是最常用的方法。最直观的一种,上图使用的就是这种散列法,公式: index = value % 16,求模数其实是通过一个除法运算得到的。

2) 平方散列法 :求index频繁的操作,而乘法的运算要比除法来得省时。公式: index = (value * value) >>28 (右移,除以2^28。记法:左移变大,是乘。右移变小,是除)

3) 数字选择法:如果关键字的位数比较多,超过长整型范围而无法直接运算,可以选择其中数字分布比较均匀的若干位,所组成的新的值作为关键字或者直接作为函数值。

4) 斐波那契(Fibonacci)散列法:平方散列法的缺点是显而易见的,通过找到一个理想的乘数index = (value * 2654435769) >>28

冲突处理:令数组元素个数为 S ,则当 h(k) 已经存储了元素的时候,依次探查 (h(k)+i) mod S , i=1,2,3…… ,直到找到空的存储单元为止(或者从头到尾扫描一圈仍未发现空单元,这就是哈希表已经满了,发生了错误。当然这是可以通过扩大数组范围避免的)。

12、各类树结构的实现和应用

13、hash,任何一个技术面试官必问(例如为什么一般hashtable的桶数会取一个素数?如何有效避免hash结果值的碰撞)

不选素数的话可能会造成hash出值的范围和原定义的不一致

14.什么是平衡二叉树?

左右子树都是平衡二叉树,而且左右子树的深度差值的约对值不大于1。

15.数组和链表的优缺点

数组,在内存上给出了连续的空间。链表,内存地址上可以是不连续的,每个链表的节点包括原来的内存和下一个节点的信息(单向的一个,双向链表的话,会有两个)。

数组优于链表的:

A. 内存空间占用的少。

B. 数组内的数据可随机访问,但链表不具备随机访问性。

C. 查找速度快

链表优于数组的:

A. 插入与删除的操作方便。

B. 内存地址的利用率方面链表好。

C. 方便内存地址扩展。

17.最小堆插入,删除编程实现

18. 4G的long型整数中找到一个最大的,如何做?

每次从磁盘上尽量多读一些数到内存区,然后处理完之后再读入一批。减少IO次数,自然能够提高效率。分批读入选取最大数,再对缓存的最大数进行快排。

19. 有千万个string在内存怎么高速查找,插入和删除?

对千万个string做hash,可以实现高速查找,找到了,插入和删除就很方便了。关键是如何做hash,对string做hash,要减少碰撞频率。

在内存中维护一个大小为10000的最小堆,每次从文件读一个数,与最小堆的堆顶元素比较,若比堆顶元素大,则替换掉堆顶元素,然后调整堆。最后剩下的堆内元素即为最大的1万个数,算法复杂度为O(NlogN)

(1)全局洗牌法

a)首先生成一个数组,大小为54,初始化为1~54

b)按照索引1到54,逐步对每一张索引牌进行洗牌,首先生成一个余数 value = rand %54,那么我们的索引牌就和这个余数牌进行交换处理

c)等多索引到54结束后,一副牌就洗好了

(2)局部洗牌法:索引牌从1开始,到54结束。这一次索引牌只和剩下还没有洗的牌进行交换, value = index + rand() %(54 - index)

算法复杂度是O(n)

22.请分别用递归和非递归方法,先序遍历二叉树

24.其他各种排序方法

25.哈希表冲突解决方法?

常见的hash算法如下:

解决冲突的方法:

也叫散列法,主要思想是当出现冲突的时候,以关键字的结果值作为key值输入,再进行处理,依次直到冲突解决

线性地址再散列法

当冲突发生时,找到一个空的单元或者全表

二次探测再散列

冲突发生时,在表的左右两侧做跳跃式的探测

伪随机探测再散列

同时构造不同的哈希函数

将同样的哈希地址构造成一个同义词的链表

建立一个基本表和溢出区,凡是和基本元素发生冲突都填入溢出区

六、系统架构

1.设计一个服务,提供递增的SessionID服务,要求保证服务的高可靠性,有哪些方案?集中式/非集中式/分布式

2.多台服务器要执行计划任务,但只有拿到锁的任务才能执行,有一个中心服务器来负责分配锁,但要保证服务的高可靠性。

3.如何有效的判断服务器是否存活?服务器是否踢出集群的决策如何产生?

4.两个服务器如何在同一时刻获取同一数据的时候保证只有一个服务器能访问到数据?

可以采用队列进行处理,写一个队列接口保证同一时间只有一个进程能够访问到数据,或者对于存取数据库的来说,数据库也是可以加锁处理的

5. 编写高效服务器程序,需要考虑的因素

性能对服务器程序来说是至关重要的了,毕竟每个客户都期望自己的请求能够快速的得到响应并处理。那么影响服务器性能的首要因素应该是:

(1)系统的硬件资源,比如说CPU个数,速度,内存大小等。不过由于硬件技术的飞速发展,现代服务器都不缺乏硬件资源。因此,需要考虑的主要问题是如何从“软环境”来提升服务器的性能。

服务器的”软环境“

(2)一方面是指系统的软件资源,比如操作系统允许用户打开的最大文件描述符数量

(3)另一方面指的就是服务器程序本身,即如何从编程的角度来确保服务器的性能。

主要就要考虑大量并发的处理这涉及到使用进程池或线程池实现高效的并发模式(半同步/半异步和领导者/追随者模式),以及高效的逻辑处理方式--有限状态机内存的规划使用比如使用内存池,以空间换时间,被事先创建好,避免动态分配,减少了服务器对内核的访问频率,数据的复制,服务器程序还应该避免不必要的数据复制,尤其是当数据复制发生在用户空间和内核空间之间时。如果内核可以直接处理从socket或者文件读入的数据,则应用程序就没必要将这些数据从内核缓冲区拷贝到应用程序缓冲区中。这里所谓的“直接处理”,是指应用程序不关心这些数据的具体内容是什么,不需要对它们作任何分析。比如说ftp服务器,当客户请求一个文件时,服务器只需要检测目标文件是否存在,以及是否有权限读取就可以了,不需要知道这个文件的具体内容,这样的话ftp服务器就不需要把目标文件读入应用程序缓冲区然后调用send函数来发送,而是直接使用“零拷贝”函数sendfile直接将其发送给客户端。另外,用户代码空间的数据赋值也应该尽可能的避免复制。当两个工作进程之间需要传递大量的数据时,我们就应该考虑使用共享内存来在他们直接直接共享这些数据,而不是使用管道或者消息队列来传递。上下文切换和锁:并发程序必须考虑上下文的切换问题,即进程切换或线程切换所导致的系统开销。即时I/O密集型服务器也不应该使用过多的工作线程(或工作进程),否则进程间切换将占用大量的CPU时间,服务器真正处理业务逻辑的CPU时间比重就下降了。因此为每个客户连接都创建一个工作线程是不可取的。应该使用某种高效的并发模式。(半同步半异步或者说领导者追随者模式)另一个问题就是共享资源的加锁保护。锁通常被认为是导致服务器效率低下的一个因素,因为由他引入的代码不仅不处理业务逻辑,而且需要访问内核资源,因此如果服务器有更好的解决方案,应该尽量避免使用锁。或者说服务器一定非要使用锁的话,尽量使用细粒度的锁,比如读写锁,当工作线程都只读一块内存区域时,读写锁不会增加系统开销,而只有当需要写时才真正需要锁住这块内存区域。对于高峰和低峰的伸缩处理,适度的缓存。

6. QQ飞车新用户注册时,如何判断新注册名字是否已存在?(数量级:几亿)

可以试下先将用户名通过编码方式转换,如转换位整型。然后设置N个区间,每个区间为2^/N的大小。对于新的用户名,先通过2分寻找该用户名属于哪个区间,然后在在这个区间,做一个hash。对于不同的时间复杂度和内存要求可以设置不同N的大小~

加一些基础的技术面试之外的职业素养的面试问题

1.你在工作中犯了个错误,有同事打你小报告,你如何处理?

a.同事之间应该培养和形成良好的同事关系,就是要互相支持而不是互相拆台,互相学习,互相帮助,共同进步。

b.如果小报告里边的事情都是事实也就是说确实是本人做的不好不对的方面,那么自己应该有则改之,提高自己。如果小报告里边的事

情全部不是事实,就是说确实诬陷,那么应该首先坚持日久见人心的态度,持之以恒的把本职工作做好,然后在必要的时候通过适当的

方式和领导沟通,相信领导会知道的。

2.你和同事合作完成一个任务,结果任务错过了截止日期,你如何处理?

3.职业规划?

4.离职原因?

5. 项目中遇到的难题,你是如何解决的?

A.时间 b要求 c.方法

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com