关于C++的基础易错知识(源于各种笔试题,自己要记得不断更新)

   1、关于指针分配内存的题目:

void GetMemory(char *p)  
{  
    p = (char *)malloc(12);  
}  
  
int main(void)  
{  
    char *str = "Hello";  
    GetMemory(str);  
    strcpy(str,"Hello World");  
    printf("%s",str);  
    return 0;  
}

    这个题目在VS2010下是运行时报错,首先忽略malloc(11)本身就放不下"Hello World"的问题,关键str是个const char*,因为其指向的是"Hello",人家是存在静态常量存储区的,所以是不可以将str作为strcpy的第一个参数的,若是char str = “Hello”;则是可以的;其次,GetMemory函数没有起到为str分配内存的作用,因为传进去的是str,而并非str的地址,所以在GetMemory中对p的操作并没有真正改变str,so程序应该改成:


void GetMemory(char **p)  
{  
    *p = (char *)malloc(12);  
}  
  
int main(void)  
{  
    char *str = "Hello";  
    GetMemory(&str);  
    strcpy(str,"Hello World");  
    printf("%s",str);  
    return 0;  
} 


2、关于数组名字做左值的问题

void main()  
{  
    char s[] = "abcde";  
    s += 2;  //编译错误
    printf("%c\n",s[0]);  
} 


     数组和指针的一个很重要的区别就是数组名字是不能改变的,即不能做左值,so将char s[]改成char* s就OK了。


3、二维数组的存储方式

int main(void)  
{  
    char matrix[3][3]={{'a','b','c'},{'d','e','f'},{'g','h','i'}};  
    printf("%c",matrix[1][4]);  
    return 0;  
}  


    二维数组分行优先和列优先两种存储方式,在C++中是采用行优先的,所以第i+1行是紧接着第i行线性存储的,所以输出的是h。


4、C++的析构函数为虚函数

    记住:构造函数不能是虚函数!

    经常遇到的题目,特别是选择题问输出结果的,有一句话很重要:如果基类存在虚函数,那么析构函数必须为虚函数!!

    当基类指针指向子类的对象时,若析构函数不是虚函数,则最后只调用基类的析构函数,这会造成内存泄露!


2014.05.12 

    果然没事看CSDN牛人的博客是受益匪浅的,最近看STL的时候无意中看到:

博客

    其中实在不明白最后三组的结果:

  1. const int x = 50;  
  2.     int* y = (int *)(&x);       // 同样的地址,但是内容是不一样的  
  3.     *y = 200;  
  4.     cout << "x: "<<x<<" address: "<<&x<<endl;  
  5.     cout << "*y: "<<*y<<" address: "<<y<<endl;  
  6.     cout<<endl;  
  7.       
  8.     const int xx = 50;  
  9.     int* yy = const_cast<int *> (&xx);     // 同样的地址,但是内容是不一样的  
  10.     *yy = 200;  
  11.     cout << "xx: "<<xx<<" address: "<<&xx<<endl;  
  12.     cout << "*yy: "<<*yy<<" address: "<<yy<<endl;  
  13.     cout<<endl;  
  14.     // int  
  15.     const int xxx = 50;  
  16.     int yyy = const_cast<int&> (xxx);     // yyy是另外一个int对象  
  17.     yyy = 200;  
  18.     cout << "xxx: "<<xxx<<" address: "<<&xxx<<endl;  
  19.     cout << "yyy: "<<yyy<<" address: "<<&yyy<<endl;  

    在我的电脑里结果如下:


    单步跟踪发现x的值确实发生了变化,但是为什么输出结果就是不对呢,在实验室同学的提醒下发现,万恶的编译器又进行了优化,故在const int x前加了volatile,当然最终x的值也是200了,但是输出的地址就是1,这就牵扯到另外一个知识了:ostream的operator<<有哪些:

    ostream 有 operator<<(const void*)  但是没有operator<<(volatile void*), 当 cout<<&x 时, 因为 &ix的类型是 volatile const int *,没有对应的operator<<(valatile int*)。
  重载解析选中的是 operator<<(std::_Bool) (见上面的警告)。
  又因为它们都不是空指针,所以总是true, 所以输出总是1。

    解决办法就是使用const_cast,这个强制转换符是专门用于const和volatile的,故:

    

cout<<const_cast<int*>(&x);

    但是又牵扯另一个问题了:char*

    operator<<会把char*类型当成要输出字符串,例如:

char* str = "aa";
cout<<str<<endl;

    结果就输出: aa

    故再次使用强制转换符:reinterpret_cast

cout<<reinterpret_cast<void *>(&str)<<endl;

    输出结果:0012FE2C

    在这其中,要注意以后书写输出时最后最好加endl,因为可以刷新输出,使结果立马显示到控制台。

    

    言归正传,那这个编译优化叫什么呢?常量重叠:

    所有用使用const 常量的地方将直接在编译时期替换成其对应的字符值。但常量有自己的内存,只是编译器优化了不知从内存中取值,而是直接是进行值代换。

    若想摆脱这种命运,还是尽量少用这些个强制类型转换符吧!

    最近看到了一个面试题,const在C++中的机制,所以对const又做了几个实验:

    

const int f = 10;
int main ()
{
	int* p = const_cast<int*> (&f);
	*p = 20;
	cout<<*p<<f<<endl;
	return 0;
}
    当f是全局变量时就无法进行修改,当定义为局部变量时还是在栈上,可以通过指针修改,但编译器只在预处理时读一次值,之后偷懒。

    如果是结构体类型的数据,编译器就不会做这种优化,因为不是内置类型,不知道如何替换。

    

int main ()
{
	struct test{
		int a;
	
		test()
		{
			a = 5;
		}
	};
	const test f;
	int* p = const_cast<int*> (&f.a);
	*p = 20;
	cout<<*p<<f.a<<endl;
	return 0;
}

    输出结果:2020

2014.05.19

    最近出差,木有好好学习,要好好准备软考!

    虚函数一定是public的,不然编译都通不过。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值