一些易错的题目及扩充问题(书没看完,陆续更新)

//摘自某书

//p33
#include <stdio.h>
int main(int argc,char *argv[])
{
	int b=3;
	int arr[]={6,7,8,9};
	int *ptr=arr;
	*(ptr++)+=123;
	printf("%d,%d\n",*ptr,*(++ptr));
}
printf("%d,%d\n",*ptr,*(++ptr));
00A613E7  mov         eax,dword ptr [ebp-30h]  
00A613EA  add         eax,4  //先计算++ptr,ptr指向8
00A613ED  mov         dword ptr [ebp-30h],eax  
00A613F0  mov         esi,esp  
00A613F2  mov         ecx,dword ptr [ebp-30h]  
00A613F5  mov         edx,dword ptr [ecx]  
00A613F7  push        edx  
00A613F8  mov         eax,dword ptr [ebp-30h]  
00A613FB  mov         ecx,dword ptr [eax]  
00A613FD  push        ecx  
00A613FE  push        offset string "%d,%d\n" (0A65740h)  
00A61403  call        dword ptr [__imp__printf (0A682B0h)]  
00A61409  add         esp,0Ch  
00A6140C  cmp         esi,esp  
00A6140E  call        @ILT+295(__RTC_CheckEsp) (0A6112Ch)  

printf("%d,%d\n",*ptr,*(ptr++));
013413E7  mov         eax,dword ptr [ebp-30h]  
013413EA  mov         ecx,dword ptr [eax]  
013413EC  mov         dword ptr [ebp-0F8h],ecx  
013413F2  mov         edx,dword ptr [ebp-30h]  
013413F5  add         edx,4  
013413F8  mov         dword ptr [ebp-30h],edx  
013413FB  mov         esi,esp  
013413FD  mov         eax,dword ptr [ebp-0F8h]  
01341403  push        eax  
01341404  mov         ecx,dword ptr [ebp-30h]  
01341407  mov         edx,dword ptr [ecx]  //保存的是7
01341409  push        edx  
0134140A  push        offset string "%d,%d\n" (13457A8h)  
0134140F  call        dword ptr [__imp__printf (13482B0h)]  
01341415  add         esp,0Ch  
01341418  cmp         esi,esp  
0134141A  call        @ILT+295(__RTC_CheckEsp) (134112Ch)  

*(ptr++)+=123;
011C13D1  mov         eax,dword ptr [ebp-30h]  
011C13D4  mov         ecx,dword ptr [eax]  
011C13D6  add         ecx,7Bh  
011C13D9  mov         edx,dword ptr [ebp-30h]  
011C13DC  mov         dword ptr [edx],ecx  
011C13DE  mov         eax,dword ptr [ebp-30h]  
011C13E1  add         eax,4  
011C13E4  mov         dword ptr [ebp-30h],eax  

//p34内存截断
#include <iostream>
using namespace std;
int main(int argc,char *argv[])
{
	float a=1.0f;
	cout<<(int)a<<endl;
	cout<<&a<<endl;
	cout<<(int&)a<<endl;//相当于将浮点数地址开始的sizeof(int)个字节当成int型数据输出,取决于float在内存中的存储方式
}

//p44
//易错的宏定义
#include <iostream>
using namespace std;
#define SUB(x,y) x-y
#define ACCESS_BEFORE(element,offset,value) *SUB(&element,offset)=value
int main(int argc,char *argv[])
{
	int i;
	int array[10]={1,2,3,4,5,6,7,8,9,10};
	//ACCESS_BEFORE(array[5],4,6);//宏展开后是*&array[5]-4=6;此时*&array[5]为常值6,为不可修改左值,编译错误
	//修改:把#define SUB(x,y) x-y修改为:#define SUB(x,y) (x-y)
	for (int i=0;i<10;i++)
	{
		cout<<array[i];
	}
	return 0;
}

