//摘自某书
//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.封装可以实现隐藏细节,使得代码模块化;继承可以扩展已存在的代码模块;封装和继承均为了代码重用
而多态为了接口重用。*/