.第04章 CORE C++_指针(II)_动态内存_引用_类_对象_构造函数_析构函数

1.问题:输出数列的存储空间(是一个数据的空间大小)

   思路1:直接调用数组,sizeof(数组名)

   思路2:通过指针调用数组,sizeof(数组名)

   代码1:#include<iostream>  
            using namespace std;

            int main()   
            {   
               int num[5]={3,4,5,6,7};

               cout<<sizeof(num)<<endl;
            }  

   代码2:#include<iostream>  
            using namespace std;   
            int length(int a[],int n)
            {
               cout<<sizeof(a)<<endl;
            }
            int main()   
            {   
               int num[5]={3,4,5,6,7};

               length(num,5);  
            }  

   解释:1.sizeof后面是整个数组,就一定是20个字节 

            2.sizeof后面是个指针,就一定是4个字节 

2.问题:字符‘$’的对应指针变量作为输出时,应该输出什么了?答:$开头的不确定值。为什么?

   思路:无

   代码::#include<iostream>  
            using namespace std; 

            int main()   
            {   
               char c='$';

               char* p=&c;

               cout<<p<<endl;
            }  

   解释:只要字符是地址,到遇到/0为止,而看不出了,到哪遇到不知道。所以输出的是以$开头的不确定值???

3.问题:指针调用字符串,输出指针变量值和16进制数据

   思路:1.用字符指针输出字符串

            2.输出指定字符串的所占数据空间

            3.指定指针变量后,输出指针变量值及其16进制数据

   代码:#include<iostream>   
            using namespace std;   
            int main()   
            {   
               cout<<"hello, 秀秀!"<<endl;//直接用的字符串常量会自动分配空间来放, 自动分配一个无名数组。这个数组很可能分配在只读存储器中。  
               char name[20]="明男";   
               char* mm=name;// 指针中只能保存地址  
               cout<<"hello,"<<mm<<"!"<<endl;//只是个首地址,为什么输出的却是数组???   
               cout<<sizeof("hello")<<endl;//因为数组末尾有‘/0’ ,所以5+1=6  
               const char* p="hello";// 在用指针访问常量的时候别忘了const   
               cout<<*p<<endl;// 也可以p[0]   
               // *p='H';// 段错误  
               cout<<(void*)p<<endl;  //这是16进制什么数??? 
            }

   解释:段错误:对内存空间进行了非法访问

4.问题:拷贝添加字符至原来字符之后并输出

   思路:1.定义形参为字符常量指针,返回值为整型,计算字符个数的子函数

            2.定义形参为目标指针和字符常量指针,返回值为目标指针,挨个复制字符的子函数

            3.定义形参为目标指针和字符常量指针,返回值为目标指针,复制添加字符常量至目标指针的子函数

   代码:#include<iostream>   
            using namespace std;   
            int Strlen(const char* str)   
            {   
               int cnt=0;   
               while(*str++!='/0')//先计算str++然后算*str++,*str++!='/0'   
                   ++cnt;//最后退出时,这里是到'/0'之前的字符个数   
               return cnt;   
            }   
            char* Strcpy(char* dst,const char* src)// 前面的需要加入数据,后面的只需要读就可以,所以确定有无const.   
            {   
               char* save=dst;   
               while((*dst++=*src++)!='/0');//; 代表空语句。挨个复制,直到/0 为止???不等价*dst=(*dst)+(*src++)  
               return save; //程序的返回值会保存到char* dst  
            }   
            char* Strcat(char* dst,const char* app)   
            {   
               Strcpy(dst+Strlen(dst),app);   
               return dst;   
            }   
            int main()   
            {   
               cout<<Strlen("hello")<<endl;   
               char buf[100];   
               Strcpy(buf," 早上好!");   
               cout<<buf<<endl;   
               Strcat(buf," 明男!");   
               cout<<buf<<endl;   
            }

   解释:处理字符串往往用字符指针来做字符串的处理 
            字符串常量的准确类型是const char*  

            比较字符串实际就是比较ASCII码的,正数表示前面的大,负数表示前面的小,0表示两个字符串相等

