学做ppt的网站,dedecms行业门户网站模板,公司变更经营范围,橙色企业网站C/C/C#面试题精选#xff08;1#xff09;
题目#xff08;一#xff09;#xff1a;C中我们可以用static修饰一个类的成员函数#xff0c;也可以用const修饰类的成员函数#xff08;写在函数的最后表示不能修改成员变量#xff0c;不是指写在前面表示返回值为常量/C#面试题精选1
题目一C中我们可以用static修饰一个类的成员函数也可以用const修饰类的成员函数写在函数的最后表示不能修改成员变量不是指写在前面表示返回值为常量。请问能不能同时用static和const修饰类的成员函数
分析答案是不可以。C编译器在实现const的成员函数的时候为了确保该函数不能修改类的实例的状态会在函数中添加一个隐式的参数const this*。但当一个成员为static的时候该函数是没有this指针的。也就是说此时static的用法和static是冲突的。
我们也可以这样理解两者的语意是矛盾的。static的作用是表示该函数只作用在类型的静态变量上与类的实例没有关系而const的作用是确保函数不能修改类的实例的状态与类型的静态变量没有关系。因此不能同时用它们。
题目二运行下面C代码输出是什么
class A
{
}; class B
{
public: B() {} ~B() {}
}; class C
{
public: C() {} virtual ~C() {}
}; int _tmain(int argc, _TCHAR* argv[])
{ printf(%d, %d, %d/n,sizeof(A),sizeof(B),sizeof(C)); return 0;
}
分析答案是1, 1, 4。class A是一个空类型它的实例不包含任何信息本来求sizeof应该是0。但当我们声明该类型的实例的时候它必须在内存中占有一定的空间否则无法使用这些实例。至于占用多少内存由编译器决定。Visual Studio 2008中每个空类型的实例占用一个byte的空间。
class B在class A的基础上添加了构造函数和析构函数。由于构造函数和析构函数的调用与类型的实例无关调用它们只需要知道函数地址即可在它的实例中不需要增加任何信息。所以sizeof(B)和sizeof(A)一样在Visual Studio 2008中都是1。
class C在class B的基础上把析构函数标注为虚拟函数。C的编译器一旦发现一个类型中有虚拟函数就会为该类型生成虚函数表并在该类型的每一个实例中添加一个指向虚函数表的指针。在32位的机器上一个指针占4个字节的空间因此sizeof(C)是4。
题目三运行下面的C代码得到的结果是什么
class A
{
private: int m_value; public: A(int value) { m_value value; } void Print1() { printf(hello world); } void Print2() { printf(%d, m_value); }
}; int _tmain(int argc, _TCHAR* argv[])
{ A* pA NULL; pA-Print1(); pA-Print2(); return 0;
}
分析答案是Print1调用正常打印出hello world但运行至Print2时程序崩溃。调用Print1时并不需要pA的地址因为Print1的函数地址是固定的。编译器会给Print1传入一个this指针该指针为NULL但在Print1中该this指针并没有用到。只要程序运行时没有访问不该访问的内存就不会出错因此运行正常。在运行print2时需要this指针才能得到m_value的值。由于此时this指针为NULL因此程序崩溃了。
题目四运行下面的C代码得到的结果是什么
class A
{
private: int m_value; public: A(int value) { m_value value; } void Print1() { printf(hello world); } virtualvoid Print2() { printf(hello world); }
}; int _tmain(int argc, _TCHAR* argv[])
{ A* pA NULL; pA-Print1(); pA-Print2(); return 0;
}
分析答案是Print1调用正常打印出hello world但运行至Print2时程序崩溃。Print1的调用情况和上面的题目一样不在赘述。由于Print2是虚函数。C调用虚函数的时候要根据实例即this指针指向的实例中虚函数表指针得到虚函数表再从虚函数表中找到函数的地址。由于这一步需要访问实例的地址即this指针而此时this指针为空指针因此导致内存访问出错。
题目五C中静态成员函数能不能同时也是虚函数
分析答案是不能。调用静态成员函数不要实例。但调用虚函数需要从一个实例中指向虚函数表的指针以得到函数的地址因此调用虚函数需要一个实例。两者相互矛盾。
博主何海涛对本博客文章享有版权。网络转载请注明出处。整理出版物请和作者联系。有任何建议或意见欢迎在评论中告知或者加我微博http://weibo.com/zhedahht与我交流。 C/C/C#面试题精选2 题目六运行下列C代码输出什么
struct Point3D
{ int x; int y; int z;
}; int _tmain(int argc, _TCHAR* argv[])
{ Point3D* pPoint NULL; int offset (int)((pPoint)-z); printf(%d, offset); return 0;
}
答案输出8。由于在pPoint-z的前面加上了取地址符号运行到此时的时候会在pPoint的指针地址上加z在类型Point3D中的偏移量8。由于pPoint的地址是0因此最终offset的值是8。
(pPoint-z)的语意是求pPoint中变量z的地址pPoint的地址0加z的偏移量8并不需要访问pPoint指向的内存。只要不访问非法的内存程序就不会出错。
题目七运行下列C代码输出什么
class A
{
public: A() { Print(); } virtualvoid Print() { printf(A is constructed./n); }
}; class B:public A
{
public: B() { Print(); } virtualvoid Print() { printf(B is constructed./n); }
}; int _tmain(int argc, _TCHAR* argv[])
{ A* pA new B(); delete pA; return 0;
}
答案先后打印出两行:A is constructed. B is constructed.调用B的构造函数时先会调用B的基类及A的构造函数。然后在A的构造函数里调用Print。由于此时实例的类型B的部分还没有构造好本质上它只是A的一个实例他的虚函数表指针指向的是类型A的虚函数表。因此此时调用的Print是A::Print而不是B::Print。接着调用类型B的构造函数并调用Print。此时已经开始构造B因此此时调用的Print是B::Print。
同样是调用虚拟函数Print我们发现在类型A的构造函数中调用的是A::Print在B的构造函数中调用的是B::Print。因此虚函数在构造函数中已经失去了虚函数的动态绑定特性。
题目八运行下列C#代码输出是什么
namespace ChangesOnString
{ classProgram { staticvoid Main(string[] args) { String str hello; str.ToUpper(); str.Insert(0, WORLD); Console.WriteLine(str); } }
}
答案输出是hello。由于在.NET中String有一个非常特殊的性质String的实例的状态不能被改变。如果String的成员函数会修改实例的状态将会返回一个新的String实例。改动只会出现在返回值中而不会修改原来的实例。所以本题中输出仍然是原来的字符串值hello。
如果试图改变String的内容改变之后的值可以通过返回值拿到。用StringBuilder是更好的选择特别是要连续多次修改的时候。如果用String连续多次修改每一次修改都会产生一个临时对象开销太大。
题目九在C和C#中struct和class有什么不同
答案在C中如果没有标明函数或者变量是的访问权限级别在struct中是public的而在class中是private的。 在C#中如果没有标明函数或者变量的访问权限级别struct和class中都是private的。struct和class的区别是struct定义值类型其实例在栈上分配内存class定义引用类型其实例在堆上分配内存。
题目十运行下图中的C#代码输出是什么
namespace StaticConstructor
{ classA { public A(string text) { Console.WriteLine(text); } } classB { staticA a1 new A(a1); A a2 newA(a2); static B() { a1 newA(a3); } public B() { a2 newA(a4); } } classProgram { staticvoid Main(string[] args) { B b newB(); } }
}
答案打印出四行分别是a1、a3、a2、a4。
在调用类型B的代码之前先执行B的静态构造函数。静态函数先初始化类型的静态变量再执行静态函数内的语句。因此先打印a1再打印a3。接下来执行B b new B()即调用B的普通构造函数。构造函数先初始化成员变量在执行函数体内的语句因此先后打印出a2、a4。
博主何海涛对本博客文章享有版权。网络转载请注明出处。整理出版物请和作者联系。有任何建议或意见欢迎在评论中告知或者加我微博http://weibo.com/zhedahht与我交流。
C/C/C#面试题精选3
题目11运行下图中的C#代码输出是什么
namespace StringValueOrReference
{ class Program { internal staticvoid ValueOrReference(Type type) { String result The type type.Name; if (type.IsValueType) Console.WriteLine(result is a value type.); else Console.WriteLine(result is a reference type.); } internal staticvoid ModifyString(String text) { text world; } static void Main(string[] args) { String text hello; ValueOrReference(text.GetType()); ModifyString(text); Console.WriteLine(text); } }
}
答案输出两行。第一行是The type String is reference type. 第二行是hello。类型String的定义是public sealed class String {...}既然是class那么String就是引用类型。
在方法ModifyString里对text赋值一个新的字符串此时改变的不是原来text的内容而是把text指向一个新的字符串world。由于参数text没有加ref或者out出了方法之后text还是指向原来的字符串因此输出仍然是hello.
题目12运行下图中的C代码输出是什么
#includeiostream class A
{
private: int n1; int n2;
public: A(): n2(0), n1(n2 2) { } void Print() { std::cout n1: n1 , n2: n2 std::endl; }
}; int _tmain(int argc, _TCHAR* argv[])
{ A a; a.Print(); return 0;
}
答案输出n1是一个随机的数字n2为0。在C中成员变量的初始化顺序与变量在类型中的申明顺序相同而与它们在构造函数的初始化列表中的顺序无关。因此在这道题中会首先初始化n1而初始n1的参数n2还没有初始化是一个随机值因此n1就是一个随机值。初始化n2时根据参数0对其初始化故n20。
题目13编译运行下图中的C代码结果是什么A编译错误B编译成功运行时程序崩溃C编译运行正常输出10。请选择正确答案并分析原因。
#includeiostream class A
{
private: int value; public: A(int n) { value n; } A(A other) { value other.value; } void Print() { std::cout value std::endl; }
}; int _tmain(int argc, _TCHAR* argv[])
{ A a 10; A b a; b.Print(); return 0;
}
答案编译错误。在复制构造函数中传入的参数是A的一个实例。由于是传值把形参拷贝到实参会调用复制构造函数。因此如果允许复制构造函数传值那么会形成永无休止的递归并造成栈溢出。因此C的标准不允许复制构造函数传值参数而必须是传引用或者常量引用。在Visual Studio和GCC中都将编译出错。
题目14运行下图中的C代码输出是什么
int SizeOf(char pString[])
{ return sizeof(pString);
} int _tmain(int argc, _TCHAR* argv[])
{ char* pString1 google; int size1 sizeof(pString1); int size2 sizeof(*pString1); char pString2[100] google; int size3 sizeof(pString2); int size4 SizeOf(pString2); printf(%d, %d, %d, %d, size1, size2, size3, size4); return 0;
}
答案4, 1, 100, 4。pString1是一个指针。在32位机器上任意指针都占4个字节的空间。*pString1是字符串pString1的第一个字符。一个字符占一个字节。pString2是一个数组sizeof(pString2)是求数组的大小。这个数组包含100个字符因此大小是100个字节。而在函数SizeOf中虽然传入的参数是一个字符数组当数组作为函数的参数进行传递时数组就自动退化为同类型的指针。
题目15运行下图中代码输出的结果是什么这段代码有什么问题
#includeiostream class A
{
public: A() { std::cout A is created. std::endl; } ~A() { std::cout A is deleted. std::endl; }
}; class B :public A
{
public: B() { std::cout B is created. std::endl; } ~B() { std::cout B is deleted. std::endl; }
}; int _tmain(int argc, _TCHAR* argv[])
{ A* pA new B(); delete pA; return 0;
}
答案输出三行分别是A is created. B is created. A is deleted。用new创建B时回调用B的构造函数。在调用B的构造函数的时候会先调用A的构造函数。因此先输出A is created. B is created.
接下来运行delete语句时会调用析构函数。由于pA被声明成类型A的指针同时基类A的析构函数没有标上virtual因此只有A的析构函数被调用到而不会调用B的析构函数。
由于pA实际上是指向一个B的实例的指针但在析构的时候只调用了基类A的析构函数却没有调用B的析构函数。这就是一个问题。如果在类型B中创建了一些资源比如文件句柄、内存等在这种情况下都得不到释放从而导致资源泄漏。 博主何海涛对本博客文章享有版权。网络转载请注明出处http://blog.csdn.net/cadcisdhht。整理出版物请和作者联系。有任何建议或意见欢迎在评论中告知或者加我微博http://weibo.com/zhedahht与我交流。 C/C/C#面试题精选4 问题16运行如下的C代码输出是什么
class A
{
public: virtualvoid Fun(int number 10) { std::cout A::Fun with number number; }
}; class B:public A
{
public: virtualvoid Fun(int number 20) { std::cout B::Fun with number number; }
}; int main()
{ B b; A a b; a.Fun();
}
答案输出B::Fun with number 10。由于a是一个指向B实例的引用因此在运行的时候会调用B::Fun。但缺省参数是在编译期决定的。在编译的时候编译器只知道a是一个类型a的引用具体指向什么类型在编译期是不能确定的因此会按照A::Fun的声明把缺省参数number设为10。 这一题的关键在于理解确定缺省参数的值是在编译的时候但确定引用、指针的虚函数调用哪个类型的函数是在运行的时候。
问题17运行如下的C代码输出是什么
char* GetString1()
{ char p[] Hello World; return p;
} char* GetString2()
{ char *p Hello World; return p;
} int _tmain(int argc, _TCHAR* argv[])
{ printf(GetString1 returns: %s. /n, GetString1()); printf(GetString2 returns: %s. /n, GetString2()); return 0;
}
答案输出两行第一行GetString1 returns: 后面跟的是一串随机的内容而第二行GetString2 returns: Hello World.两个函数的区别在于GetString1中是一个数组而GetString2中是一个指针。
当运行到GetString1时p是一个数组会开辟一块内存并拷贝Hello World初始化该数组。接着返回数组的首地址并退出该函数。由于p是GetString1内的一个局部变量当运行到这个函数外面的时候这个数组的内存会被释放掉。因此在_tmain函数里再去访问这个数组的内容时结果是随机的。
当运行到GetString2时p是一个指针它指向的是字符串常量区的一个常量字符串。该常量字符串是一个全局的并不会因为退出函数GetString2而被释放掉。因此在_tmain中仍然根据GetString2返回的地址得到字符串Hello World。
问题18运行下图中C#代码输出的结果是什么
namespace StaticVariableInAppDomain
{ [Serializable] internalclassA : MarshalByRefObject { publicstaticint Number; publicvoid SetNumber(int value) { Number value; } } [Serializable] internalclassB { publicstaticint Number; publicvoid SetNumber(int value) { Number value; } } classProgram { staticvoid Main(string[] args) { String assamblyName Assembly.GetEntryAssembly().FullName; AppDomain domain AppDomain.CreateDomain(NewDomain); A.Number 10; String nameOfA typeof(A).FullName; A a domain.CreateInstanceAndUnwrap(assamblyName, nameOfA)asA; a.SetNumber(20); Console.WriteLine(Number in class A is {0},A.Number); B.Number 10; String nameOfB typeof(B).FullName; B b domain.CreateInstanceAndUnwrap(assamblyName, nameOfB)asB; b.SetNumber(20); Console.WriteLine(Number in class B is {0},B.Number); } }
}
答案输出两行第一行是Number in class A is 10而第二行是Number in class B is 20。上述C#代码先创建一个命名为NewDomain的应用程序域并在该域中利用反射机制创建类型A的一个实例和类型B的一个实例。我们注意到类型A是继承自MarshalByRefObject而B不是。虽然这两个类型的结构一样但由于基类不同而导致在跨越应用程序域的边界时表现出的行为将大不相同。 由于A继承MarshalByRefObject那么a实际上只是在缺省的域中的一个代理它指向位于NewDomain域中的A的一个实例。当a.SetNumber时是在NewDomain域中调用该方法它将修改NewDomain域中静态变量A.Number的值并设为20。由于静态变量在每个应用程序域中都有一份独立的拷贝修改NewDomain域中的静态变量A.Number对缺省域中的静态变量A.NewDomain没有任何影响。由于Console.WriteLine是在缺省的应用程序域中输出A.Number因此输出仍然是10。 B只从Object继承而来的类型它的实例穿越应用程序域的边界时将会完整地拷贝实例。在上述代码中我们尽管试图在NewDomani域中生成B的实例但会把实例b拷贝到缺省的域。此时调用b.SetNumber也是在缺省的域上进行它将修改缺省的域上的A.Number并设为20。因此这一次输出的是20。
问题19运行下图中C代码输出的结果是什么
int _tmain(int argc, _TCHAR* argv[])
{ char str1[] hello world; char str2[] hello world; char* str3 hello world; char* str4 hello world; if(str1 str2) printf(str1 and str2 are same./n); else printf(str1 and str2 are not same./n); if(str3 str4) printf(str3 and str4 are same./n); else printf(str3 and str4 are not same./n); return 0;
}
答案输出两行。第一行是str1 and str2 are not same第二行是str3 and str4 are same。
str1和str2是两个字符串数组。我们会为它们分配两个长度为12个字节的空间并把hello world的内容分别拷贝到数组中去。这是两个初始地址不同的数组因此比较str1和str2的值会不相同。str3和str4是两个指针我们无需为它们分配内存以存储字符串的内容而只需要把它们指向hello world“在内存中的地址就可以了。由于hello world”是常量字符串它在内存中只有一个拷贝因此str3和str4指向的是同一个地址。因此比较str3和str4的值会是相同的。
问题20运行下图中C#代码输出的结果是什么并请比较这两个类型各有什么特点有哪些区别。
namespace Singleton
{ publicsealedclass Singleton1 { private Singleton1() { Console.WriteLine(Singleton1 constructed); } publicstaticvoid Print() { Console.WriteLine(Singleton1 Print); } privatestaticSingleton1 instance new Singleton1(); publicstaticSingleton1 Instance { get { return instance; } } } publicsealedclass Singleton2 { Singleton2() { Console.WriteLine(Singleton2 constructed); } publicstaticvoid Print() { Console.WriteLine(Singleton2 Print); } publicstaticSingleton2 Instance { get { returnNested.instance; } } classNested { static Nested() { } internalstaticreadonly Singleton2 instance new Singleton2(); } } classProgram { staticvoid Main(string[] args) { Singleton1.Print(); Singleton2.Print(); } }
}
答案:输出三行第一行“Singleton1 constructed”第二行“Singleton1 Print”第三行“Singleton2 Print”。
当我们调用Singleton1.Print时.NET运行时会自动调用Singleton1的静态构造函数并初始化它的静态变量。此时会创建一个Singleton1的实例因此会调用它的构造函数。Singleton2的实例是在Nested的静态构造函数里初始化的。只有当类型Nested被使用时才回触发.NET运行时调用它的静态构造函数。我们注意到我们只在Sington2.Instance里面用到了Nested。而在我们的代码中只调用了Singleton2.Print。因此不会创建Singleton2的实例也不会调用它的构造函数。
这两个类型其实都是单例模式Singleton的实现。第二个实现Singleton2只在真的需要时才会创建实例而第一个实现Singleton1则不然。第二个实现在空间效率上更好。
博主何海涛对本博客文章享有版权。网络转载请注明出处http://blog.csdn.net/cadcisdhht。整理出版物请和作者联系。有任何建议或意见欢迎在评论中告知或者加我微博http://weibo.com/zhedahht与我交流。
C/C/C#面试题精选5
问题21C#是一门托管语言那么是不是说明只要用C#就能保证不会出现内存泄露和其他资源泄漏如果不是在哪些情况下可能会出现泄漏
答案C#不能保证没有资源泄漏。比如如下几种情况可能会造成资源泄漏1 调用Nativecode比如用P/Invoke或者调用COM2 读写文件时的没有及时closestream, 或者ADO.NET连数据库时没有及时关闭连接也算资源泄漏3注册事件后没有remove导致publisher和subscriber的强依 赖垃圾回收可能会被推迟4.NET还定义了一些方法直接申请非托管内存比如Marshal.AllocHGlobal和Marshal.AllocCoTaskMem。通过这种方式得到的内存如果没有及时释放也会造成内存泄露。
问题22下面的两段C#有哪些不同 [csharp] view plaincopy static void CatchException1() { try { Function(); } catch { throw; } } static void CatchException2() { try { Function(); } catch (Exception e) { throw e; } } 答案两个函数的catch都是重新抛出截获的exception但抛出的exception的callstack是不一样的。对于第一种方法exception的callstack是从最开始的抛出地点开始的。对于第二种方法exception的callstack是从CatchException2开始的最初抛出的地方相关的信息被隐藏了。
问题23运行下图中的C代码打印出的结果是什么 [cpp] view plaincopy bool Fun1(char* str) { printf(%s\n,str); return false; } bool Fun2(char* str) { printf(%s\n,str); return true; } int _tmain(int argc, _TCHAR* argv[]) { bool res1,res2; res1 (Fun1(a) Fun2(b)) || (Fun1(c) || Fun2(d)); res2 (Fun1(a) Fun2(b)) (Fun1(c) || Fun2(d)); return res1|| res2; } 答案打印出4行分别是a、c、d、a。
在C/C中与、或运算是从左到右的顺序执行的。在计算rest1时先计算Fun1(“a”) Func2(“b”)。首先Func1(“a”)打印出内容为a的一行。由于Fun1(“a”)返回的是false,无论Func2(“b”)的返回值是true还是falseFun1(“a”) Func2(“b”)的结果都是false。由于Func2(“b”)的结果无关重要因此Func2(“b”)会略去而不做计算。接下来计算Fun1(“c”)|| Func2(“d”)分别打印出内容c和d的两行。 在计算rest2时首先Func1(“a”)打印出内容为a的一行。由于Func1(“a”)返回false和前面一样的道理Func2(“b”)会略去不做计算。由于Fun1(“a”) Func2(“b”)的结果是false不管Fun1(“c”) Func2(“d”)的结果是什么整个表达式得到的结果都是false因此Fun1(“c”) || Func2(“d”)都将被忽略。
问题24运行下面的C#代码打印出来的结果是什么 [csharp] view plaincopy struct Person { public string Name; public override string ToString() { return Name; } } class Program { static void Main(string[]args) { ArrayListarray new ArrayList(); Personjim new Person(){Name Jim}; array.Add(jim); Personfirst (Person)array[0]; first.Name Peter; Console.WriteLine(array[0].ToString()); } } 答案Person的定义是一个struct因此是一个值类型。在运行到语句Person first (Person)array[0]的时候first是array[0]的一个拷贝first和array[0]不是一个实例。因此修改first对array[0]没有影响。
问题25运行下面的C代码打印的结果是什么 [cpp] view plaincopy class Base { public: voidprint() { doPrint();} private: virtual void doPrint() {cout Base::doPrint endl;} }; class Derived : public Base { private: virtual void doPrint() {cout Derived::doPrint endl;} }; int _tmain(int argc, _TCHAR* argv[]) { Base b; b.print(); Derived d; d.print(); return 0; } 答案输出两行分别是Base::doPrint和Derived::doPrint。在print中调用doPrint时doPrint()的写法和this-doPrint()是等价的因此将根据实际的类型调用对应的doPrint。所以结果是分别调用的是Base::doPrint和Derived::doPrint2。如果感兴趣可以查看一下汇编代码就能看出来调用doPrint是从虚函数表中得到函数地址的。 博主何海涛对本博客文章享有版权。网络转载请注明出处http://blog.csdn.net/cadcisdhht。整理出版物请和作者联系。有任何建议或意见欢迎在评论中告知或者加我微博http://weibo.com/zhedahht与我交流。