rainit2006 / C-Program

C# Program knowledge
0 stars 0 forks source link

面试题-笔试题 #26

Open rainit2006 opened 6 years ago

rainit2006 commented 6 years ago

rainit2006 commented 6 years ago

反射(Reflection)有下列用途: 1,它允许在运行时查看特性(attribute)信息。 2,它允许审查集合中的各种类型,以及实例化这些类型。 3,它允许延迟绑定的方法和属性(property)。 4,它允许在运行时创建新类型,然后使用这些类型执行一些任务。

System.Reflection.MemberInfo info = typeof(MyClass);
         object[] attributes = info.GetCustomAttributes(true);
         for (int i = 0; i < attributes.Length; i++)
         {
            System.Console.WriteLine(attributes[i]);
         }

Reflection是.Net中获取运行时类型信息的方式, .Net的应用程序由几个部分:‘程序集(Assembly)’、‘模块(Module)’、‘类型(class)’组成,而反射提供一种编程的方式,让程序员可以在程序运行期获得这几个组成部分的相关信息,例如:

-- Assembly类 可以获得正在运行的装配件信息,也可以动态的加载装配件,以及在装配件中查找类型信息,并创建该类型的实例。 -- Type类 可以获得对象的类型信息,此信息包含对象的所有要素:方法、构造器、属性等等,通过Type类可以得到这些要素的信息,并且调用之。

…
public  void  Process(  object  processObj  )
{
//利用GetType方法
Type  t  =  processsObj.GetType();
if(  t.GetInterface(“ITest”)  !=null  )
                    …
}

-- MethodInfo 包含方法的信息,通过这个类可以得到方法的名称、参数、返回值等,并且可以调用之。

诸如此类,还有FieldInfo、EventInfo等等,这些类都包含在System.Reflection命名空间下。

运行期得到类型信息有什么用?


rainit2006 commented 6 years ago

从实现原理上来说: 重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。如,有两个同名函数:function func(p:integer):integer;和function func(p:string):integer;。那么编译器做过修饰后的函数名称可能是这样的:int_func、str_func。对于这两个函数的调用,在编译器间就已经确定了,是静态的。也就是说,它们的地址在编译期就绑定了(早绑定),因此,重载和多态无关! 重写:和多态真正相关。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚绑定)。


- New delete 与malloc free 的联系与区别?
答案:都是在堆(heap)上进行动态的内存操作。用malloc函数需要指定内存分配的字节数并且不能初始化对象,new 会自动调用对象的构造函数。delete 会调用对象的destructor,而free 不会调用对象的destructor.

- #define DOUBLE(x) x+x ,i = 5*DOUBLE(5); i 是多少?
答案:i 为30。(注意直接展开就是了) 5 * 5 + 5 

- C++是不是类型安全的?
答案:不是。两个不同类型的指针之间可以强制转换(用reinterpret cast)。C#是类型安全的。

- 描述内存分配方式以及它们的区别?

1) 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static 变量。 2) 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集。 3) 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意多少的内存,程序员自己负责在何时用free 或delete 释放内存。动态内存的生存期由程序员决定,使用非常灵活,但问题也最多。 4) 代码区。



- struct 和 class 的区别
答案:struct 的成员默认是公有的,而类的成员默认是私有的。struct 和 class 在其他方面是功能相当的。

- const与#define 相比,有何优点?
1) const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。
2) 有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。
比较大的区别还在于#define是没有作用域的,只是文本替换,发生在预处理期,可能被undefine , redefine掉了。而const是有作用域的,在编译期。

- 如何打印出当前源文件的文件名以及源文件的当前行号?
答案:
cout << __FILE__ ;
cout<<__LINE__ ;
__FILE__和__LINE__是系统预定义宏,这种宏并不是在某个文件中定义的,而是由编译器定义的
rainit2006 commented 6 years ago

Java 言語を例に挙げると、 Integer a = new Integer(0); Integer b = new Integer(0); assert a != b; // 異なるインスタンスへの参照であるため、等値ではない assert a.equals(b); // インスタンスが持つ情報は両方とも整数の 0 なので、等価


- 「値渡し」と「参照渡し」の違い

値渡しは、データそのものをコピーして渡す。

参照渡しは、データへアクセスするための情報を渡す。例えばポインタ等。

値渡しがデータサイズが大きいほど遅くなるのに対し、参照渡しは一定で、一般的に高速。

値渡しは渡した先でデータが書き換えられても、元のデータには影響しない。他方、参照渡しは、渡した先でデータが書き換えられたら、元のデータが書き換わってしまう。

つまり、一般的に、値渡しは低速だが安全で、 参照渡しは高速だが危険だ。 C/C++ 言語では、const 修飾子によって安全に参照渡しができる (抜け道があるので、真実安全ではないが)。 Java 等の最近のオブジェクト指向言語では、オブジェクトは参照渡ししかできない場合が多い上に、const 修飾子のような機能はない。 そのため、防御的コピーという手法を用いて安全性を確保する。これは値渡しよりもさらに低速である。

