C++指针心得

来源:互联网 发布:藏文输入法软件下载 编辑:程序博客网 时间:2024/06/07 01:58

指针定义的时候是指向一个地址,如:

int a = 10;

int *b = &a;

b中存储的是a的地址,解引用可以得到地址为a的变量的值,即*b


既然指针存储的是地址,那么二维指针指向的就是地址的地址,如:

int a = 10;

int *b = &a;

int **c = &b;

因为解引用得到的是值,那么指针存放的就是地址,因此c中存的是b的地址,*c就是b中的值,即a的地址

所以,如下代码:

int *p = *c;

因为*c是a的地址

那么代码等同于

int *p = &a;

int *p = b;


引用的用法是:

int a = 10;

int &b = a;

当对b复制的时候,如:

b = 30;

此时不是像对变量复制的过程那种在堆栈中新增加一个变量,找到变量b所在的地址,b地址存放的值是变量a的地址,因此给b赋值的过程如下:

找到变量b的地址,读取该地址下的值,即a的地址,之后通过a的地址,修改a地址下的值为30

如果引用过程中涉及类型转换,如:

double a = 3.14;

int &b = a;

b = 7;

实际上b没有改变a的值,因为对于有类型转换的引用,编译器实际是这样处理的:

int temp = a;

int &b = temp;

b = 7;

所以b更改的是临时的中间变量temp,而不是a


指向const的指针和const指针:

指针的读法是从右向左读,如:

int *a;

读成a是一个指针,指向int,同理,如下指针:

const int *a;

读成a是一个指针,指向int,int是const的,也就是说,指针所指向的值不会变而指针可以自由移动,成为指向const的指针

const指针是这样的,如:

int *const a;

读成a是一个const指针,指向int,这就说明a指针指向int型的数据后就不能移动了,而所指向的数据可以修改,因此声明const指针的时候不许进行初始化

这样就可以理解指向const的const指针,如:

const int *const a;

这就说明a要指向固定的值不能动,而指向的值也不能被修改


char指针

const char *a = “abcdefg”;

用字符串常量初始化指向const char的指针a时,字符串的结尾会自动添加\0空白符

如果用数组声明的话,如:

char a[4] = “abcd”;

会报错,说为数组进行初始化的值过长,因为这时候实际常量后面有了\0空白符,因此数组长度应该是5

如果这样声明,如:

char a[4] = “abc”;

就对了

用循环进行初始化的时候,如

char a[4];

for(int i = 0;i < 4;i++)

{

a[i] = ‘b’;

}

cout<<a<<endl;

运行后打印出来的结果在bbbb后面还有一堆乱码的值,这是因为没有在结尾添加\0空白符

在循环中加上

if(i == 3)

{

a[i] = ‘\0’;

break

}

就可以正确的打印出结果了


对于一维数组

int a[5];

当访问相应的下标a[i]的时候,相当于对指针a进行解引用相当于*(a + i)

所以a中存放的是数组开始的地址,因此可以通过指针进行赋值访问,如:

int *p = a;

对于二维数组

int b[3][4]

该数组有3行4列,既然b[3][4]是一个解引用的结果,那么b[i]里存储的是指第i+1个长度为4的数组的地址,b就是指向指针的指针,即二维数组开始的地址

但是二维数组不能通过二维指针进行索引,如:

int **p = b;

的做法是错误的,因为没有表示指向的是一个数组,缺少了列数,不能进行索引

对于,指向二维数组第n行地址的指针,可以用如下表示法

int (*p)[4] = &b[n-1];

其中n为行数,这样p就指向了第n个以为数组的开始元素

因为a[n]是地址b解引用的结果,所以

int (*p)[4] = &b[0];

int (*p)[4] = b;

是等价的

同理下面的代码

int b[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};

int (*p)[4] = b

p++;

cout<<p[0][0];

p首先指向了第1行,之后p++,因为p是二维数组,所以自增后指向的是&a[1],因此p[0][0]得到的结果是第二行第一列的元素5


指针操作符优先级问题

指针*操作符的优先级小于于自增++操作符,但都小于()操作符,因此

(*p)++是得到p的解引用的值,之后对解引用的值++

*(p++)和*p++等价,都是先把指针p++后再对递增前的地址解引用,因为p++先返回原地址,之后在对地址++,因此解引用的是递增前的地址

()操作符只影响运算顺序,不影响返回结果的顺序

数组中的[]操作符优先级大于指针*操作符

int *p[4]声明的是p是一个长度为4的数组,数组中的每一个元素都是一个指向int的指针,即p[0]到p[3]都是指针

int (*p)[4]声明的是p是一个指针,指向的是列为4的int型二维数组


数组动态建立的时候,对于一维数组

int *a = new int[4];

表明动态创建一个长度为4的int型数组,删除的时候用

delete [] a;

对于二维数组a[3][4]的动态建立,如:

int **a = new int *[3];

for(int i = 0;i < 3;i++)

{

a[i] = new int[4];

}

首先动态创建一个长度为3,每个元素都是指向int的指针,之后为每个数组动态建立一个长度为4的存储int值的数组

对于二维数组的删除

首先要删除每个int指针数组的元素

for(int i = 0;i < 3;i++)

{

delete [] a[i];

}

之后长度为3的指针数组

delete [] a;


如果有如下代码:

typedef string *s_string;

const s_string a;

a不是一个指向cons string的指针,而是一个const的string指针,即等同于

string *const a;

因为const修饰的是s_string,所以s_string是一个const,即一个const指针


指向函数的指针

如果一个函数是这样的:

void coutFunc(string a)

{

cout<<a<<endl;

}

打印出一个传入函数的string型变量a

如果用一个指针指向countFunc函数,则称为指向函数的指针,如:

void (*p)(string) = countFunc;

这里p是一个指向以string为参数,返回void值的函数countFunc的指向函数的指针,这里函数名作为地址,这种定义等同于

void (*p)(string) = &countFunc;

通过函数指针调用函数,可以通过

p(“abcd”);

(*p)(“abcd”);执行

即调用了countFunc函数

当指向函数的指针作为函数参数传递时,可以这样声明:

void func_a(void (*)(string));

即函数func_a的参数是一个以string为参数返回值为void的指向函数的指针,func_a返回值是void,定义实现如下:

void func_a(void (*p)(string))

{

p(“abc”);

}

同理,以指向函数的指针作为返回值的函数可以定义为

void (*func_b())(string)

{

void (*p)(string) = countFunc;

return p;

}

func_b的参数为空,返回一个指向参数为string返回值为void的函数的指针


对于指向函数的指针,用typedef来声明会容易理解些

typedef void(*p_func)(string);

p_func p = countFunc;

这里,p_func是一个指向参数为string返回值为void的函数的指针类型,可以定义一个指向函数的指针p,并赋值为函数countFunc

同样,可以定义函数

p_func test_func()

{

void (*p)(string) = countFunc;

return p;

}

test_func函数参数是空,返回一个指向参数为string返回值为void的函数的指针

0 0
原创粉丝点击