//p47 const int *a=&b;
//不允许通过指针a修改b,可以直接对b操作修改b,可以把a指向别的数据
#include <iostream>
using namespace std;
int main(int argc,char *argv)
{
	int b=500;
	const int *a=&b;
	cout<<*a<<endl;
	int c=600;
	a=&c;
	cout<<*a<<endl;
}

//p55 sizeof
/*
1.char *ss1="0123456789"; sizeof(ss1)=4;//ss1是一个字符指针
2.char ss2[]="0123456789";sizeof(ss2)=11;//ss2是字符数组,且末尾加'\0'
3.static静态常量存放在全局数据区,sizeof是计算栈中分配的大小,不会把static计算在内
4.int **a[3][4];sizeof(a)=48;a为一个数组;
  int (**a)[3][4];sizeof(a)=4;a为一个指针;
5.sizeof不是函数,也不是一元运算符,二是类似于宏的特殊关键字,括号内的内容在编译过程
中不被编译
6.类有虚函数(不管是自己的还是继承而来的),那么类中就有一个vptr指向vtable,类的大小为
size+4*(vptr的个数n)//n取决于继承分支
*/
#include <iostream>
using namespace std;
class A
{
public:
<span style="white-space:pre">	</span>static int array[1024][1024];
protected:
private:
};
int main(int argc,char *argv[])
{
<span style="white-space:pre">	</span>cout<<sizeof(A)<<endl;//1
<span style="white-space:pre">	</span>static int B[1024][1024];//1024*1024*4
<span style="white-space:pre">	</span>cout<<sizeof(B)<<endl;
}

//p57指针数组还是数组指针的问题

#include <iostream>
using namespace std;
int main(int argc,char *argv[])
{
	int *a[5];//a指针数组
	int (*b)[5];//b数组指针
	cout<<sizeof(a)<<" "<<sizeof(b)<<endl;
	int** c[3][4];//c为指针数组
	cout<<sizeof(c)<<endl;
}

//p71.补充虚函数的情况
#include <iostream>
using namespace std;

class A
{
public:
	A(){m_a=11;m_b=12;}
	~A(){}
	void fun1(){cout<<m_a<<" "<<m_b<<endl;}
	virtual void fun2(){cout<<"A::fun2()"<<endl;}
protected:
public:
	int m_a;
	int m_b;
};

class B:public A
{
public:
	B(){m_a=21;m_b=22;m_c=23;}
	~B(){}
	void fun3(){cout<<m_c<<endl;}
	virtual void fun2(){cout<<"B::fun2()"<<endl;}
protected:
public:
	int m_c;
};


int main(int argc,char *argv[])
{
	A a;
	cout<<&a<<endl;//002BFBFC
	cout<<&(a.m_a)<<endl;
	printf("%p\n",&A::m_a);//00000004
	printf("%p\n",&A::m_b);//00000008

	printf("%p\n",&B::m_a);//00000004
	printf("%p\n",&B::m_b);//00000008
	printf("%p\n",&B::m_c);//0000000C
	
	B *pb=(B*)&a;//不安全的,把基类对象转换为子类对象时不自然的,此时pb指向a,而编译器对m_c的认识是m_c距离对象偏移量为0C,于是打印了a首地址编译量为002BFBFC+0C的变量值
	pb->fun3();
}

//p72构造顺序问题
#include <iostream>
using namespace std;
class A
{
public:
	int _a;
	A()
	{
		cout<<"A::A()"<<endl;
		_a=1;
	}
	void print()
	{
		printf("%d\n",_a);
	}
protected:
private:
};

class B:public A
{
public:
	int _a;
	B()
	{
		cout<<"B::B()"<<endl;
		_a=2;
	}
};


int main(int argc,char *argv[])
{
	B b;
	b.print();
	printf("%d\n",b._a);
}

//p73
#include <iostream>
using namespace std;
struct S
{
	int i;
	int *p;
};
int main(int argc,char *argv[])
{
	S s;
	int *p=&s.i;
	p[0]=4;
	p[1]=3;
	s.p=p;//s.p指向s.i
	s.p[1]=1;//s.p[1]即为s.p本身,即s中的指针的值为1
	s.p[0]=2;//*(int*(1))=2,对为声明的地址直接访问,出错
}

