专业课面试之C++

  1. 请用英语说一下面向对象和面向过程的区别(南大) 参考

面向过程”是一种是事件为中心的编程思想。就是分析出解决问题所需的步骤,然后用函数把这写步骤实现,并按顺序调用。
面向对象“是以“对象”为中心的编程思想。
简单的举个例子(面试中注意举例):汽车发动、汽车到站。汽车启动是一个事件,汽车到站是另一个事件,面向过程编程的过程中我们关心的是事件,而不是汽车本身。针对上述两个事件,形成两个函数,之后依次调用。对于面向对象来说,我们关心的是汽车这类对象,两个事件只是这类对象所具有的行为。而且对于这两个行为的顺序没有强制要求。
面向过程的思维方式是分析综合,面向对象的思维方式是构造。

“Process-oriented” is an event-centric programming idea. Is to analyze the steps required to solve the problem, and then use the function to achieve this write step, and call in order.
“Object-oriented” is an object-centered programming idea.
A simple example: cars start, cars arrive. The car startup is an event, and the car arrival is another event. In the course of process-oriented programming, we care about the event, not the car itself. For the above two events, two functions are formed and then called one after another. For object orientation, we are concerned with objects such as cars. Two events are just the behavior of such objects. And there is no requirement for the order of these two behaviors.
The process-oriented way of thinking is analysis and synthesis, and the object-oriented way of thinking is construction.

  1. malloc函数申请一个二维数组(CUHK)参考一 参考二
//申请一维数组
#include <stdio.h>
int main()
{
   char * p=(char *)malloc(sizeof(char)*5);//申请包含5个字符型的数组
   free(p);
   return 0;
}
//法一:使用二级指针申请二维数组
char **p=NULL;int i; //申请一个5行3列的字符型数组
p=(char ** )malloc(sizeof(char *)*5);
for(i=0;i<5;i++)
   p[i]=malloc(sizeof(char)*3)/*释放内存*/
for(i=0;i<5;i++)
      free(p[i]);
free(p);
//法二:用指向数组的指针的方式申请内存
#include <stdio.h>
#include <stdlib.h>
int main()
{
    int i, j;
    //申请一个3行2列的整型数组
    int(*a)[2] = (int(*)[2])malloc(sizeof(int) * 3 * 2);//a是一个指向包含2个元素的数组的指针
    for (i = 0; i < 3; i++)
    {
        for (j = 0; j < 2; j++)
        {
            printf("%p\n", &a[i][j]); //输出数组每个元素地址,每个元素的地址是连续的
        }
    }
    free(a);
    return 0;
}  
  1. 给你一个数组,设计一个既高效又公平的方法随机打乱这个数组(此题和洗牌算法的思想一致)

为了保证公平,每个数只能被选中和移动一次,那么我可以每次随机选一个数移动到最后的位置,然后递归移动前n-1个数。

//递归实现
void shuffle(int *a, int n)
{
    if (n <= 1)
        return;
    swap(a[n - 1], a[rand() % n]);
    shuffle(a, n - 1);
}
//非递归实现
void shuffle(int *a, int n)
{
    while (n > 1)
    {
        swap(a[n-1],a[rand()%n]);
        n--;
    }
}
  1. 各类变量的内存分配 参考
类型字节数
char1
short2
int4
long4
long long8
float4
double8
指针8
  1. 全局,静态,局部的区别

全局变量:定义在函数之外的变量。

  • 在程序运行的过程中,始终存在(生命期是从main函数开始,到main函数结束)
  • 在各个函数中,均能访问(称为"全局可见")。

局部变量:在函数内部定义的变量。参变量也属于局部变量。

  • 生命期短:在进入函数时生效,在退出函数时失效。
  • 仅在本函数内可以访问,在别的函数内不可以访问。(称为"局部可见")。

静态局部变量

  • 静态局部变量存储在静态存储区。
  • 函数运行结束,静态局部变量的内存空间不会被系统回收。下一次调用的时候使用上一次退出时的值。
  • 静态局部变量如果未进行初始化,会被编译器初始化为0或NULL;
