如果在程序中定义了一个变量,在对程序进行编译时,系统就会给这个变量分配内存单元,编译系统根据程序中定义的变量类型,分配一定长度的空间。内存区的每一个字节有一个编号,这就是“地址”,它相当于旅馆中的房间号,在地址所标志的内存单元中存放的数据则相当于旅馆房间中居住的旅客。
通过地址就能找到所需的变量单元,可以说,地址指向该变量单元,将地址形象化的称为“指针”,意思是通过它(指针)能找到以他为地址的内存单元。
比如:一个房间的门口挂了一个房间号2008,这个2008它房间的地址,或者说2008指向“该房间”。
注意:
对不同类型的数据,在内存中分配的存储单元大小(字节数)和存储方式是不同的,例如:整数以补码形式存放,实数以指数形式存放,如果指定地址1010,希望从该单元中调出数据,虽然可以找到指定的存储单元,但是无法确定是从一个字节中取信息还是两个字节取信息。为了有效存取一个数据,除了知道位置信息外,还需要该数据的类型信息,地址包括内存编号和它所指向的数据的类型信息或者说它是带“类型的地址”。例如:int a;&a表示变量a的地址,确切的说它是整型变量a的地址。
例如:
int a,float b;
分配到2000开始的存储单元中,&a和&b的信息不完全相同
虽然存储单元编号相同,但是他们的数据类型是不一样的
假设定义了整型变量i,j,k,20002003分配给i;20042007分配给j;2008~2011分配给k;
一般是通过变量名来引用变量的值printf(“%d\n”,i);
在编译的时候,系统分配4个字节给i,并建立了变量名和地址的对应表,因此在执行上面语句时,从该4个字节中按照整型数据的存储方式读出整型变量i的值,然后按十进制整数格式输出。
注意:对变量的访问都是通过地址进行的
打一个比方:
为了打开一个A抽屉,有两种办法,方法1是将A钥匙带在身上,需要时直接找出该钥匙打开抽屉,取出所需的东西,这就是“直接访问”,方法2是,为了安全起见,将A钥匙放到另一个抽屉B中锁起来,如果需要打开A抽屉,就需要先找出B钥匙,打开B抽屉,取出A钥匙,在打开A抽屉,取出A抽屉中的东西,这就是“间接访问”。
直接按变量名进行的访问,称为“直接访问”
依然是上面的例子,如果输入
printf("%d",&i);
//在执行时,把键盘输入的值送到地址为2000开始的整型存储单元中国
k = i + j;
//从2000~2003字节取出i的值,再从2004~2007取出j的值,相加后送到k所占用的2008~2011字节单元中
如果是将变量i的地址存放到另一个变量中,然后通过变量来找到变量i的值,从而访问i变量的方式称为“间接访问”。
用一个来存放整型变量的地址
i_pointer = &i;
//把i的地址(2000)存放到i_pointer中
//i_pointer的值就是2000(即是变量i所占用单元的起始地址)
//间接访问i的值:
先找到存在“变量i的地址”的变量i_pointer,从中取出i的地址,然后在2000字节开始的存储单元中取出i的值
为了表示将数值为3送到变量中,有两种方式
(1)直接访问:将3直接送到变量i所标识的单元中,如i=3。这是根据变量名直接向变量i赋值,由于变量名与变量的地址有一一对应的关系,就按此地址直接对变量i的存储单元进行访问。
(2)间接访问:将3送到变量i_pointer所指向的单元(即变量i的存储单元),例如“*i_pointer = 3”,其中 *i_pointer表示i_pointer指向的对象。
指向就是通过地址来体现的,假设i_pointer中的值是变量i的地址(2000),这样就在i_pointer和变量i之间建立一种联系,即通过i_pointer能知道i的地址,从而找到变量i的内存单元。
由于通过地址就能找到所需的变量单元,因此说,地址指向该变量单元(如同一个房间号指向某一房间一样),将地址形象的称为“指针”。意思是通过指针就能找到以它为地址的内存单元(如同根据地址2000就能找到哦啊变量i的存储单元一样)。
如果有一个变量专门用来存放另外一个变量的地址(即指针),则称它为“指针变量”,i_pointer就是一个指针变量。指针变量就是一个地址变量,用来存放地址,指针变量的值是地址(即指针)。
即:指针是一个地址,而指针变量是存放地址的变量
指针变量的定义:
存放地址的变量是指针变量,它是用来指向另一个对象(如变量,数组,函数等)。
例如:通过指针变量访问整型变量
#include
int main()
{
int a=100,b=10;//定义整型变量a和b,并且初始化
int *p1,*p2;//定义指向整型数据的指针变量p1和p2
p1 = &a;//把变量a的地址赋给指针变量p1
p2 = &b;//把变量b的地址赋给指针变量p2
printf("a=%d,b=%d\n",a,b);//输出ab的值
printf("*p1=%d,*p2=%d\n",*p1,*p2);//输出变量ab的值
return 0;
}
"*"表示指向
"*p1"表示指针变量p1所指向的变量,也就是变量a,
*p2同理。
int *p1,*p2;//表示定义了两个指针变量
printf("*p1=%d,*p2=%d\n",*p1,*p2);//表示指针*p1和*p2所指向的变量
注意:
在定义指针变量的时候,一定要指定指针变量的类型。
形式:
类型名 *指针变量名;
例如:
int *p1,*p2;
//int是指针的基本类型,表示指针变量可以指向的变量的类型。
//*p1和*p2可以指向整型的变量i和j,不能指向浮点类型的a和b
注意:
(1)*表示该变量为指针型变量
(2)定义指针变量时候必须指定类型,因为不同数据类型在内存中所占的字节数和存放方式是不一样的。
(3)一个变量的指针包含两个方面:一是以存储单元编号表示纯地址,一是它指向的存储单元的数据类型(int,char等)
(4)指向整形数据的指针类型表示为"int *",读作指向int的指针或者简称int指针,其他类型的同理。
(5)指针变量中只能存放地址指针,不要将一个整数赋给一个指针变量,因为从形式上看整数只能赋给整形变量,而不能赋给指针变量,地址只能用地址符号"&"得到并赋给一个指针变量例如:”p=&a“;
熟练掌握运算符
(1)&,取地址运算符,&a是变量a的地址
(2)*,指针运算符(间接访问运算符)
(3)*p表示指针变量p指向的对象
(1)给指针变量赋值
p=&a;
//把a的地址赋值给p,指针变量p的值是变量a的地址,p指向a
(2)引用指针变量指向的变量
p=&a;
printf("%d",*p);//以整数形式输出指针变量p所指向的变量的值,即变量a的值
*p=1;//把1赋给p当前所指向的变量,相当于把1赋给a,即a=1
(3)引用指针变量的值
p = &a;
printf("%o",p);//以八进制数形式输出指针变量p的值,即输出a的地址
方法一:用指针的方法处理这个问题,不交换整型变量的值,而是交换两个指针变量的值
#include
int main()
{
int *p1,*p2,*p;//定义的三个int*类型的指针变量
int a,b;
printf("please input two number:");
scanf("%d%d",&a,&b);
p1 = &a;//p1指向a的地址
p2 = &b;//p2指向b的地址
if(a<b)
{
p=p1;
p1=p2;
p2=p;
//可以不用定义中间变量
//p1=&b;p2=&a
}
printf("a=%d,b=%d\n",a,b);
printf("max=%d,min=%d\n",*p1,*p2);
return 0;
}
方法二:利用指针作为函数参数
#include
void swap(int *p1,int *p2){
int temp;
temp = *p1;
*p1 = *p2;
*p2 =temp;
}
int main(void)
{
int a,b;
printf("please input two number:");
scanf("%d%d",&a,&b);
int *p1,*p2;
p1 = &a;//把a的地址赋给p1
p2 = &b;//把b的地址赋给p2
if(a<b)
{
swap(p1,p2);
}
printf("a=%d,b=%d\n",a,b);
return 0;
}
注意:
void swap(int *p1,int *p2){
int *temp;//没有初始化,是野指针
*temp = *p1;
p1 = *p2;//‘int *’ from ‘int类型不匹配
p2 =*temp;
}
void swap(int *p1,int *p2){
int *temp=NULL;//error
//改为:
//int *temp=(int *)malloc(sizeof(int));
*temp = *p1;
*p1 = *p2;
*p2 =*temp;
}
指针定义为NULL的时候,表示为空指针,指向的是一个零地址,零地址是没有存储空间的,指针指向零地址是不可用的,读写都不能,也不能访问。
malloc是在堆区连续的开辟空间,空间可以赋初值为0,但是它就不叫0地址,空间连续后是可以用的,0地址是没有连续空间的,所以是不能用的。
void swap(int x,int y)
{
int temp;
temp = x;
x=y;
y=temp;
}
函数调用时,a的值传给x,b的值传给y,x和y的值是交换了,但是a和b的值是没有交换的,因为在函数结束的时候,x和y释放了,形参的值并没有改变实参
如何调用函数得到要改变的值:
①通过形参改变实参,使用指针变量
②设计的函数的形参为指针类型的
void swap(int *p1,int *p2){
int *temp=(int *)malloc(sizeof(int));
temp = p1;
p1 = p2;
p2 =temp;
}
,b的值传给y,x和y的值是交换了,但是a和b的值是没有交换的,因为在函数结束的时候,x和y释放了,形参的值并没有改变实参
[外链图片转存中…(img-hNXi52xQ-1660563958276)]
如何调用函数得到要改变的值:
①通过形参改变实参,使用指针变量
②设计的函数的形参为指针类型的
void swap(int *p1,int *p2){
int *temp=(int *)malloc(sizeof(int));
temp = p1;
p1 = p2;
p2 =temp;
}
实参变量和形参变量之间的数据传递是单向的“值传递”,用指针变量作为函数参数也应该遵从这一规则。