第二周学习

来源:互联网 发布:网上装修设计软件 编辑:程序博客网 时间:2024/05/18 02:04

2.1函数指针

2.1.1定义

类型名(*指针变量名)(parameter 1, parameter 2…)
e.g:
int(*p)(int, char)

2.1.2使用方法

函数指针名(actual parameter list)

eg1:

#include <iostream>using namespace std;void outmin(int a,int b){a<b?cout<<a<<endl:cout<<b<<endl;}//条件运算符,问号前语句为真执行冒号前问号后语句,为假则执行冒号后语句int main(){    void(*p)(int,int)=outmin;    p(4,5);    return 0;}
返回值:4

eg2:

//qsor函数void qsort(void* base, int a, unsigned int width, int(*p)(const void*, const void*))//void qsort(数组起始地址,数组元素个数,每个元素大小,自定义大小规则)//自定义规则:如果返回值为负整数,则第一个元素在前,如果返回值是0,则相等,如果返回值是正整数,那么第一个元素在后。

eg3:

调用qsort,使数组按照个位数从小到大排序。

#include <iostream>using namespace std;int mycompare(const void* elem1,const void* elem2){    return *(int*)elem1%10-*(int*)elem2%10;//强制转换int*,然后比较个位数大小}int main(){    int an[]={8,123,11,10,4};    qsort(an,5,sizeof(int),mycompare);    for(int i=0;i<5;++i){        cout<<an[i]<<endl;    }    return 0;}
返回值:101112348

2.2位运算

2.2.1 按位于 &

将两操作数进行与操作,只有两者的相应二进制位皆为1时,结果为1.

eg1:

21&18
21二进制:   1010118二进制:   1001021&18二进制:10000(十进制16)

eg2:

判断一个int型变量n第七位是否为1

n & 0x80==0x80
0x80:10000000若两者相等则为1

2.2.2按位或 |

将两操作数进行或操作,只有两者的相应二进制位只要有一个为1时,结果为1.

eg:

21|18
21二进制:   1010118二进制:   1001021&18二进制:10111(十进制23)

2.2.3按位异或 ^

将两操作数进行异或操作,只有两者的相应二进制位不相同时,结果为1.

eg:

21^18
21二进制:   1010118二进制:   1001021&18二进制:00111(十进制7)

ps:

1.异或运算的特点”若a^b=c,则有c^b=a, c^a=b”可以用来最简单的解密加密。
2.可以实现不通过零时变量进行两个变量值的交换:

int a=5,b=7;a=a^b;b=b^a;a=a^b;

2.2.4按位非 ~

将一操作数进行非操作,0变成1,1变成0

eg:

~21
21二进制:   0000 0000 0000 0000 0000 0000 0001 0101~21二进制:  1111 1111 1111 1111 1111 1111 1110 1010(0xffffffea)

2.2.5左移运算符 <<

a<

eg:

9<<4
9二进制:   0000 0000 0000 0000 0000 0000 0000 10019<<4二进制:0000 0000 0000 0000 0000 0000 1001 0000(十进制144)

2.2.6右移运算符 >>

a>>b
将a二进制位右移b位,移出右边丢弃。若为有符号数,右移时符号位一起移动,左边补充原符号位相同的数作为新符号位。
右移n位相当于左操作数除以2n后往小里取整

eg:

15>>2
15二进制:   1000 0000 0000 0000 0000 0000 0000 111115>>2二进制:1111 0000 0000 0000 0000 0000 0000 0011(3)

2.2.7思考题

Q:有两个int型变量a和n(0<=n<=31)求a的第n位
A1:

(a>>n)&1

A2:

(a&(1<<n)>>n)

2.3引用

2.3.1定义

引用等价于这个变量,对其修改等于对原变量修改

类型名&引用名=某变量名
e.g:

int n=4;int& r=n //r的类型是int&r=5;//此时n也变为5

2.3.2用法

eg1:用引用交换两个变量的值

#include <iostream>using namespace std;void swap(int &a,int &b){    int tmp;    tmp=a;a=b;b=tmp;}int main(){    int n1=5,n2=3;    swap(n1,n2);    cout<<n1<<" "<<n2<<endl;    return 0;}
3 5

eg2:引用作为返回值

#include <iostream>using namespace std;int n=4;int& setvalue(){    return n;}int main(){    setvalue()=40;    cout<<n<<endl;    return 0;}
40

2.3.3常引用

常引用不能通过引用的量来修改原来的值。

int n;const int& r=n;

2.4const关键字和常量

2.4.1定义常量

const int max=23const double pi=3.14const char* p="hello world!"

2.4.2定义常量指针

不可通过常量指针修改其指向的内容

int n,m;const int* p=&n;*p=5//编译出错,不可通过常量指针修改指定内容n=4;//okp=&m;//ok,但常量指针的指向可以变化

