一、指针是什么?
指针就是指向内存中某一个具体单元块的地址,并且指针变量是只存储地址的变量。
二、指针的申明
C语言的基本数据类型有三种:整数、实数、字符,因此在申明指针变量的时候,也要考虑其数据类型。
int *p; //指向整数型变量地址
float *q;//指向实数型变量地址
char *ch;//指向字符型变量地址
前面已经提到,既然指针变量只能存储地址,那么该怎么给初始化呢?--这里需要使用一个运算符‘&’叫做“取地址运算符”。
/*例如申明一个指向整数型的指针,并初始化*/
int i,j =26;
int *p;//申明变量p是一个指针变量,并且呢,只能存储整数型变量的地址
p = &i;//指针变量p指向变量i在内存中的地址
*p = 18;//给指针p指向的内存单元里,存放一个数字18,这其实等价于i = 18
//简单来说,就是通过指针间接地给变量i完成了初始化赋值操作。
需要特别强调的是:指针变量在使用之前,必须先初始化。因为指针指向的是某个具体内存块地址的,如果没有初始化,那么系统就不知道该指向哪个地址。
int *p;
*p = 5;//ERROR
/*这种没有给指针p初始化,却直接给*p赋值的做法是错误的。*/
/*原因在于,指针p没有明确的指向,那么就可以指向任何int类型的变量地址,
*这就会导致修改了不该修改的变量值,那么就会造成不可预知的问题
*/
三、指针有什么好处?
比较常见的有以下两种:
(1)指针作为实际参数传递;
/*
*假设我们有一个需求:希望构造一个函数,能够实现的功能是,分别取出实数的整数部分和小数部分。
*如果不使 *用指针的话,是没法实现的,因为调用函数之后,返回值的类型有两个,
*这显然跟函数定义的理论相悖。
*/
//使用指针,可以定义如下:
void decompose (float x, int *int_part, float *float_part)
{
*int_part = (int)x;//得到整数部分
*float_part = x -*int_part;//得到小数部分
}
/*在调用decompose函数的时候,需要给指针形式变量,传递实际变量的地址*/
//例如:
int main(void)
{
float number = 3.14159;
float f;
int i;
decompose(number,&i,&f);//传递变量i和f的地址
printf("f=%f,i=%d\n ",f,i);
return 0;
}
**当指针作为实际参数的时候,如果我们不希望通过调用函数,改变实际参数的值。那么可以利用const 关键字来修饰。例如:
void show (const int *p)
{
printf("%d\n",*p);//输出p指针指向的内存单元里的数值
//*p = 100;这种写法是错误的。因为在申明里指明,该指向的是“整型常量”的指针
}
同样的道理,如果我们希望保护指针本身的指向不被改变,也可以利用const来实现。例如:
void Demo (int * const p)//注意观察const位置
{
int j;
*p = 250;//这里给指针p指向的对象重新赋值是可以的
//p = &j;//这种写法是错误的,因为const 限制了p不能指向别的地址。
}
(2)指针作为返回值:当我们希望函数返回的结果是内存的某个位置而不是该内存单元里存储的具体值时,可以使用指针来实现。例如:
int *small (int *num1,int *num2)
{
if(*num1 < *num2)
return num1;//注意这里返回的是num1的地址,也就是指针num1
else
return num2;
}
(3)指向数组时,由于C语言允许对指针进行算术运算(加法、减法),这就可以让指针代替数组的下标,从而实现对数组的操作。