C++类
能够准确无误地编写出String类的构造函数、拷贝构造函数、赋值函数和析构函数的面试者至少已经具备了C++基本功的60%以上!在这个类中包括了指针类成员变量m_data,当类中包括指针类成员变量时,一定要重载其拷贝构造函数、赋值函数和析构函数,这既是对C++程序员的基本要求,也是《Effective C++》中特别强调的条款。仔细学习这个类,特别注意加注释的得分点和加分点的意义,这样就具备了60%以上的C++基本功!
1.
Typedef 在C语言中频繁用以声明一个已经存在的数据类型的同义字。也可以用预处理器做类似的事。例如,思考一下下面的例子:
#define dPS struct s *
typedef struct s * tPS;
以上两种情况的意图都是要定义dPS 和 tPS 作为一个指向结构s指针。哪种方法更好呢?(如果有的话)为什么?
?
这是一个非常微妙的问题,任何人答对这个问题(正当的原因)是应当被恭喜的。答案是:typedef更好。思考下面的例子:
dPS p1,p2;
tPS p3,p4;
第一个扩展为struct s * p1, p2;
上面的代码定义p1为一个指向结构的指,p2为一个实际的结构,这也许不是你想要的。
第二个将struct s* 重名为一种新的类型tPS;第二个例子正确地定义了p3 和p4 两个指针。
第一个只是字符替换,第二个才是重新定义了一种新的类型
3、解释下列输出结果
char str1[] = "abc";
char str2[] = "abc";
const char str3[] = "abc";
const char str4[] = "abc";
const char *str5 = "abc";
const char *str6 = "abc";
char *str7 = "abc";
char *str8 = "abc";
cout << ( str1 == str2 ) << endl;
cout << ( str3 == str4 ) << endl;
cout << ( str5 == str6 ) << endl;
cout << ( str7 == str8 ) << endl;
结果是:0 0 1 1
解答:
str1,str2,str3,str4是数组变量,它们有各自的内存空间;此时的数组名,实际上是两个分别指向数组起始元素的指针。
而str5,str6,str7,str8是指针,它们指向相同的常量区域。
4、下面的C程序是合法的吗?如果是,那么输出是什么? //Ps
#include <stdio.h>
int main()
{
int a=3, b=5;
printf(&a["Ya!Hello! what is this? %s\n"], &b["junk/super"]);
printf(&a["WHAT%c%c%c %c%c %c !\n"],
1["this"],2["beauty"],0["tool"],0["is"],3["sensitive"],4["CCCCCC"]);
return 0;
}
参考答案:本例是合法的,输出如下:
Hello! what is this? super
That is C !
本例主要展示了一种另类的用法。下面的两种用法是相同的:
"hello"[2] 2["hello"]
如果你知道:a[i] 其实就是 *(a+i)也就是 *(i+a),所以如果写成 i[a] 应该也不难理解了。
5、要对绝对地址0x100000赋值,我们可以用*(unsigned int*)0x100000 = 1234;那么要是想让程序跳转到绝对地址是0x100000去执行,应该怎么做?
答:
((void (*)())0x100000)();
首先要将0x100000强制转换成函数指针,即:
(void (*)())0x100000
然后再调用它:
((void (*)())0x100000)();
用typedef可以看得更直观些:
typedef void (*voidFuncPtr)();
((voidFuncPtr)0x100000)();
6.结构体:
结构体成员对齐规则:
1.每一个成员的起始地址必须是某个数的倍数。(这个数是cpu字长和成员自身大小之间的 最小值)
2.结构体整体大小必须是最大成员和cpu字长两者之间最小值的倍数。
struct' node{
int a;
char b;
char c;
int d;
int e;
}
struct node s={3,4,5,6};
struct node*p=&s;
printf("%d",(int*)p+3); //0
7.数组指针
static void test2()
{
int a[] = { 1, 2, 3, 4, 5 };
int *p = (int*)(&a + 1); //&a的类型是int (*)[5], &a指向的类型是int [5]
printf("%d %d\n", *(a + 1), *(p - 1)); //2 5
}
8.strcpy
试题2: //ps:(注意)
void test2()
{
char string[10], str1[10];
int i;
for(i=0; i<10; i++){
str1[i] = 'a';
}
strcpy( string, str1 );
printf("%s", string);
}
解答:
由于str1末尾没有'\0'结束标志,所以strcpy不知道拷贝到何时结束, 因此陷入死循环;
strcpy( char *s1,char *s2)的工作原理是,扫描s2指向的内存,逐个字符复制到s1所指向的内存,直到碰到'\0',因为str1结尾没有'\0',所以具有不确定性,不知道后面还会复制什么内容。
printf函数,对于输出char* 类型,顺序打印字符串中的字符直到遇到空字符('\0')或已打印了由精度指定的字符数为止。
如果面试者指出字符数组str1不能在数组内结束可以给3分;如果面试者指出strcpy(string, str1)调用使得从str1内存起复制到string内存起所复制的字节数具有不确定性可以给7分,在此基础上指出库函数strcpy工作方式的给10分