- 「ポリモーフィズム(Polymorphism)」とは何

複数の異なる実装を持つことができるインターフェイスの性質。 例えば、仮想関数を持つクラスはポリモーフィズムを備えている。派生クラスによって、仮想関数に異なる実装を与えることができる。 ex. C++では、「継承」と「仮想関数」を利用することで、ポリモーフィズムを実現します。


- 「悲観的ロック」と「楽観的ロック」

楽観ロック: 他者はそうそう同じリソースに変更を加えないだろう、という楽観的な視点での排他制御。 更新系において、参照時には全くロックを掛けず、新しいリソースの挿入時に参照データとバージョンが同じか、参照から更新の間に誰かに変更されていないか、をチェックしてから挿入する手法。参照から更新の間に元データに変更があったら変更を破棄する。 待ちが発生せず、更新の失敗がそのまま失敗として返ってくる。他者の更新通知を受け取らない。

悲観ロック: 他者が同じリソースに頻繁に変更を加えること前提の悲観的視点での排他制御。 更新系において、参照時に参照リソースにロックをかけ、新しいリソースの挿入完了時にロックをはずす手法。 待ちが発生するが、待っている作業に対して前の作業が終了したことが通知される。

悲観的ロックを行ってしまうと、データ操作を並列処理できない。 楽観的ロックでは、頻繁にデータ操作がバッティングしないことを前提に、効率よく並列処理が行える。

Java では ConcurrentHashMap, C# では ConcurrentDictionary 等、高度な楽観的ロックのアルゴリズムを備えたコンテナが標準で提供されている。

- 数値Xのフィボナッチ数を計算するアルゴリズムを示す
![image](https://user-images.githubusercontent.com/12871721/38967291-5033948a-43c1-11e8-9253-0d5e4080793c.png)

- 指定された数値Xが素数であるかどうかを判定するアルゴリズム
https://qiita.com/asksaito/items/76b71602dd956b79dbf7
https://blog.csdn.net/wangjun_huster/article/details/65949646

- ループを使わずに配列の順序を逆にするアルゴリズムを示す。

再帰すればいいのかな。以下 C++ 言語 template void reverseArray(T begin, T end) { if (begin >= end) return; std::swap(begin, (end-1)); reverseArray(begin+1, end-1); }


- C++ テンプレートと C# ジェネリックの違い
https://github.com/rainit2006/C-Program/issues/5

- Binary Search Trees over Hash Tables

Binary Search Trees (reference-based) are memory-efficient.

For instance, if a hash function has a range R(h) = 0...100, then you need to allocate an array of 100 (pointers-to) elements, even if you are just hashing 20 elements. If you were to use a binary search tree to store the same information, you would only allocate as much space as you needed, as well as some metadata about links.

ハッシュテーブルは、追加する時ハッシュ関数を回してキーからアドレスを得て、他の値に影響しない上で、呼び出す時キーさえあれば、アドレスもキーからわかってきて、すぐ値を尋ねられる。

ハッシュテーブほどメモリの確保が要らない。 ハッシュ関数を考えずに、済む。 などのメリットがあります。 ただ木のバランスが取れておらず、片方が長くなると、計算量はO(n)O(n)に近づくため、左右のバランスをとる平衡木などが考案されています。回転、などの手法によって実現されます。

rainit2006 commented 6 years ago

特别要注意的是:string是引用类型。


- 请列举一下您所知道的模式,越多越好:

创建型模式:工厂方法(Factory Method)、抽象工厂(Abstract Factory)、Prototype(原型模式)、Builder(构造模式)、Singleton(单件模式)

结构模式:外观模式(Facade)、代理模式(Proxy)、适配器模式(Adapter)、组合模式(Composite)、装饰模式(Decorator)、桥接模式(Bridge)、享元模式(Flyweight)。

行为模式: 模板方法(Template Method)、备忘录模式(Memento)、观察者模式(Observer)、职责链模式(Chain of Responsibility)、命令模式(Command)、状态模式(State)、策略模式(Strategy)、中介者模式(Mediator)、解释器模式(Interpreter)、访问者模式(Visitor)、迭代器模式(Iterator)


- 请任选一种算法,用C#语法实现对一个整型数组的逆序排序

可以有多种排序方法,最简单的是冒泡排序: int[] array = new int[]{ 2, 4, 5, 6, 7, 2, 1, 9, 0 }; for(int k=0; k<array.Length; k++) { for(int i=0; i<k; i++) { if(array[k] < array[i]) { int t = array[k]; array[k] = array[i]; array[i] = t; } } }


-  假如一个整型数组中有重复的元素,请用C#写一个算法,将其中重复的元素去除,只保留一个

int[] array = new int[]{ 2, 4, 5, 6, 7, 5, 6, 7, 2, 1, 9, 0 }; List list = new List(); foreach(int item in array) { if(!list.Contains(item)) list.Add(item); }

array = list.ToArray();

rainit2006 commented 6 years ago