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次???
}
解释:析构函数:~类名(),主要用于动态内存释放时的
如果你不写,系统会给你创建一个默认的析构函数,什么都不做。总是无参的、不可以重载、没有返回类型、一般由系统调用的