今天我们又要认识一下C语言中的一个重点加难点,是什么呢,就是指着,指针在我们以后的编程中会经常遇到,今天我们做一个简单的介绍,以后我们遇到相关文件再继续拓展。
什么是指针
- 计算机内存是以字节为单位的存储空间,内存的每一个字节都有一个唯一的编号,这个编号就称之为地址。当C程序中定义一个变量的时候,系统就分配一个带有唯一地址的存储单元来存储这个变量,程序对变量的读取操作(变量的引用),实际上是对变量所在存储空间进行写入或者兑读取。
- 通常我们引用变量的时候是通过变量名来直接引用变量,例如赋值运算b = 66,系统自动将变量名转换成变量的存储位置(即地址),然后再讲数据66放入变量b的存储空间中。这种引用变量的方式称为变量的“直接引用”方式。
- 此外,C语言中还有另一种称为“间接引用”的方式。它首先将变量A的地址存放在一个变量B(存放地址的变量称之为指针)中,然后通过存放地址的这个变量B来引用变量A。
- 一个变量的地址称之为该变量的指针。用来存放一个变量地址的变量称为指针变量。当指针变量p的值为某变量的地址的时候,可以说指针变量p指向该变量。
总结:
定义变量的本质:在内存呢中开辟出一块空间,并用一个变量名指向那一块空间。
内存空间的最小单位是字节,每一个字节都有一个自己的编号,这个编号称为地址。
有一种特殊的变量,这种变量专门存变量的地址,我们称之为指针变量,一般也称为指针。
指针的基本使用方式
指针的使用一般分为三步:
- 定义指针变量
- 给指针变量赋值
- 指针解引用
- 整个过程中需要使用到两个运算符:
&和*
定义指针变量
定义指针变量的格式为:类型名 *指针变量名;
int* p1;
char * p2;
注:
变量前面的
*
是一个说明符,用来说明该变量是指针变量,这个*
是不能省略的,但是这个*
不是变量名的一部分。
类型名表示该指针指向的变量类型,而且该指针只能指向该类型变量。
给指针变量赋值
之前在我们使用scanf_s
用到取地址符&
,这里我们也会用到这个符号来取一个变量的地址赋值给指针。
int nNum = 100;
int *p;
p = &nNum;//指针指向了变量nNum
我们也可以在指针初始化的时候对指针进行赋初值:
int nNumA;
char cChA;
int *p1 = &nNumA;
char *p2 = &cChA;
这里两个指针在初始化的时候就进行了赋值,p1赋值的是int型变量nNumA的地址,p2赋值的是char型变量cChA的地址。
指针变量的引用
这里我们需要用到符号有两个,一个是指针运算符*
,另一个是取地址符&
。
int a = 10;
int *p = 0;
p = &a;
int temp = *p;
//此时temp被赋值为10,也就相当于temp = a;
*p = 20;
//修改的是指针指向变量的内容,也就是修改a的内容,相当于a = 20;
注:
指针变量是用来存放地址的,所以不要给指针赋值常数值,但是赋值0相当于将指针指向NULL。
例如:*p = 10000;
指针没有指向一个确定的地址之前,不要对他的所指向的内容进行操作。
例如:int nNum = 5;int *p;*p = nNum;
示例:
int main()
{
//1 定义指针变量
int* p1 = NULL;
char * p2 = NULL;
int nNum1 =100;
int nNum2 = 0;
char cCh1 = 'm';
//2 给指针变量赋值
p1 = &nNum1;//指针存储了谁的地址,我们就说指针指向了谁
p2 = &cCh1;//存储了b的地址,指针指向了变量b
//3 解引用
*p1 = 10;
*p2 = 'm';
printf("%d", nNum1);
printf("%c ", *p2);
printf("%c", cCh1);
//4 修改指针变量
p1 = &nNum2;
*p1 = 300;
return 0;
}
指针与函数传参
指针是间接引用的,我么可以利用这一特性来进行参数传递,从而使得参数在函数内部的改变可以形象到函数外部。
void swap(int x,int y)
{
int temp;
temp = x;
x = y;
y = temp;
}
void main()
{
int a = 10;
int b = 20;
swap(a,b);
printf("%d,%d",a,b);
}
通过输出的结果我们可以看出来,这两个变量的值经没有改变。
void swap(int *x,int *y)
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}
void main()
{
int a = 10,b = 20;
swap(&a,&b);
printf("%d,%d",a,b);
}
在上面的这个例子中,我们通过向函数中传递了两个变量的地址,在函数中以指针的方式接受了两个变量的地址,通过两个变量的地址,我们可以找到两个变量的存储内容的空间,通过指针修改了两个变量的内容。
但是这中方式并没有使用形参修改实参的内容,因为在上面的例子中,实参是两个变量的地址,但是最终修改的不是两个变量的地址。
指针的运算与一维数组
指针是可以有数学运算的,但是它的运算和它的类型有关。
int a = 100;
int *p = &a;
p+1;
//这个时候进行p+1,不是对p指向的a的值加1,也不是p指向的地址加1,
//而是将指针指向的位置向后移动一个int,
//p+1计算方式为:p指向的的地址+sizeof(指针类型,这里是int),就相当于&a+4。
//所以p+1实际上地址加了4。
short b = 200;
short *p1 = &b;
*p1++;
//通过上面的计算方式,我们可以知道这里是地址加了2。
指针运算的方式设计为这样主要是为了数据访问的便利性,我们可以看一下指针和数组的操作。
int Arr[5] = {0,1,2,3,4};
int *p = Arr; //数组名就是数组首元素的地址
printf("%d",p[0]);//和数组中的Arr[0]一样
pritnf("%d",p[4]);
//使用指针的方式操作数组中的数据
printf("%d",*(Arr+0));//和p+0以及Arr[0]一样
printf("%d",*(Arr+4));
一维数组的数组名就是地址,并且一维数组名这个地址也是有类型的,就是一级指针类型。
总结
指针只是一个变量,这个变量是用来存放地址的。
指针复杂的地方在于:指针有多种多样类型。