一、指针变量定义
C语言有两种变量:
其中变量(普通变量)存储内容值;地址变量(指针变量)存储地址值。
1、定义的格式:
类型名 *指针变量名;
如:
int a,b,*p1,*p2;
float x,y,*p3,*p4;
chars,*p5,*p6;
注:
(1)定义变量(普通变量、指针变量)都必须在前面有类型名。
(2)在定义指针变量时,指针变量名前的“*”表示现定义的是一个指针类型的变量。星号并不是指针变量名的一部分,只有一个标志。
(3)指针变景专口用来存地址,禁止将一个整型值直接t给一不着变量。
int a,b,*p;
a=1000;
b=2000;
p=4000;//错误只能存地址值
2、指针变量的引用
“&”取地址运算符,通过&运算符可以取出普通变量的地址。
“”指针运算符,可以取出指针变量所指向的普通变量的值,(间接引用普通量)
*指针变量名
如:
int a,b=20,c=30,d=40,*p;
p=&d;
a=*p;a=d;
指针方法:
口诀:内容变量画房子,指针变量画指向,定义也要初始化,
口诀:地址变量得地址,得谁地址指向谁,有*为内容值,不是读就是写,=号左边是写操作
画图:数组,static,指针,链表,文件
注:
(1)可以通过赋值使一个指针变量“指向”某一普通变量(指针变量=&普通变量)。
(2)在C语言中正确的做法是先让指针变量指向一个确定的存储单元后,再通过该指针变量引用它所指向的存储单元,如:
int *p;//p的"房子"是随机的,指针是任意指的,如果指针指向系统区,则代价极高
*p=200;危险!//因此在C语言中指针必须定义且初始化
(3)变量名(普通变量、指针变量)都表示其存储单元内的值。
pl=p2;/*pl指向了p2所指向的单元*/
读出p2的内容值写到p1的"房子"里
(4)若指针变量p指向变量a,即将变量a的地址赋给了指针变量p。
如:int a=20,*p=&a;则有下列结果(等价表):
A、*p<=>a
B、p<=>&a
C、&*p<=>&a<=>p
D、*&a<=>*p<=>a
E、(*p)++ a++都是给变量a的值加1。
(*p)-- a--
++(*p) ++a ++*p
--(*p) --a --*p
(5)所有的指针变量在内存中分配的字节数相同。sizcof()
int *p1;
float *p2;
double *p3;
指针变量永远占两个字节(地址),前面类型表示的是该指针指向的内容值的类型
例1:
请输出下列程序的结果
void fun(int*x,int*y)
{printf("%d %d",*x,*y);
*x=3;
*y=4;
}
main()
{int x=1,y=2;
fun(&y,&x);
printf("d% d%",x,y);
}
输出结果:2 14 3
例2:
#include<stdio.h>请输出下列程序的结果
void swap(int*pl,int*p2)
{int temp;
temp=*p1;
*p1=*p2;
*p2=temp;}
main()
{
int a,b;
int *p1=&a,*p2=&b;
scanf("%d%d",pl,p2);
swap(pl,p2);
printf("%d,%d",*pl,*p2);
}
键盘输入2 5
输出结果:5,2
改动后:
#include<stdio.h>请输出下列程序的结果
void swap(int*pl,int*p2)
{int *temp;
temp=pl;
p1=p2;
p2=temp;
}
main()
{int a,b;
int*p1=&a,*p2=&b;
scanf("%d%d",pl,p2);
swap(p1,p2);
printf("%d,%d",*p1,*p2);
}
键盘输入:2 5
输出结果为: 2,5
例3:
#include<stdio.h>请输出下列程序的结果
void swap(int*pl,int*p2)
{int *temp;
*temp=*pl;
*p1=*p2;
*p2=*temp;}
main()
{int a,b;
int *p1=&a,*p2=&b;
scanf("%d%d",pl,p2);
swap(pl,p2);
printf(%d,%d",*p1,*p2);
}
键盘输入:2 5
结果:是5,2吗?错误!会报错哦,指针变量不能任意指,必须初始化程序中temp没有初始化所以很危险哦
二、一维数组与指针变量
说明:(1)
int fun(int a[10])<=>int fun(int*a)<=>int fun(int a[])
若数组做为形参,则将数组名做指针变量来处理。
指向数组的指针变量
1、指向数组元素的指针变量
由于数组元素与普通一样,所以定义指向数组元素的指针变量与定义指向普通变量的指针变量完全一样
如:
int s[10],a,b;
int b[3][6];
int*p;
p=&a;
p=&s[2];
p=&b[2][4];
2、指向一维数组的指针变量
注:数组a[]
(1)在C语言中规定:数组名a代表数组的首地址,而且是一个地址常量,且a<=>&a[0]
如:
int a[10];intp;P=a;<=>P=&a[0];
(2)当指针变量指向数组中的某一个元素时,指针变量加1后指向数组的下一个元素,指针变量减1时指向数组中前一个元素。
如:
float a[10];floatp;p=&a[4];则p-3指向?---->a[1]
(3)
int a[N],*p=a;
p+i a+i &a[i] 地址三者相互等价
*(p+i) *(a+i) a[i] p[i] 元素四等价
当指针变量指向数组时,下标运算符(一级) ([])用于数组也可用于指针变量后
a)*(p+i)*(a+i)a[i] p[i]
b)p++、++p、p+=1、p=p+1
c)p--、--p、p-=1、p=p-1
d)*p++*(p++) *p-- *(p--)
e)*++p *(++p) *--p *(--p)
f)(*p)++ ++(*p)++*p
g)(*p)-- --(*p)--*p
如:
若有定义:
int b[5]={10,30,20,15,40};
int*q=b+2;
则:
++二级从右向左运算
q++表达式的值?,同时q指向了?----->(q++)--->20,b[3]
++q表达式的值?,同时q指向了?----->(++q)---->15,b[3]
(q)++表达式的值?同时q指向了?21,b[2]
++(q)表达式的值?同时q指向了?21,b[2]
例:
举例指针在数组中的使用:
main()
{int*p,a[3],I;
p=a;
for(i=0:i<3;i++) //for(i=0;i<3;i++)
scnaf("%d",p++); // scanf("%d",&a[i]);
printf("\n\n");
for(p=&a[0];p<a+3;) //for(i=0;i-3;i++)
printf("%d",*p++); //printf("%d",a[i]);
}
(4)若两个指针变量指向同一个数组,则这两个指针变量可以进行大小比较如:
char s[10];charpl=s+3,p2=&s[7];
则:
pl>p2=>0 pl<p2=>1
p1-p2=>-4 p2-p1=>4
(5)在形参中的数组实际上是一个指针变量,并不是真正的数组,因为该“数组名”的值是可以改变的,而真正的数组名的值是不能改变的。
(6)若形参是数组或指针变量,则在函数中可以通过该形参改变实参的值
三、多维数组与指针变量
如:int a[3][4];
a+1是跳过一行。因为二维数组名是行指针,加1是跳过一行不是一个元素切记:
①只有列指针才是“真正”指向元素。即指向某一个元素的存储单元
②一维数组名表示的是列指针;二维数组名表示的是行指针。
注:若a是一个二维数组,则有:
(1)a+i是行指针,即指向的是一整行。若对它加1则指向下一行
(2)*(a+i)和a[i]一样,都是一个列指针即指向的是一个元素,
(3)*(a+i)+j和a[i]+j一样,都表示元素a[i][j]的地址。即与&a[i][j]等价
*(a+i)+j a[i]+j &a[i][j]地址三等价
(4)*(*(a+i)+j)、*(a[]j)、(*(a+i))[j]和a[i][j]一样,都表示(元素四等价)
若有以下定义:
int w[2][3];
则对w数组元素非法引用是:E
A、*(w[0]+2)B、*(w+1)[2]C、w[0][0]D、*(w[1]+2)E、w[l]+2
1、指向多维数组元素的指针变量
如:
int a[31[4];
int*p=&a[0][3];
则:
p+1指向元素a[1][0];
p+4指向元素a[1][3]
p-2指向元素a[0][1]
常用于取二维数组a元素地址的方式:
&a[i][j]、a[i]+j、*(a+i)+j
例:
main()
{ int a[3][3]={1,2,3,4,5,6,7,8,9},*p;
for(p=a[0];p<a[0]+9;p++)
printf("%d",*p);
}
输出:123456789
2、指向由m个元素组成的一维数组的指针变量定义指向由m个元素组成的一维数组的指针变量的格式:
基类型(*指针变量名)[m];//行指针变量,指向该行m个元素
如:
int a[5][7];
int(*p)[7];
p=a;char b[10][80];
char(*r)[80];
r=b+5;
例:
main()
{
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
int(*p)[4];//行指针变量,指向四个元素
p=a;
for(i=0;i<3;i++)
{for(j=0:j<4:j++)
printf("%d",p[i][i]);
printf("\n");
}
}
例:
# include<stdio.h>
main()
{ int a[][3]={{1,2,3},{4,5,0}},(* pa)[3];
int i;
pa=a;
for(i=0:i<3;i++)
if(i-2) pa[1] [i]=pa[1][i]-1;
else pa[1][i]=1;.
printf("% d\n",a[0][1]+a[1][1]+a[1][2]);
}
7
3.指向字符串的指针变量
字符串常量:C语言对字符串常量是按首地址处理字符串常量
(1)char str[]="China
(2)char*p="China”;
(3)str="Chinese";
(4)p="Chinese";
(5)char *p= {"china"};错误:字符型变量的标志是双引号而不是花括号,=左边是地址变量,右边是常量,所以不合法
(6)char str[]={"china"};合法,数组的初始化,有“”出现时,花括号可加可不加,且数组长度为6
(7)char *p;*p="china";不合法,*p是取值,=右边是地址值,所以不合法
四、函数与指向函数的指针
五、指向函数的指针变量
函数名与数组名一样,是起始地址,而且是一个地址常量,函数地址
定义指向函数的指针变量的方式:
类型名(*指针变量名)();
辨认合法性
类型名(*指针变量名)();
类型名普通变量名;
类型名数组名[];
类型名*指针变量名;
类型名函数名()
{。。。。}
类型名(*指针变量名)[M];
例题:
int min(int a. int b)
{ retum a b?b:a}
int max(int a. int b)
{ return a-b?a:b;}
main()
{ int x=6,y=10;
int(*p)();
p=max;
printf("%d", max(x,y));
printf("%d",p(x,y));
p=min;
printf("%d", min(x,y));
printf("%d",p(x,y));
}
输出:101066
注:
(1)在定义指向函数的指针变量时,要注意有两个小括号必须要有,不需要定义形参。
(2)单独的函数名代表该函数的首地址(函数的入口地址)。
(3)函数的指针变量只能指向函数的入口处(函数的首地址),不能指向函数中的某条指令。(另对指向函数的指针变量加1是没有意义的)。
(4)给指向函数的指针变量赋值时,只写函数名即可,不必写参数。
六、返回指针的函数
类型名 函数名(形参)
返回指针的函数的定义方式为:
类型名 *函数名(形参列表)
{
return 地址值}
例:
int * fun(int *x, int *y)
{ lf(*x<*y)
return x;
else
return y;
}
main()
{ int a=7,b=8,*p,*q,*r;
p=&a;q=&b;
r=fun(p,q);
printf("%d,%d. %d\n",*p,*q,*r);
}
输出:7,8,7
七、指针数组和指向指针的指针变量
1、若一个数组的所有元素均为指针类型(地址),则称为指针数组。
格式:
类型名 *数组名[常量表达式];
int *s[10];
例1:类型名*数组名[常量表达式];
int*s[10];
例2:类型名 *指针变量名;
int *p;
例3:类型名数组名[常量表达式];
int s[10];
注:
(1)要注意它与定义指向由m个元素组成的一维数组的指针变量之间的区别
类型名数组名[常量表达式];
类型名(指针名)[常量表达式m];
(2)它的每个元素都是一个指针类型(地址),即它的每个元素都和当子一个指针变重。
int*a[10];
int a[10];
int a[10][10];
nain()
{char ch[3][4]={"123","456","78"},*p[3];
int i;
for(i=0;i<3;i++)
p[i]=ch[i];
for(i=0;i<3;i++)
printf("%s",p[i]);
}
输出:12345678
2、指向指针的指针变量
用来存放指针变量地址的指针变量称为指向指针的指针变量。
定义格式:
基类型名**指针变量名;
如:
int a=3;
int*p=&a;
int**k=&p;
则*k得到变量p(变量a的地址)。
**k得到变量a的值(a的数据3)
八、空指针
指针变量可以有空值,即指针变量不指向任何变量,不指向任何有用的存储单元
在系统中已将NULL定义为0,即NULL的值为0
int a,b,c,*P=NULL
此时p的值为空指针,即p不指向任何有用的存储单元。尽管NULL的值为0。但我们不能认为p指向了地址为0的存储单元。
注;
(1)当一个指针变量的值为空指针时,我们不能引用它所指向的存储单元。
(2)若某指针(地址)的基类型为void型,则有引用时应进行相应的强制类
例:
#include<stdio.h>
main()
{int a[l={1,2,3,4,5,6,7,8,9,10,11,12};
int*p=a+5,*q=NULL;
*q=*(p+5);
printf("%d%d\n",*p,*q);
}
输出:报错:因为q指针所指为空,不存在,因此不能进行写操作
网友评论