5.问题:用序号:人名的格式,输出人名

   思路:用指针++方式

   代码:#include<iostream>   
            using namespace std;     
            int main()   
            {   
               char* vip[6]={" 刘哲","刘晓梅","李孛孛","张明月","廖作祥","屈艳丽"};   
               for(int i=0;i<6;i++)   
                  cout<<i+1<<':'<<vip[i]<<endl;// 不能用i++     
            }

   解释:为什么不能定义为普通字符数组输出呢???

6.问题:不能用野指针

   思路:无

   代码1:#include<iostream>   
            using namespace std;     
            int main()   
            {   
               char* name;// 野指针

               cout<<" 请输入姓名:";   
               cin>>name;   
               cout<<name<<endl;       
            }

   代码2:#include<iostream>   
            using namespace std;     
            int main()   
            {   
               char* name=NULL;

               char buf[100];  
               name=buf;  

               cout<<" 请输入姓名:";   
               cin>>name;   
               cout<<name<<endl;       
            }

   解释:1.结果是段错误,因为野指针指向不确定

            2.为改正后程序

7.问题:输出命令行上字符串的个数,命令行上的那些字符串 

   思路:对主函数设置字符类型形参和数组指针形参

   代码:#include<iostream>  
            using namespace std;  
            int main(int argc,char* argv[])   //能否把形参改成字符数组???
            {  
            cout<<"argc="<<argc<<endl;  
            cout<<"argv[0]="<<*argv<<endl; //为什么显示所有数组内容??? 
            for(int i=0;i<argc;i++)  
               cout<<i<<'"'<<argv[i]<<endl;   
            for(int i=1;i<argc;i++)  
               cout<<i<<" 感谢你,"<<argv[i]<<"!"<<endl;  

            }

   解释:无
8.问题:两个数字(字符型)相加

   思路1:???编译也???

   思路2:把字符数组转换为整型数值,然后进行相加

   代码1:#include<iostream>  
            using namespace std;   
            int str2int(const char* str)  
            {  
               int num=0;  
               for(int i=0;i<strlen(str);i++)  
               {  
                  num*=10;  
                  num+=str[i]-'0';  
               }  
               return num;  
            }  
            int main()  
            {   
               char s1[]="1395";  
               char s2[]="30182";  
               cout<<str2int(s1)+str2int(s2)<<endl;  
            }   

   代码2:#include<iostream>  
            using namespace std;  
            int s2i(const char* str)  
            {  
               int num=0;  
               while(*str!='/0')  
                  num=num*10+*str++-'0'; //什么意思??? 
               return num;  
            }  
            int main()  
            {  
               char s1[]="1395";  
               char s2[]="30182";  
               cout<<s2i(s1)+s2i(s2)<<endl;  
            }  

   解释:无语

9.问题:动态内存使用方法  

   思路:1.声明

            2.初始化,默认为0

            3.使用内存

            4.归还内存

   代码:#include<iostream>  
            using namespace std;    
            int main()  
            {   
                double* p1=new double;//p1 在栈中,4个字节;默认初始化 
                cout<<"*p1="<<*p1<<endl;  
                cout<<"p1="<<p1<<endl;  
                cout<<"&p1="<<&p1<<endl;  
                double* p2=new double(3.5); //声明和初始化 
                cout<<"*p2="<<*p2<<endl;  
                cout<<"p2="<<p2<<endl;  
                cout<<"&p2="<<&p2<<endl;  
                int n=100;  
                double* p3=new double[n];  
                for(int i=0;i<n;i++)  
                   p3[i]=i*0.1;  
                for(int i=0;i<n;i++)  
                   cout<<p3[i]<<' ';  
                cout<<endl;  
                delete p1;p1=NULL;// 归还空间 
                delete p2;p2=NULL;    
                delete[] p3;p3=NULL;

            }

   解释:动态内存:用指针来管理内存。两类:栈:stack 自动收回;堆:heap 不自动收回

            动态内存是在堆区(heap)中开辟空间,不受作用范围限制  
            内存泄露:申请之后却无法使用的内存  memory leak   
            new的数据无法初始化。(  )  表示赋值;[  ]  表示数组  
            delete 归还空间:归还的是new的空间而不是指针指向的空间。格式:delete+地址  
            new和delete配对使用(有借有还);  
