一、指针
(1)什么是指针
指针就是专门用来储存地址的变量
注意刚开始学的时候,不知道怎么才用指针。定义指针p后,正常使用p就可以了,“p”就代表指针了。(而不是*p,*p代表指针地址所指向的内容了)
(2)定义指针变量
1️⃣定义类型
特别注意:
2️⃣指针变量的类型
3️⃣指针变量要先赋值再使用
指针变量被定义后,必须将指针变量和一个特定的变量进行关联后才可以使用它。当然被赋的值必须是地址。
4️⃣定义指针变量时的“ * ”和定义指针变量后的“ * ”
特别要注意:
定义指针变量时的“ * ”只是一个说明符,代表我要定义一个指针。
定义指针变量后的“ * ”是一个运算符,代表间接访问指针p所指向的变量。
5️⃣定义指针变量时,最容易犯的错误
第一种
int i,*p=&i;
第二种
int *p,i;
*p=&i;
第三种
int *p,i;
p=&i;
在这三种定义中,第二种是错的,注意它与一、三种的区别。
而在除了定义指针外出现的 * 的情况,都有运算含义。那就是取该指针(q)的内容。所以*p=&i 这样的赋值是不成立的。*p代表了一个具体的内存单元里的内容(就是字符串),而&i 是一个地址。当然不能进行赋值。
(3)指针变量的初始化
1️⃣用地址来初始化
char str[10],*p;
p=str;
int i,*p;
p=&i;
2️⃣用同类型指针来初始化
int a=3,*p1,*p2;
p1=&a;
p1=p2;
3️⃣不能用数值作为指针初始化的初值,但可以用0来做初值,代表将指针变量初始化为一个空指针。
int *p=1000//非法
int *p=0//可以的
4️⃣用于给指针变量初始化的地址,必须先定义才能给指针赋值。
int *p=&i;
int i;
这样是不行的,这种局部变量i 只有在被定义后才分派了内存单元,有了内存单元才有地址,有了地址才能给指针赋值。
二、指针的运算
(1)指针的加减法
1️⃣指针与整数的加减法2️⃣同类指针之间的相减
3️⃣非法的运算:
指针之间的相加,相乘,相除或加上一个浮点数或减去一个浮点数都是非法的啊
(2)指针之间的关系运算
(3)取地址运算符&和取内容运算符*
&用于给出地址
int *p,a=3;
p=&a;
*用于取指针里的内容
当指针p指向变量后, * p就用代表访问指针内的内容。
(4)指针变量的赋值
1️⃣赋地址
char str[10],*p;
p=str;
int i,*p;
p=&i;
2️⃣同类型指针的赋值
int a=3,*p1,*p2;
p1=&a;
p1=p2;
完成p1=p2后,就代表指针p1和p2都指向变量a,*p1,*p2,a访问同一个内存单元,他们的值都一样。
(5)各种++,- -
1️⃣(*p)++:
(*p)++代表将指针所指向的变量+1;
比如p指向i ,i =4,那(*p)++之后久代表i =5;
2️⃣ *p++:
*p++等同于 * (p++),因为++的运算等级高于 *。
它代表指针p向后移一个内存单元(++的含义),然后再用 *来取该内存单元的内容。
p++常用于p++=一个需要赋值的数据,既能历遍数组,又能赋值,一举两得。
三、指针的一些特殊功能
(1)终于能通过函数做数值交换了
详细的讲解在P195页
这里我想讲一下通过这题之后我对*px=*py和px=py的理解,刚开始学的时候真的有点懵。
在swap2和swap3中,px和py都分别接收了a和b的值,但只有swap2是能真正做到交换a和b的值得。
*px=*py代表px所指向的变量的值等于py所指向变量的值,即a=b,真正能够改变指针px所指变量的值。
而px=py只代表px与py共同指向内存单元b,是完全与px内存的a的值无关的。只是改变了指针的指向(从下面的尝试来看,指针的内容也被改变了),但没有改变它指向的变量的值。
注意区分改变指针的指向和改变其内的值
一个尝试:
#include <stdio.h>
void swap3(int *px,int *py);
int main() {
int a=1,b=2;
int *pa=&a,*pb=&b;
a=1,b=2;
swap3(pa,pb);
printf("a=%d b=%d",a,b);
return 0;
}
void swap3(int *px,int *py){
int *pt;
pt=px;
px=py;
py=px;
printf("*px=%d *py=%d\n",*px,*py);
}
改变指针的指向就是改变了指针储存的内容,但是之前指针所指向的变量的值没有改变。(我可不可以理解为,指向改变之后,新的值覆盖了旧的值,那么px=&a也无影无踪了)
(2)在函数内使用指针可以返回多个值
课本例题一:
#include <stdio.h>
void sum_diff(double op1,double op2,double *psum,double *pdiff);
int main(){
double op1,op2,sum,diff;
scanf("%d %d",&op1,&op2);
sum_diff(op1,op2,&sum,&diff);//把sum和diff的地址给*psum和*pdiff
printf("sum=%d diff=%d",sum,diff);
return 0;
}
void sum_diff(double op1,double op2,double *psum,double *pdiff){
//
double sum,diff;
sum=op1+op2;
diff=op1-op2;
*psum=sum;//此时赋值给*psum就代表sum(主函数)的值被改变
*pdiff=diff;
}
可以这样理解,*psum pdiff在接受&sum,&diff的参数传递后,就代表了sum,diff的地址赋给了psum pdiff。也可以直接理解为psum *pdiff获得了变量sum和diff的内存修改权。所以在函数中进行赋 *psum=sum;
*pdiff=diff后,主函数变量sum,diff的值就被改变。
四、指针和数组
(1)定义方式
1️⃣先定义指针,再赋值
int a[5],* p
1.p=a;p=a+1…
2.p=&a[0];p=&a[1]…
p=a与p=&a[0]是等价的,它们都是把数组的首地址付给了指针p
2️⃣直接在定义中完成
int a[5], *pa=a;
3️⃣运用 * 和数组首地址表示
如下所示, * (a+0)就能代表a[0]的地址
(2)两者的关系
1️⃣关于数组
数组的第一个值的地址就是内存中储存数组的起始地址,因此数组名本身就是一个地址,可以看做是一个指针常量。
注意因为数组是个常量所以不能像指针一样用a=p,a++,a+2这样的表达式。
2️⃣对应关系
它们的表达方式可以说是一样的
3️⃣用指针遍历数组的两种方式
#include <stdio.h>
int main(){
int i,n=10,a[10]={
1,2,3,4,5,6,7,8,9,10},*p;
for(i=0;<