c笔记之指针.docx
《c笔记之指针.docx》由会员分享,可在线阅读,更多相关《c笔记之指针.docx(33页珍藏版)》请在冰豆网上搜索。
c笔记之指针
指针
指针乃地址也。
变量的地址:
系统为变量分配的内存单元的地址(一个无符号的整型数)
变量--存储内容:
数据值
空间大小:
数据类型
空间位置:
地址
生存周期:
存储类别
变量的访问方式:
直接访问
间接访问
指针变量:
是存放地址的变量,该变量是一个地址(无符号的整型数)
eg:
p为指针变量,它存放整型变量a的首地址
则,指针变量p指向整型变量a
指针变量的定义和引用
1.定义方法
类型符*指针变量名
eg:
int*p1,*p2;
char*ps;
float*pf1,pf2;
指针变量的类型--〉是所指向的内存中存放的数据的类型。
2.赋值
指针变量的值为地址,是个无符号整数。
但不能直接将整型常量赋给指针变量。
1.用变量的地址给指针变量赋值(求地址运算符&)
eg:
inta,b,*p;
p=&a;
变量的类型必须与指针变量的类型相同。
p=123;×p指向地址,不是常量或变量
p=&123;×123是常量,常量没有存储空间,就不可能取地址
*p=123;×不知道指针地址,怎么确定的指针内容?
2.用相同类型的指针变量赋值
eg:
inta;
int*p1,*p2;
p1=&a;
p2=p1;
若不赋值,则指针变量的值是随机的。
---危险(死机...)
3.赋空值NULL
eg:
int*p;
p=NULL;或p=0;
4.指针变量的初始化方法
1.赋空值NULL
eg:
int*p1=NULL;
2.用已定义的变量的地址
eg:
floata;
float*p2=&a;
charch,*p3=&ch;
3.应用
1.两个有关的运算符:
*、&
形式:
&任意变量-->取地址运算符
*指针变量-->指针运算符
含义:
&a表示变量a所占据的内存空间的首地址--一般变量
*p表示指针变量p所指向的内存中的数据--指针变量
inta,*p;p=&a;-->*p相当于a
应用:
通过指针变量访问所指变量(通过指针变量间接访问某一个变量)
将指针变量指向被访问的变量
eg:
inta=5,*p,b;
p=&a;
访问所指变量
取内容:
b=*p;-->*p相当于=a
b=*p;//间接访问<==>b=a;//直接访问
printf("%d\n",*p);
存内容:
*p=100;
注意:
*p若出现在“=”的右边或其他表达式中,则为取内容。
*p若出现在“=”的左边,则为存内容。
注意区分:
intb,*p1,*p2=&b;
1.p1=p2;与*p1=*p2;
p1=p2;//把p2的地址赋给p1,p1和p2的地址都指向了b。
*p1=*p2;//把p2所指向的内容放到p1内容里,p1和p2得内容都等于b的内容(b的值)
2.(*p1)++;与*p1++;
(*p1)++;//*p1<==>a,即(*p1)++;<==>a++;
*p1++;//先得到*p1的内容,*p1++;<==>*(p1++);
3.&*p等价于p
*&a等价于a
eg1:
#include
main()
{
inta=5,b=3;
int*p;
p=&a;
b=*p+5;
printf("%d\n",b);//b=10;
*p=4;
printf("%d,%d\n",a,*p);//a=4;*p=4;
}
eg2:
同指针变量来交换两个单元中的内容。
#include
main()
{
inta,b,c,*p1=&a,*p2=&b;
scanf("%d%d",p1,p2);
c=*p1;*p1=*p2;*p2=c;
printf("a=%d,b=%d\n",*p1,*p2);
}
2.运算规则
*、&:
优先级相同,且右结合
与++、--、!
等单目运算符的优先级相同
高于算术运算符*、/、%
eg1:
#include
main()
{
inta=2,*p=&a,*q=&a;//*p=&a--〉已定义的变量的地址为指针变量赋值
printf("*p++=%d,*(q++)=%d\n",*p++,*(q++));
//*p++=2,*(q++)=2
//*p++,先运算*p,再p++。
*p在左边,为取内容
//*(q++),地址相加(q++=(&a)++)而不是a++。
先运算q,再q++
//指针变量里的值相加,使指针指向了其他的变量
p=&a;
q=&a;
printf("*p=%d,(*q)++=%d\n",*p,(*q)++);
//*p=3,(*q)++=2;
//(*q)++,所指向的变量的值相加,即a++
}
eg2:
写出下面各表达式的结果,并找出具有等价关系的对子。
eg:
inta=5,*p=&a;//*p=&a:
已定义的变量的地址为指针变量赋值*p指向a-->*p=a
&*p=&a;//p=&a;*p=a;&*p=&a=p;
*&a=a;//p=&a;*p=a;*&a=*p=a;
(*p)++=a++;
*p++=*(p++);//*(p++)=*((&a)++)
eg1:
#include
main()
{
inta,b,c;
int*pa,*pb,*pc;
pa=&a,pb=&b,pc=&c;
scanf("%d%d",pa,pb);//*pa=3,*pb=4
//scanf("%d%d",&a,&b);
printf("&a=%d,&b=%d\n",pa,pb);//地址&a=2293408,&b=2293404
printf("a=%d,b=%d\n",*pa,*pb);//数据a=3,b=4
c=a+b;printf("c=%d\n",*pc);//a=3,b=4,c=3+4=7
*pc=a+*pb;printf("c=%d\n",c);//a=3,b=4,c=3+4=7
c=*pa**pb;printf("c=%d\n",c);//a=3,b=4,c=3*4=12
c=++*pa+(*pb)++;printf("c=%d\n",c);//a=4,b=4,c=4+4=8,b=5
c=(*pa)+++*pb;printf("c=%d\n",c);//a=4,b=5,c=4+5=9,a=5
printf("a=%d,b=%d\n",a,b);//a=5,b=5
}
eg2:
交换两个数a、b的值。
#include
main()
{
//inta=5,b=8;
//intt;
//printf("a=%d,b=%d\n",a,b);
//
//t=a;
//a=b;
//b=t;
//printf("a=%d,b=%d\n",a,b);
inta=5,b=8;
int*pa=&a,*pb=&b;//已定义的变量的地址(&a/&b)为指针变量(*pa/*pb)赋值
intt;
printf("a=%d,b=%d\n",a,b);
t=*pa;//*pa:
pa所指向的单元的内容--〉a
*pa=*pb;
*pb=t;
printf("a=%d,b=%d\n",a,b);
}
4.指针变量作函数参数
eg1:
编写一个函数实现两个数的交换。
////×子函数交换,主函数未交换。
//#include存储单元
//voidswap(intx,inty)内容单元名存储单元(假设位置)
//{3a2A02
//intt;//局部变量5b2C16
//t=x;x=y;y=t;//子函数交换变量拷贝赋值
//}3x(a)4012
//main()5y(b)4016
//{值交换后-->存储单元不一样,未完成交换
//inta=3,b=5;5x4012
//swap(a,b);3y4016
//printf("%d%d\n",a,b);//主函数未交换
//}
√指针变量间接访问
#include
voidswap(int*x,int*y)//使用指针变量存储单元
{内容单元名存储单元(假设)
intt;3a2A02
t=*x;*x=*y;*y=t;//地址交换5b2C16
//t=*x;-->*x所指向的单元内容赋值给t。
地址赋值
}2A02x(&a)4012
main()2C16y(&b)4016
{内容交换后
inta=3,b=5;5*x(a)2A02
swap(&a,&b);//地址值3*y(b)2C16
//实参传递地址值,形参一定是指针变量
printf("%d%d\n",a,b);
}
////×地址交换,内容没变。
//#include
//voidswap(int*x,int*y)//定义指针变量存储单元
//{内容单元名存储单元(假设)
//int*t;//定义局部指针变量3a2A02[2C16]
//t=x;x=y;y=t;//地址交换5b2C16[2A02]
//}地址赋值↑
//main()2A02x(&a)4012↑
//{2C16y(&b)4016↑
//inta=3,b=5;地址交换后-->a和b的地址交换了,内容不变。
//swap(&a,&b);//地址值2C16x(&a)4012
//printf("%d%d\n",a,b);2A02y(&a)4016
//}
////×危险错误:
*t中地址不确定,不可存放内容。
//#include
//voidswap(int*x,int*y)//定义指针变量
//{
//int*t;//定义局部指针变量
////intw;t=&w;//给*t指定地址,则程序正确。
//*t=*x;*x=*y;*y=*t;
////*t中地址(t)随机,则*t所指向的单元内容存放位置不得当。
//}
//main()
//{
//inta=3,b=5;
//swap(&a,&b);//地址值
//printf("%d%d\n",a,b);
//}
eg2:
输入a,b,c三个数,按大小顺序输出。
-->四个数排序输出,需要6次两两比较交换。
#include
voidswap(int*x,int*y)//定义指针变量
{
intt;//定义局部指针变量
t=*x;*x=*y;*y=t;
}
main()
{
inta,b,c;
printf("enterdataa,b,c:
");
scanf("%d%d%d",&a,&b,&c);
if(a
if(aif(bprintf("%d%d%d\n",a,b,c);
}
指针和数组
1.一维数组与指针
1.数组是连续存放的若干个元素的集合。
2.数组名就是指向此数组第1个元素的指针(首地址)
eg:
inta[10],*p=a;则p=a;等价于p=&a[0];
3.某一元素的地址:
p=&a[i];
用指针引用该元素:
*p=a[i];//a[i]:
a数组中下标为i的元素
4.数组元素的下标在内部实现时,统一按“基地址+位移”的方式处理。
a:
a数组中的首地址=&a[0];
a+1:
a数组中下标为1的元素地址=&a[1];
a+i:
a数组中下标为i的元素地址=&a[i];
位移eg:
a数组是int整型,占用两个字节。
假设a数组首地址a=3A00;
则a[1]=a+1*2=3A02;
a[i]=a+i*2;
故表示数组元素的地址可以用:
&a[i]、p+i、a+i(p=a)
表示数组元素的内容可以用:
下标表示法a[i]
指针表示法*(p+i)、*(a+i)
5.数组名a(数组的指针)与指向数组首地址的指针变量p性质不同。
(a不是变量,它是一个常量,不会改变值。
)
eg1:
#include
main()
{
inta=3,b=5;
int*p=&a;//p=&a;
printf("*p=%d\n",*p);//*p=3
*p=4;//a=*p;
p=&b;
printf("*p=%d\n",*p);//*p=5
*p=6;//b=*p;
printf("a=%d,b=%d\n",a,b);//a=4,b=6
}
eg2:
1.#include
main()
{
inti,a[5];
int*p;
for(i=0;i<5;i++)
{
p=&a[i];x
a[i]=i;//*p=a[i]=i;
printf("a[%d]=*p=%3d\n",i,*p);
}
printf("\n");
}
/*
a[0]=*p=0
a[1]=*p=1
a[2]=*p=2
a[3]=*p=3
a[4]=*p=4
--------------------------------
*/
2.#include
main()
{
inti,a[5];
int*p=a;//p=a;或p=&a[0];
//i++;指i单元的内容+1
//p++;指地址移到下一个元素(下一个元素的长度与数据的类型有关系)
for(i=0;i<5;i++,p++)
{
*p=i;//a[i]=i;
printf("a[%d]=*p=%3d\n",i,*p);
}
printf("\n");
}
/*
a[0]=*p=0
a[1]=*p=1
a[2]=*p=2
a[3]=*p=3
a[4]=*p=4
--------------------------------
*/
6.数组指针(a)、指针变量(p)与数组元素(a[i])之间的关系:
设有inta[10],*p=a;则
地址关系
指针变量p数组指针a数组元素
pa&a[0]
p+1a+1&a[1]
p+2a+2&a[2]
...
p+ia+i&a[i]
...
p+9a+9&a[9]
内容关系
指针变量p数组指针a数组元素
*p*aa[0]
*(p+1)*(a+1)a[1]
*(p+2)*(a+2)a[2]
...
*(p+i)*(a+i)a[i]
...
*(p+9)*(a+9)a[9]
eg:
数组的使用形式
#include
main()
{
inti,a[5],*p=a;
printf("input5numbers:
\n");
for(i=0;i<5;i++)
//scanf("%d",&a[i]);//数组的使用形式
//scanf("%d",a+i);
scanf("%d",p+i);
printf("outputthesenumbers:
\n");
for(i=0;i<5;i++)printf("%d",a[i]);//a[i]可换为*(a+i)或*(p+i)
printf("\n");
}
2.指针的运算(指向数字的指针p的运算)
1.赋值运算-->指针类型相同。
eg:
p=&x;//将x的地址赋给p
p=a;//将a数组的首地址赋给p
p=NULL;
2.加减运算-->只能用于数组元素的引用,注意下标的有效范围。
即加减运算必须在连续空间上的加减(移动)才有意义。
用法:
指针+/-整数
eg:
a+i-->a是一个数组名,表示地址的首地址,只能加不能减。
p+/-i-->p是一个指针变量,指向某一个数组元素,可进行加减。
p-q;//p和q都是指向同一个连续存储的空间(相减得到相隔两个元素的个数)
3.两指针的相减运算:
求两地址的间距-->两个指针的类型相同,并指向同一连续的存储区域。
用法:
指针-指针
eg:
p-a-->a为数组首地址保持不变,p可以移动(求这个地址到首地址跟了几个元素)
4.移动指针(++、--)-->对数组名(常量)/简单变量不能实施该运算。
eg:
p++;//后移p=p+1;要求p为变量(指针变量),不能是常量(数组名)。
p--;//前移
5.比较运算(p和q都是指向同一个连续存储的空间)
比较两个元素相隔的个数
用法:
指针运算符指针
eg:
p地址
比较:
字符量根据ascii码;
数值量根据数值大小;
指针变量根据地址大小
2~5运算通常用于指向数组的指针[连续空间的指针]
eg:
将数组a的数据复制到数组b中并输出出来。
//数组下标的方法
#include
#defineM7
main()
{
inti,a[M]={23,15,50,3,21,20,35};
intb[M];
for(i=0;iprintf("outputthesenumbers:
\n");
for(i=0;iprintf("\n");
}
//指针的方法
#include
#defineM7
main()
{
inti,a[M]={23,15,50,3,21,20,35};
intb[M];
//p指向a的首地址&a[0];q指向b的首地址&b[0]
int*p=a,*q=b;
for(i=0;i{
//*q=*p;//将p地址所指向的内容赋给q地址
//q++;//地址指针+1
//p++;
//将p地址所指向的内容赋给q地址,然后p、q后移
*q++=*p++;
}
printf("outputthesenumbers:
\n");
//for(i=0;iq=b;//将q指针重新指向b数组的首地址
for(i=0;iprintf("\n");
}
3.数组的指针与函数参数
数组作为函数参数,实参和形参的对应关系可归纳以下四种情况:
①形参是数组x[];实参是数组名a
intf(intx[],intn)
{}
main()
{
inta[10];
...
f(a,10);
...
}
②形参是指针变量*x;实参是数组名a---常用形式
intf(int*x,intn)
{}
main()
{
inta[10];
...
f(a,10);
...
}
③形参是指针变量*x;实参是指针变量p,指向数组a的首地址---常用形式
传进去地址,也用指针接收
intf(int*x,intn)