10.问题:如果new一个大的空间的时候,检查一下是否成功  
   思路:判断指针是否为空

   代码:#include<iostream>   
            using namespace std;   
            #include<new>   
            int main()   
            {   
               int* p=new(nothrow) int[~0];// 注意nothrow,是什么意思???   
               cout<<"p="<<p<<endl;   
               if(p==NULL)//if(NULL==p) 也可以  
                  cout<<" 不成功"<<endl;   
               else{   
                  cout<<" 成功了"<<endl;   
                  delete[] p;p=NULL;   
               }   
            }   
   解释:无
11.问题:引用的定义

   思路:别名

   代码:#include<iostream>   
            using namespace std;   
            int main()   
            {   
               int n=100;   
               int& r=n;//& 表示别名,不是地址。表明:r是n的别名  
               cout<<"&n="<<&n<<endl;   
               cout<<"&r="<<&r<<endl;   
               int& m=r;// 别名的别名 同一个变量同一类型  
               m=300;   
               cout<<"n="<<n<<endl;   
            }

   解释:引用:给一个变量另起一个名字 

12.问题:引用用于形参 
   思路:无

   代码:void squre(int& r)   
            {   
               r*=r; //等价于r=r*r;  
            }  

             void squre(int* p)// 指针类型  
            {   
               *p*=*p;   
            }   
            int main()   
            {   
               int n=100;   
               squre(n);   
               cout<<"n="<<n<<endl;  

               squre(&n);   
               cout<<"n="<<n<<endl;   
            }  

   解释:引用多用于形参;函数的重载,没有关系 
13.问题:用别名,设计计数器

   思路:无形参,调用一次累加一次

   代码:#include<iostream>   
            using namespace std;   
            int& counter()//是个别名,意思是int& x=n;   
            {   
               static int n=0;// 静态static   
               ++n;   
               return n;   
            }   
            int main()   
            {   
               cout<<counter()<<endl;   
               cout<<counter()<<endl;   
               cout<<counter()<<endl;   
               counter()=10;// 代表n的别名  
               cout<<counter()<<endl;   
               cout<<counter()<<endl;   
               cout<<counter()<<endl;   
            }

   解释:把临时空间或者常量传给引用时,要求常量有const

14.问题:定义类的格式

   思路:class 类名{  
 数据成员定义:// 类似结构 
 函数成员定义:可以直接使用数据成员,不需要再定义 
 也可以直接调用函数成员包括自己(递归)  
 };

   代码:#include<iostream>  
using namespace std;  
//定义类
#include<string> 
class Person{  
string name;  
bool gender;  
int age;  
public:// 别忘:号 
void birth(string n,bool g){  
name=n;  
gender=g;  
age=0;  
}  
void grow(int year){  
age+=year;  
}  
void show(){  
cout<<" 我是"<<(gender?"帅哥":"美女")<<name<<", 今年"<<age<<"> 岁."<<endl;}  
};//别忘了;号 
int main()  
{ // 定义对象(也就是变量) 
Person lz;  
Person qyl;  
lz.birth("刘哲",true);  
qyl.birth(" 屈艳丽",false);  
lz.grow(25);// 使用对象 
qyl.grow(22);  
lz.show();  
qyl.show();  
}  


   解释:1.OOAD: 面向对象分析/设计;object_oriented  简称“OO“  
           OOP:面向编程    
         2.结构:相关的内容打包在一起  封装的思想  数据 