不能把常量指针赋值给非常量指针,但反过来可以

const int* p1; int* p2;p1=p2;//okp2=p1;//编译出错,不可将非常量赋值给常量p2=(int*)p1;//ok,强制类型转换,但有风险

函数参数为常量指针时,可避免函数内部不小心改变参数指针所指向的地方(后面函数的参数一般都如此定义)

void myprint(const char* p){strcpy(p,"this");//编译出错,不可改变参数指针指向的地方cout<<*p<<endl;//ok,简单的调用可以,但不能改变}

2.5动态内存分配

2.5.1用new运算符实现动态内存分配

2.5.1.1第一种用法,分配一个变量

t* p=new t;//p为t*类指针

2.5.1.2第二种用法,分配一个数组

t* p=new t[n];//p为t*类指针,n为数组个数

ps:特别注意的是,p作为数组时,可以用p[n]调用数组中第n个元素,很常见

2.5.2用delete运算符释放动态分配的内存

用new分配的内存空间,一定要记得用delete进行释放

2.5.2.1删除 new出来的变量

int* p=new int;*p=5;delete p;delete p;//编译错误,空间不能被delete多次 

2.5.2.2删除new出来的数组

int* p=new int[20];p[0]=1;delete [] p;

2.6内联函数

减少函数调用的开销
用法如下:

inline int max(int a, int b){return a<b?b:a;}

2.7函数重载

多个函数有同一个函数的名字,但函数的参数类型不同,叫做函数的重载
ex:以下三个是重载关系

int max(double n1, double n2){}int max(int n1, int n2){}int max(int n1, int n2, int n3){}

编译器会根据实际传入的参数来判定调用哪个函数。
ex:

max(3.2,2.5);//调用上述第一行的函数max(2,4);//调用上述第二行的函数max(1,2,3);//调用上述第三行的函数

2.8函数的缺省函数

调用函数时,可以不写相应的参数,编译器会以缺省值代替

void func(int x1, int x2=2, int x3=3){cout<<x1+x2+x3<<endl;}func(10);//等效于func(10,2,3)func(10,8);//等效于func(10,8,3)func(10, ,8);//编译错误,只能最右边的连续若干个参数缺省

可以提高程序的可扩充性

2.9类的基础定义

2.9.1类的定义

class 类名{访问说明符:    变量1    变量2    成员函数访问说明符:    变量3    变量4    成员函数};

2.9.2调用类中的成员变量和成员函数

用法1:
对象名.成员函数名字/成员变量名字
用法2:
对象指针->成员函数名字/成员变量名字
用法3:
引用名.成员名
eg:

#include <iostream>using namespace std;class crectangle{public:    int w,h;//成员变量    void init(int a,int b){w=a;h=b;}//成员函数1    int area(){return w*h;}//成员函数2    int perimeter(){return 2*(w+h);}//成员函数3};int main(){    int w=4,h=6;//第一种调用    crectangle r;//从类中建立一个新的对象r,这个r拥有上述类所有的成员变量和成员函数    r.init(w,h);//调用成员函数初始化成员变量    cout<<r.area()<<endl<<r.perimeter()<<endl;//第二种调用    crectangle* p=&r;//对象指针p    p->init(w,h);//第二种调用方式    cout<<p->area()<<endl<<p->perimeter()<<endl;//第三种调用    crectangle& rr=r;    rr.init(w,h);    cout<<rr.area()<<endl<<rr.perimeter()<<endl;    return 0;}
242024202420

也可以只在定义类的时候只申明函数,在外面写函数体

class rectangle{public:    int w,h;    int area();    int perimeter();    void init(int a, int b)};void rectangle::init(int a,int b){w=a;h=b;}//成员函数1int rectangle::area(){return w*h;}//成员函数2int rectangle::perimeter(){return 2*(w+h);}//成员函数3

2.10类成员的可访问范围

在上一节定义类的时候,有个访问说明符,分类如下:
private:其成员只能被成员函数访问
public:可以在任何地方访问
protected:后面会提到,有关于基类/派生类

#include <iostream>using namespace std;class crectangle{public:    int w,h;    void init(int a,int b){w=a;h=b;}    int area(){return w*h;}    void seta(int x){a=x};private:    int a;    int perimeter(){return 2*(w+h);}};int main(){    int w=4,h=6;    crectangle r;    r.init(w,h);//ok,可以调用public成员    cout<<r.area()<<endl//ok,可以调用publlic成员    cout<<r.perimeter()<<endl;//编译错误,不能调用private成员    r.w=5;//ok,可以调用    r.a=6;//编译错误,不能调用private成员    r.seta(6);//ok,想修改private的值只能通过其public成员函数    return 0;}
原创粉丝点击