//p81
句柄与指针
句柄是一个32位整数,实际上是window在内存中维护的一个对象(窗口等)内存物理地址列表的整数索引
因为window内存管理经常会将空闲对象内存释放,当需要的时候再重新提交到物理内存,所以对象的物理地址
是变化的,不允许程序直接通过物理地址访问对象。程序将想访问对象的句柄传给系统,系统根据句柄维护
检索自己维护的对象列表就能知道知道想访问的对象的物理地址了。
句柄是一种指向指针的指针。
句柄地址(稳定)->记录对象在内存中的地址->对象在内存中的地址(不稳定)->实际对象
Conclusion:
句柄和指针其实是两个截然不同的概念,window系统用句柄标记系统资源,隐藏系统信息。指针则是标记某个物理内存地址

//p90.非递归实现f(m,n)=f(m-1,n)+f(m,n-1),m>1,n>1
//类似于背包问题
#include <iostream>
using namespace std;
//递归
int f_recursion(int m,int n)
{
	if (m==1)
	{
		return n;
	}
	else if (n==1)
	{
		return m;
	}
	else
	{
		return f_recursion(m-1,n)+f_recursion(m,n-1);
	}
}
//非递归矩阵
int f_not_recursion(int m,int n)
{
	//简单版本
	int **array=new int* [m];
	for (int i=0;i<n;i++)
	{
		array[i]=new int[n];
		memset(array[i],0x00,sizeof(array[i]));
	}
	//初始化
	for (int i=0;i<m;i++)
	{
		array[i][0]=i+1;//第一列
	}
	for (int j=0;j<n;j++)
	{
		array[0][j]=j+1;//第一列
	}
	//进行计算
	for (int i=1;i<m;i++)
	{
		for (int j=1;j<n;j++)
		{
			array[i][j]=array[i-1][j]+array[i][j-1];
		}
	}
	int retval=array[m-1][n-1];
	delete []array;
	return retval;
}
//非递归数组
int f_not_recursion_s(int m,int n)//节省存储空间
{
	//利用row和rank来存放上一次的运算结果
	int *row=new int[n];//每一行有n列
	int *rank=new int[m];//每一列有m行
	//初始化
	for (int i=0;i<m;i++)
	{
		rank[i]=i+1;
	}
	for (int j=0;j<n;j++)
	{
		row[j]=j+1;
	}
	int retval=0;
	//进行计算
	int pre_row;
	int pre_rank;
	for (int i=1;i<m;i++)
	{
		for (int j=1;j<n;j++)
		{
			retval=row[j]+rank[i];
			rank[i]=retval;
			row[j]=retval;
		}
	}
	delete[]row;
	delete[]rank;
	return retval;
}

int main(int argc,char *argv)
{
	cout<<f_not_recursion(10,20)<<endl;
	cout<<f_not_recursion_s(10,20)<<endl;
	cout<<f_recursion(10,20)<<endl;
}
//p97素数问题
#include <math.h>
#include <string>
#include <iostream>
using namespace std;
class LessThanTwo
{
public:
		static string msg;
protected:
private:
};
string LessThanTwo::msg="num is less than 2";
bool judge(int num)
{
	if (num<2)
	{
		throw LessThanTwo();
	}
	else
	{
		int i,j;
		for (i=2;i<=num;i++)
		{
			for (j=2;j<=sqrt(double(i));j++)
			{
				if (i%j==0)
				{
					break;
				}
			}
			if (j>sqrt(double(i)))
			{
				cout<<i<<" ";
			}
		}
	}
}
int main(int argc,char *argv[])
{
	try
	{
		judge(4);
	}
	catch (LessThanTwo& e)
	{	
		cout<<e.msg<<endl;
	}

}

//p102.深浅拷贝问题