函数:相关的语句打包在一起  也是一个封装  代码 
类:把数据和操作的函数全部封装在一起  class 面向对象的基础 
传统的说法:封装是面向对象的第一步  抽象 
类里面可以对成员进行访问限制  
         3.数据成员和函数成员的顺序随意 
class 访问限制,默认为私有,不允许从外面访问 
私有 private: 公开public: 带:号数据成员:data member  
函数成员:member function ( 有时翻译成成员函数)
习惯上: 数据成员private,而函数成员public
15.问题:编写一个时钟程序
思路:1.预编译,调入一个时钟头文件
      2.定义时间类:数据成员为时,分,秒;
                    函数成员为:设置时,分,秒;
                                到了60秒了,从0秒开始,这是到了60分,从0分开始,这是到了24时,从0时开始;
                                获取时;获取分;获取秒;
      3.定义时钟类:数据成员为 时间类的对象,即现在时间;
                    函数成为为:判断时,分,秒,即根据指定时间,设置时,分,秒;
                                等待1秒,即获取现在时间,并同步更新;
                                时钟,即根据现在时间同步更新,并对时,分,秒循环计时;
                                执行,即执行时钟,并不断更新显示,一直执行;
                                显示时间:如果时为个位,填0输出,否则直接输出,如果分为个位,填0输出,否则直接输出,如果秒为

个位,填0输出,否则直接输出,并且让输出内容立即显示
      4.主函数:定义时钟类对象;这对象判断指定时间;这对象执行                            
代码:#include<iostream>  
#include<ctime>  
using namespace std;  
class Time{  
int hour;  
int min;  
int sec;  
public:  
void set(int h,int m,int s){  
hour=h;//是否为引用???  
min=m; //是否为引用??? 
sec=s; //是否为引用??? 
}  
void advance(){  
if(++sec>=60){  
  sec=0;  
  if(++min>=60){  
  min=0;  
  if(++hour>=24){  
  hour=0;  
  }  
  }  
 }   
}    
 int getHour(){  
 return hour;  
 }  
 int getMinute(){  
 return min;  
 }  
 int getSecond(){  
 return sec;  
 }  
};   
class Clock{//Clock类是否为Time类的子类???  
Time now;//now是否为对象???  
public:  
void adjust(int h,int m,int s){  
now.set(h,m,s);  
}  
void wait1second(){  
 long start=time(NULL);// 用来取得现在的时间,单位是秒 
 while(time(NULL)==start);//; 是个空语句,没有事可做//整个while结构是同步更新??? 
}   
void tick(){  
 wait1second();  
 now.advance();  
}   
void run(){  
for(;;){  
tick();  
showtime();  
}  
}  
void showtime(){  
 cout<<"/r/a";  
if(now.getHour()<10)  
cout<<'0';  
cout<<now.getHour()<<";";  
if(now.getMinute()<10)  
cout<<'0';  
cout<<now.getMinute()<<":";  
if(now.getSecond()<10)  
cout<<'0';  
cout<<now.getSecond()<<":";  
cout<<flush;// 表示让输出内容立即显示 
}  
};  
int main()  
{  
Clock c; //c是否为对象??? 
c.adjust(23,59,50);  
c.run();  
}  
解释:无
16.问题:要求写一个分数类,有分子分母,能设置分子分母,能够约分,能显示小数。比如,3/6约分=1/2=0.5;再,5/20约分=1/4=0.25。并