//静态局部变量.cpp
#include <iostream>
using namespace std;

void show_average(double x) //输入数字并计算平均值
{
    static double num = 0; //其实num就可以用来记录show_average这个函数调用了几次
    static double sum = 0;
    num += 1;
    sum += x;
    cout << "num=" << num << " sum=" << sum << " avg=" << sum / num << endl;
}
int main()
{
    double entry = 0;
    while (1)
    {
        cout << "Entry a number:";
        cin >> entry;
        if (entry < 0)
        {
            break;
        }
        show_average(entry);
    }
    return 0;
}

静态全局变量与全局变量的区别

  • 静态全局变量生命周期不变,作用域缩小。 静态全局变量只能在它所声明的文件中使用,不能被extern关键字引用。

内存分配顺序
首先将全局变量和静态局部变量分配在静态存储区,然后将声明的局部变量分配在栈区作用域结束后系统自动收回,最后将动态申请的空间分配在堆区,由程序员手动释放。

  1. 封装,多态和继承 参考

封装:将客观事物抽象成类,每个类对自身的数据和方法实行protection。(private,protected,public)
继承:子类从父类那里得到已有的特性,比如说交通工具这个类中有属性速度,那么汽车这个新类就可以从交通工具中继承这个属性 。

多态:一个接口,多种方法,在子类中重写父类的虚函数,当用父类指针调用这个虚函数的时候实际上调用的是重写后的函数。(允许将子类类型的指针赋值给父类类型的指针)

#include <iostream>
using namespace std;

class Animal
{
public:
	virtual void makeSound() { cout << "rawr" << endl; }
};

class Dog : public Animal
{
public:
	virtual void makeSound() { cout << "bark" << endl; }
};

int main()
{
	Animal animal;
	animal.makeSound(); // rawr (1)

	Dog dog;
	dog.makeSound(); // bark (2)

	Animal badDog = Dog();
	badDog.makeSound(); // (3) rawr !!!!!!!!!!!!!!!!!!!

	Animal *goodDog = new Dog();
	goodDog->makeSound(); // bark (4)
}
  1. new 和 malloc的区别
  1. malloc和free是C++/C语言的标准库函数。new/delete是C++的运算符。它们都可以用于申请动态内存和释放内存。
  2. 对于非内部数据类型的对象而言,如果用new运算符创建一个自定义数据类型的对象,会先申请内存,再调用类的构造函数。而用malloc函数,只会分配内存,不会进行类的初始化工作。同理,free函数也不会调用析构函数。
  3. new返回指定类型的指针,并且可以自动计算所需要大小,malloc返回的是void类型的指针需要我们进行强制类型转换为需要的类型,且malloc函数需要我们自己计算字节数。
  1. 将引用作为函数返回值的格式,好处和需要遵守的规则?
  1. 格式:类型标识符 &函数名(参数列表) {函数体}
  2. 好处:在内存中不存在返回值的副本。
  3. 主要事项:
    3.1 不能返回局部变量的引用。局部变量在函数调用结束后被销毁,此时被返回的引用就成为了无所指的引用,程序会进入未知状态。
    3.2 不能返回函数内部new分配的内存的引用。被返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。
    3.3 可以返回类的成员的引用,但最好是const。(否则破坏了封装性)如果其他对象可以获得该属性的非常量引用(指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。
  1. 重写和重载的区别
  1. 重写:子类覆盖父类的虚函数。要求函数名称,参数列表,返回值都相同。重写一般与多态相关。当子类重新定义了父类的虚函数,父类指针根据赋予它的不同的子类指针,动态的调用属于子类的该函数。这样的函数调用在编译期是无法确定的。函数地址是在运行期绑定的。
  2. 重载:重载是在同一个类中的两个或两个以上的方法,拥有相同的方法名,但是参数却不相同,方法体也不相同,最常见的重载的例子就是类的构造函数。重载与多态无关。函数的调用在编译期就确定了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值