#include <vector>
#include <iostream>
using namespace std;
class CDemo
{
public:
	CDemo():str(NULL){};
	CDemo(const CDemo& copy)//定义拷贝构造函数
	{
		str=new char[strlen(copy.str)+1];
		strcpy(str,copy.str);
	}
	~CDemo()
	{
		if (str)
		{
			delete[]str;
			str=NULL;
		} 
	}
	char *str;
protected:
private:
};
int main(int argc,char *argv[])
{
	CDemo d1;
	d1.str=new char[32];
	strcpy(d1.str,"keiko test");
	vector<CDemo> *a1=new vector<CDemo>();
	a1->push_back(d1);
	delete a1;
}


//虚析构函数问题

#include <iostream>
using namespace std;
class Base
{
public:
	Base()
	{
		cout<<"Base::Base()"<<endl;
	}
	virtual ~Base()//去掉vitual 关键字进行测试
	{
		cout<<"Base::~Base()"<<endl;
	}
};
class Derived:public Base
{
public:
	Derived()
	{
		cout<<"Derived::Derived()"<<endl;
		ptr=NULL;
	}
	virtual ~Derived()//去掉vitual 关键字进行测试
	{
		cout<<"Derived::~Derived()"<<endl;
		cout<<"delete []ptr"<<endl;
		if (ptr!=NULL)
		{
			delete []ptr;
			ptr=NULL;
		}
	}
public:
	int *ptr;
};


int main(int argc,char *argv[])
{
	Derived *pd=new Derived;
	pd->ptr=new int[100];
	Base *pc=pd;
	delete pc;//如果不是虚析构函数将导致静态联编,导致子类析构函数不会被调用,从而内存泄漏
}

/*
引申:
1.构造函数不能为virtual型。
虚函数采用一种虚调用的方法,虚调用是一种可以在只有部分信息情况下工作的机制,特别允许我们调用一个只知道
接口而不知道其准确对象类型的函数。但是如果要创建一个对象,必须知道对象的准确类型,因而构造函数不能为虚的。
*/


//p119 常考:构造函数,析构函数,拷贝构造函数,赋值函数

#include <iostream>
using namespace std;
class String
{
public:
	String(const char *str=NULL)
	{
		if (str==NULL)
		{
			m_str=new char[1];
			*m_str='\0';
		}
		else
		{
			m_str=new char[strlen(str)+1];
			strcpy(m_str,str);
		}
	}
	~String()
	{
		if (m_str!=NULL)
		{
			delete []m_str;
			m_str=NULL;
		}
	}
	String(const String& copy)//复制构造函数 
	{
		m_str=new char[strlen(copy.m_str)+1];
		strcpy(m_str,copy.m_str);
	}
	String& operator=(const String& other)
	{
		if (this==&other)
		{
			return *this;
		}
		else
		{
			//释放原空间
			delete []m_str;
			m_str=new char[strlen(other.m_str)+1];
			strcpy(m_str,other.m_str);
			return *this;
		}
	}
	friend ostream& operator<<(ostream&os,const String &str)
	{
		os<<str.m_str;
		return os;
	}
protected:
private:
	char *m_str;
};
int main(int argc,char *argv[])
{
	String str1("hello");//构造函数
	cout<<str1<<endl;
	String str2(str1);//拷贝构造函数
	cout<<str2<<endl;
	String str3=str1;//赋值函数
	cout<<str3<<endl;
	const String str4("the world");
	cout<<str4<<endl;
	String str5=str4;
	cout<<str5<<endl;
}

//p125多态的概念
/*
1.多态:一种接口多种实现,允许将父对象设置为和他的一个和多个子对象相等的技术,赋值之后
父对象根据当前赋值给他的子对象的特性以不同的方式运作;
2.只要不是晚绑定的就不是多态;
3.封装可以实现隐藏细节,使得代码模块化;继承可以扩展已存在的代码模块;封装和继承均为了代码重用
而多态为了接口重用。*/




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值