且进行加法运算(有待求精思路???)
思路:1.定义分数类:
代码:#include<iostream>  
using namespace std;  
class Fract{  
int _n;  
int _d;  
public:  
void set(int n,int d){//实为构造函数的功能  
_n=n;  
_d=d;  
reduce();  
}  
/*构造函数
Fract(int n,int d)  
:n(n),d(d)// 注意别忘了‘:‘  
{  
reduce();  
}
*/
 void show(){// 注意不用传参,直接访问即可 
 cout<<_n<<'/'<<_d<<endl;  
 }  
 void reduce(){// 求约数 
 int absn=_n>0?_n:-_n;// 求分子绝对值 
 int absd=_d>0?_d:-_d;// 求分母绝对值 
 int div=absn<absd?absn:absd;// 找分子分母之间最小的数 
 while(div>1){  
 if(_n%div==0&&_d%div==0)// 分子分母同时整除的约数 
 break;  
 --div;// 找最大的约数 
 }  
 if(div!=0){// 如果约数不等于0  
 _n/=div;//分子除以最大的约数 
 _d/=div;//分母除以最大的约数 
 }  
 }  
 void showvalue(){  
 cout<<(double)_n/_d<<endl;// 先转换 
 }  
 Fract add(Fract f){// 求两个分数的和 
 Fract res;  
 res.set(_n*f._d+_d*f._n,_d*f._d);// 形同数学表达式 
 return res;  
 }  
};    
int main()  
{  
Fract f1,f2;  
f1.set(3,6);  
f2.set(5,20);  
f1.show();  
f1.showvalue();  
f2.show();  
f2.showvalue();
f1.add(f2).show();    
}  
补充:1.上面的程序如果是输入分数: 
void set(){ cout<<"input fraction:";  
cin>>_n>>_d;  
reduce(); }  
2.如果输入分数线:  
void set(){  
cout<<"input fraction(n/d):";  
char ch;// 因为'/'是个字符 
cin>>_n>>ch>>_d;  
reduce();  
}  
解释:1.在这里没有考虑分母为零的情况,如果用就需要输出错误
2.this在成员函数中,指向当前变量的指针:this->n=n; 或者Fract::n=n; this->d=d; 或者Fract::d=d;  
上面程序中的_n _d 去掉_应该做的:成员运算符发生冲突 
3.构造函数(constructor):在一个函数创建的时候,自动调用的函数,构造函数的函数名必须和类名相同。如void Fract(int n,int d)。
4.构造函数不写返回类型,因为它带不回什么东西的。如Fract(int n,int d)  
5.创建对象时传递的参数只保证传到构造函数的形参,要想传到成员变量必须写代码。构造函数最适用于为对象作后期工作。大多数时候,构

造函数做数据成员的初始化。
6.初始化列表格式::数据成员(初始数据),数据成员2( 初始数据),....  
7.在创建一个对象总是只调用一个构造函数,如Fract():n(0),d(1)。默认构造函数什么都不做,摆设而已。 
17.问题:用析构函数释放动态内存和占用内存
思路:1.定义类,构造函数,析构函数,一个成员函数。
2.对指定对象执行1次构造函数;然后执行指定对象的函数成员;对指定对象数组执行3次构造函数;
3.申请动态类的内存数组,对象数组执行2次构造函数;
4.这样首先执行动态数组析构函数2次;发现程序终结符‘}’,执行对应的其他构造函数,自动执行析构函数4次。
代码:#include<iostream>  
using namespace std;  
class Printer{  
public:  
Printer(){  
cout<<this<<"printer initializing..."<<endl;  
}  
~Printer(){  
cout<<"printer poweroff"<<endl;  
}  
void print(int pages){  
cout<<"print"<<pages<<"papers"<<endl;  
}  
};  
int main()  
{  
Printer p;//对象  
p.print(8);//调用指定对象的成员函数  
Printer a[3]; //对象数组 
cout<<"-------------"<<endl;  
Printer* x=new Printer[2];//动态内存  
delete[] x;x=NULL;//new 是个数组时,delete的时候一定要带[]; 
cout<<"-------------"<<endl;//为什么析构函数执行6次??? 
}  
解释:析构函数:~类名(),主要用于动态内存释放时的 
如果你不写,系统会给你创建一个默认的析构函数,什么都不做。总是无参的、不可以重载、没有返回类型、一般由系统调用的

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值