C语言指针的操作确实让我琢磨不透,调试了一下午之后,好像明白是怎么回事了,写个博文记录一下吧,怕忘记了。
一、前置++与后置++
首先,我们来研究一下前置++ 和后置++的区别。
void main()
{
int a = 1;
int b = ++a+1;//++运算符优先于+号,所以先计算++a,++在前,先增再用,a自增为2,再与后面的1进行运算 b=2+1=3
printf("b=%d,a=%d", b, a);
}
#include
void main()
{
int a = 1;
int b = 1+a++; //++运算符优先于+号,所以先算a++,又因为++在后面,所以先把a用掉,就是先计算1+a,a=1所以1+a=2,然后a再自增。a也变成了2。
printf("b=%d,a=%d",b,a);
}
前置- -和后置- -与加一样,–在前面,先自减,再计算,–在后面先计算在自减。
void main()
{
int a = 1;
int b = --a + 1;//--在前,先自减,再运算,a自减为0,再计算 b=0+1=1
printf("b=%d,a=%d", b, a);
}
void main()
{
int a = 1;
int b = 1 + a--;//--运算符优先于-号,所以先算a--,又因为--在后面,所以先把a用掉,就是先计算1+a,a=1所以1+a=2,然后a再自减,a变成了0。
printf("b=%d,a=%d", b, a);
}
二、*p和p,指针指向的内存空间,和指针地址
p就是一个指针,保存的是地址,*p是操作指针所指向的内存空间。
指针指向谁,就把谁的地址赋值给指针
假如我有一个变量a=100; 然后定义一个指针,让他指向变量a的内存空间。
如图:
#include
void main()
{
int a = 100; //定义变量a
int* p;//定义指针p
p = &a;//指针指向a(就是把a)的地址给指针,所以a要取地址。
printf("p=%p,&a=%p", &a, p);//可以看出来指针的地址和变量的地址是一样的
可以看到他们俩的结果是一样的。p和a是同一块内存空间
假如下面我操作*p,就是在改变变量a的值。
#include
void main()
{
int a = 100; //定义变量a
int* p;//定义指针p
p = &a;//指针指向a(就是把a)的地址给指针,所以a要取地址。
printf("p=%p,&a=%p", &a, p);//可以看出来指针的地址和变量的地址是一样的
*p = 10;//*p操作指针所指向的内存空间,也就是a的值。通过指针把a的值改成了10
printf("这是通过*p操作之后的a=%d\n",a);
三、开始讨论 *++p,++*p,*p++,(*p)++,*(p++)
(一)、*++p 按照从右到左的结合顺序,我们是不是应该先算++p(p和++结合是地址自增),然后再取*,取*就是取指针所指向的内存空间。
int arr[3] = { 1,4,6 };//定义了一个数组,3个元素
int* p = arr;//将指针指向素组首元素地址,数组名就是首元素地址,所以不用取地址了
printf("执行前的地址为:%p\n", p); //执行语句以前打印一哈p的地址
int a = *++p;//执行语句
printf("执行后的地址为%p\n", p);//这是执行语句以后的地址
printf("*++p=%d\n", a)//打印*++p的结果
代码分析:可以看到,执行后的地址比执行前的地址多了4,因为一个int类型的占是4个字节,所以执行后的地址为00f8fe48, 地址先增加了4个,所以指针的指向就跳到了素组的第二个元素,然后再取*,所以就打出了p++=4,所以可以看到先执行了p++让地址增加1个(增加一个是占用的是4个字节的空间),然后再运算打印指针所指向的内存空间。
(二)、++*p 按照从右到左的结合顺序,我们是不是应该先算*p,再计算++。
int arr[3] = { 1,4,6 };
int* p = arr;//将指针指向素组首元素地址,数组名就是首元素地址,所以不用取地址了
printf("执行前的地址为:%p\n", p);
int a = ++ *p;
printf("执行前的地址为:%p\n", p);
printf("数组的第一个元素:%d\n", arr[0]);//这一步是验证指针改变了数组元素的值。执行 ++ * p后,数组的首元素的值也发了变化。
printf("++*p=%d\n", a);
本例中,先*p取值是1,++在前,所以先计算++ , *p的计算结果是1,再++的结果就变成了2,然后再用a打印出来。通过指针操作了素组的首元素的值也变成了2。地址没有发生变化。
int arr[3] = { 1,4,6 };
int* p = arr;
printf("执行前的地址为:%p\n", p);
int a = *p++;
printf("执行前的地址为:%p\n", p);
printf("*p++=%d\n", a);
代码分析:本例中,从右到左,先计算p++,++在后,先用在增,p先和*结合,计算*p,p存的是数组的首元素地址,所以*p的值是1,所以打印的结果*p++是1,计算完*p之后,p再++,就是地址自加,指向就变成了数组的第二个元素。由原来的0093f910增加到009f914。
int arr[3] = { 1,4,6 };
int* p = arr;
printf("执行前的地址为:%p\n", p);
int a = (* p)++;
printf("执行前的地址为:%p\n", p);
printf("(* p)++=%d\n", a);
代码分析:本例中,有括号先算括号里的,p指向的是arr[0]的地址,所以*p=1,++在后,所以先用在自增,先用就是先赋值给a,在++,所以打印出来的结果是1而不是2。
五、*(p++):有括号先算括号,所以先执行p++,又因为++在后,所以先用再自加,(和*p++是一样的顺序)p先和*进行结合,然后地址再++。
代码:
int arr[3] = { 1,4,6 };
int* p = arr;
printf("执行前的地址为:%p\n", p);
int a = *(p++);
printf("执行前的地址为:%p\n", p);
printf("*(p++)=%d\n", a);
代码分析和*p++基本是一样的(有括号先括号)
六、++(*p):有括号先括号,先计算*p,然后++在前,先增再用。
代码:
int arr[3] = { 1,4,6 };
int* p = arr;
printf("执行前的地址为:%p\n", p);
int a = ++(*p);
printf("执行前的地址为:%p\n", p);
printf("++(*p)=%d\n", a);
分析:本例中,有括号先括号,先计算*p,*p是1,然后++在前,先增再用。所以++(*p)的结果是2
(七)*(++p) 有括号先括号,先算++p,++在前,所以先++,地址自增后再进行*运算。和*++p是一样的顺序。
代码:
int arr[3] = { 1,4,6 };
int* p = arr;
printf("执行前的地址为:%p\n", p);
int a = *(++p);
printf("执行前的地址为:%p\n", p);
printf("*(++p)=%d\n", a);
分析:本例中,*(++p)先算括号里面的++p ,++在前,所以地址先做自增,再取*,所以打印的是数组的第二个元素,a[1]也就是4。
以上就是对于这几个代码的分析