一、指针的概念
1、地址: 在计算机中,为了方便管理内存,内存被划分为以字节为单位的内存空间,也就是说是一个内存单元,而每一个内存单元的大小是一个字节,为了方便找到每个内存单元,我们给他们都编了一个特定的编号,这里的编号就是他们的地址,而地址在c语言中被称为指针。
2、&:变量创建的本质就是在内存中开辟空间,所以说每个变量都有他们特定的地址,而我们对于的他们的地址的获取要使用&(取地址操作符)。如下面的代码,我们就可以获得变量a的地址。对于a来说,因为a是整形变量,在内存中占四个字节,而我们拿到的是a四个字节第一个字节的地址(地址较小的地址)。
#include "stdio.h"
int main()
{
int a=0;
printf("%d\n",&a);
}
3、*:我们通过指针变量来存放变量的地址。这里的p就是指针变量,存放的a的地址,这里p的数据类型为int*,int表示p指向的对象为int类型,而*表示p为指针变量。*是解引用操作符/间接访问操作符,*p就是通过p中存放的地址,找到地址指向的空间(a)。
#include "stdio.h"
int main()
{
int a=0;
int* p=&a;
}
4、指针变量:对于指针变量大小来说,因为指针变量是用来存放地址,指针变量大小取决于地址需要多大空间,不同环境下,存放地址的空间不同。
(1)在x86环境中,地址都是32个0/1组成的二进制序列,也就是需要4个字节,所以此时指针变量大小为4个字节。
(2)在x64环境中,地址都是64个0/1组成的二进制序列,也就是8个字节,所以此时指针变量大小为8个字节。
指针变量大小都是4/8个字节,与类型无关,在相同环境中,大小都是相同的。
指针变量的类型决定了指针+1/-1一次跳过几个字节,如int*类型指针变量+1,跳过4个字节,char*指针变量+1,跳过1个字节。
5、const修饰指针:const修饰变量使变量不能被修改。
当const放在*左边时候,说明可以改变p1的指向(p1),但不能改变p1指向的内容(*p1);
而const在*右边时候,可以改变p2的指向的内容(*p2),但不能改变p2指向(p2)。.
const int* p1=&a1;
int* const p2=&a2;
二、指针的运算
1、指针+-整数
指针变量加1,向后移动1*sizeof(指针变量指向元素的数据类型)字节。
指针变量减1,向前移动1*sizeof(指针变量指向元素的数据类型)字节。
2、指针-指针
指针减指针的绝对值是指针之间元素的个数。
如下面代码,ret的值就是指针之间元素的个数9。
int arr[0];
int* p1=&arr[1];
int* p2=&arr[2];
int ret=p2-p1;
三、野指针
1、野指针就是指向的位置不可知、随机的,指向已被释放的内存空间的指针。
2、野指针是由于指针未初始化、指针越界访问、指针指向的空间被释放导致。
3、如何规避野指针
对指针进行初始化。
小心指针越界。
指针变量不再使用,及时置NULL,指针使用前检查它的有效性。
避免返回局部变量。
四、指针的使用
1、传址调用
这里我们通过交换两个数来展示传址调用的作用。
#include <stdio.h>
void Swap2(int*px, int*py)
{
int tmp = 0;
tmp = *px;
*px = *py;
*py = tmp;
}
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
printf("交换前:a=%d b=%d\n", a, b);
Swap1(&a, &b);
printf("交换后:a=%d b=%d\n", a, b);
return 0;
}
这里交换两个数字只可以使用传址调用,而不可以使用传值调用,因为对于传值调用来说,形参的改变不影响实参,所以无法通过函数的传值调用来交换两个数字。
2、strlen的模拟实现
strlen函数是测量字符串长度,会一直向后找\0字符,直到找到为止。根据定义我们可以写出my_strlen函数来模拟strlen函数,具体代码如下
#include "stdio.h"
size_t my_strlen(char* str)
{
size_t count = 0;
while (*str != '\0')
{
count++;
str++;
}
return count;
}
int main()
{
char arr[] = "hello";
size_t ret = my_strlen(arr);
printf("%d\n", ret);
}
五、常规的指针变量
1、二级指针变量
指针变量就是用来存放变量的地址,而指针变量自身也有地址,只有我们就要使用二级指针变量来存储指针变量的地址。
如下面代码所示,这里的pp就是二级指针变量,它存储的就是指针变量p的地址,同样和指针变量定义相似,int*表示它指向的是指针变量p的数据类型,第二个*表示pp是指针变量,同样还有三级指针int** *ppp=&pp;但三级指针以上就运用很少了。
int a=0;
int*p=&a;
int* *pp=&p
2、字符指针变量
这里有两种类型:
一种是存放字符的地址,如这里p就是存放ch的地址。
另一种就是存放字符串的地址,而这里的pp是将字符串的首元素a的地址存放在p中。此时的*p就是a,并且此时字符串"abcdefgh"是常量字符串,不可以被更改。
char ch='a';
char*p=&ch;
char* pp="abcdefgh";
3、数组指针变量
数组指针变量核心就是就是指针变量,是指向数组的指针,存放的数组的地址。
定义如下:这里的定义我们类比整型指针变量的定义,int* p;int是p指向元素的数据类型,*说明p是指针变量,而数组指针变量也是指针变量,所以*p表明是指针变量,int是数组元素的类型,[10]表示数组元素个数,这里其实其实就是把int [10]看作是数组的数据类型来理解,这样就和指针变量的总体定义相符合。
int arr[10]={0};
int (*p) [10]=&arr
同样,下面代码同理。
char ch[8]={0};
char (*p2) [8]=&ch;
4、函数指针变量
函数指针变量也是指针变量,指向函数的指针,存放的是函数的地址。
特别的是,对于函数来说,&函数名和函数名都表示函数的地址。
这里对于函数指针变量定义,*p表示p是指针变量,int表示函数返回值类型为int,(int x,int 有),表示指向函数的参数类型以及个数。
int Add(int x,int y)
{
return x+y;
}
int main()
{
int(*p)(int x,int y)=&Add;
}
这里通过p(3,4)来实现函数的使用。
六、指针数组
1、指针数组
指针数组就是存放指针的数组,与整型数组定义相似就是存放元素的类型 数组名[数组元素个数]。指针数组每个元素都是地址。
int* arr[20];
char* p[5];
指针数组可以用来模拟二维数组具体的代码如下:
#include "stdio.h"
int main()
{
int arr1[] = {1,2,3,4,5};
int arr2[] = {2,3,4,5,6};
int arr3[] = {3,4,5,6,7};
int* parr[3] = {arr1, arr2, arr3};
int i = 0;
int j = 0;
for(i=0; i<3; i++)
{
for(j=0; j<5; j++)
{
printf("%d ", parr[i][j]);
}
printf("\n");
return 0;
}
2、函数指针数组
函数指针数组就是存放都是函数指针变量的数组
int (*) (int,int)是函数指针变量数据类型,所以具体定义如下:
int (* parr[4])(int x,int y)={Add,Sub,Mul,Div};
其中的Add,Sub,Mul,Div都是函数的地址。
这里我们可以用函数指针数组去实现
计算器的简单应用
具体代码如下:
int add(int x, int y)
{
return x + y;
}
int sub(int x, int y)
{
return x - y;
}
int mul(int x, int y)
{
return x * y;
}
int div(int x, int y)
{
return x / y;
}
int main()
{
int x = 0;
int y = 0;
int count = 0;
int ret = 0;
int(*p[5])(int x, int y) = {0,add,sub,mul,div};
do
{
printf("*************\n");
printf("****1.add****\n");
printf("****2.sub****\n");
printf("****3.mul****\n");
printf("****4.div****\n");
printf("****0.exit***\n");
printf("*************\n");
printf("请输入你的选择\n");
scanf("%d", &count);
if (count >= 1 && count <= 4)
{
scanf("%d %d", &x, &y);
int ret=p[count](x, y);
printf("%d\n", ret);
}
else if (count == 0)
{
printf("退出使用");
}
else
printf("输入数字有误,请重新输入\n");
} while (count);
}
这里使用函数指针数组很大程度简化了代码。
对于指针的讲解就告以段落,对于指针在c语言中有着举足轻重的地位,我们深入了解指针,熟练运用指针,之后博主会发布一些关于指针的笔试题来加深大家对指针的理解。如果大家认为博主写的还不错的话,可以点赞支持一下博主,谢谢大家支持哦。