C语言指针个人理解
文章目录
- 一、什么是指针?
- 二、定义指针变量
- 三、指针变量的赋值
- 四、指针变量的引用
- 二级指针:
- 五、指针和一维数组
- 5.1 位置差
- **利用位置差实现数组的逆置**
- 六、指针和二维数组
- 二维数组元素地址表示方法
- 二维数组元素表示方法
- 七、指针数组和数组指针
- 7.1指针数组
- 7.2数组指针
- 八、数组名作函数实参
- **求数值之和**
- **利用指针编写函数最数组最大值以及其下标**
- **实现删除第n个元素**
- **实现冒泡排序**
- 九、指针函数和函数指针
- 9.1指针函数
- 9.2函数指针
一提到C语言,很多人第一时间想到的就是指针。究其根本就是指针以复杂著称,本人也是学习完第一遍之后也是和大多数人一样云里雾里,做题时也是一窍不通,后来有又多刷了几遍然后就豁然开朗,做题正确率也是十分的高。所以说学习指针真正诀窍在于学他个三五遍
本人的指针讲解严格意义上来讲根本不算是讲解,只是我个人的一个笔记罢了。
因为指针这个东西偏概念性,所以文字不好叙述,我在这里只会讲指针的大概,主要意图是为了供自己复习使用。
想看指针详细讲解的同学,可以去看这篇大哥的讲解 CSDN大神指针详细讲解,本篇文章适合有基础的同学进行观看。
一、什么是指针?
指针通俗来讲就是地址,指针就是地址,地址就是指针
。我们定义了一个变量,系统对变量进行编译
的时候就会给这个变量分配内存单元,内存若是一个公寓,那么内存单元就是公寓的一间间屋子,而指针就是公寓的“ 门牌号 ”。
二、定义指针变量
指针变量 : 含义就是存放变量地址的变量,本质仍然是变量
指针变量格式:
数据类型 *指针变量名 //eg int *a; 比普通的变量定义 多一个*,这里的*就是表示该变量为指针变量
注:若数据类型为void类型则表示该指针变量为空类型
指针变脸所占的字节数:
TC系统 | VC系统 |
---|---|
2字节 | 4字节 |
注:指针变量所占字节数和数据类型无关
三、指针变量的赋值
前面我们提到过指针变量保存的是变量的地址而非变量的元素数值,所以我们要把元素的地址给提取出来然后才可以进行下一步的赋值操作,这时候取地址运算符就应该现身了 &。
取地址运算符 | & |
---|---|
优先级 | 整数第二 |
结合性 | 从右往左 |
作用 | 获取变量的地址 |
用法很简单就是把变量的地址利用取地址运算符获取到然后再赋值给指针变量就可以达到赋值的操作。
举个栗子
int a=6,*p=&a; //这时就把a的地址赋值给了指针变量p,指针变量p也就指向了元素a
注意!!!
1.&a赋值给的时指针变量p而不是* p, *只是起到定义作用
2.变量的数值类型要和指针的数值类型保持一致
3.若定义了一个指针变量等于NULL,则代表该指针为空指针,NULL的数值为0
4.上面例子的p = &a,输入数据时可等同使用
四、指针变量的引用
访问变量有直接访问
和间接访问
两种
指针运算符/简介访问运算符/取内容运算符 | * |
---|---|
优先级 | 正数第二 |
结合性 | 从右往左 |
作用 | 获取指针所指向对象的内容 |
这时候估计就会有很多同学就懵了,这个*一会代表定义指针变量,一会代表取内容运算符,到底算个神魔东西啊,不要慌请看下面表格便一目了然。
Please look at the table below
双目内为乘法 | a*b |
---|---|
前有数据类型,后为定义的为指针 | *p |
定义之外且为单目运算符 | 取内容运算符 |
举个栗子
int a=5;
int *p=&a;
peintf("%d\n",*p); //结果就为5,因为去内容运算符*就是取指针所指向的内容,指针指向a,a的内容为5,所以结果为5
二级指针:
格式:
int **q;
含义就是指向指针的指针,内部保存的就是指针的变量地址
int a=6;
int *q=&a;
int **p=&q;
printf("%d\n"**q); //**q可以看成*(p)就是取q指针所指向内容,此时q指向q
五、指针和一维数组
重点!!!
一维数组的本质时内存中连续的存储单元,而一维数组的名字就代表一维数组的首地址,知道了首地址我们自然可以推算出其他数组元素的地址。
举个例子
int a[5];
第一种一维数组元素表示方法
a[0] | a[1] | a[2] | a[3] | a[4] |
---|---|---|---|---|
a(一维数组名) | a+1 | a+2 | a+3 | a+4 |
第二种一维数组元素表示方法
&[0] &[1] &[2] &[3] &[4]
5.1 位置差
指向同一个数组的两个指针可以做差,其含义是两个元素的元素差
设int *q,*p;
p==q | p和q指向同一个位置 |
---|---|
p<q | p的位置指向在q指向位置的前面 |
p>q | p的位置指向在q指向位置的后面 |
利用位置差实现数组的逆置
#include <stdio.h>
int main()
{
int a[8]={1,2,3,4,5,6,7,8};
int *p,*q;
int t,i;
p=a;
q=a+7;
for (;p<q;p++,q--) //利用的就是位置差
{
t=*p; *p=*q; *q=t; //交换的是内容
}
for (i=0;i<8;i++)
{
printf("%d\t",a[i]);
}
}
六、指针和二维数组
重点!!!
二维数组名代表首行地址(第0行) ,且为地址常量(不可更改值)
二维数组元素地址表示方法
二维数组元素地址第一种表示方法:
二维数组元素地址第二种表示方法:
&[0][0] ~&a[1][2]
二维数组元素地址第二种表示方法:
a[i]+j 代表a[i][j]的地址 – 常考
二维数组元素表示方法
二维数组元素第一种表示方法 | 二维数组元素第二种表示方法 | 二维数组元素第三种表示方法 |
---|---|---|
*( *(a+i)+j) | a[i][j] | *( a[i]+j) |
七、指针数组和数组指针
7.1指针数组
指针数组本质仍未数组,该数组的每一个元素都是指针变量用于存储指针变量,不可保存常量,且数组名不可被赋值。
举个栗子
int *p[5]; //该数组有五个int型的元素,每个元素存储的都是指针变量
int q[4]; //普通数组
若要把q[2]元素的地址赋值给p[1]应该如何做?
答:p[1]=&q[2]; //一定要保证要精确赋值,且需要把变量地址赋值给指针数组
来个小题测验一下
//本质还是数组,只不过是存放指针变量的特殊数组
//格 式 : [数据类型] *p[4] --比普通数组多一个 * 用于定义
#include <stdio.h>
int main()
{
int a[10]={1,2,3,4,5,6,7,8,9,10},i;
int *p[3]; //数组中有*为指针数组
for (i=0;i<3;i++)
{
p[i] = a+(i*2+1); //目标p[0]p[1]p[2]分别保存2 4 6
}
for (i=0;i<3;i++)
{
printf("%d\t\n",*p[i]); //输出2 4 6
}
for (i=0;i<3;i++)
{
printf("%d\t",p[i][2-i]); //p[i]指向的为起始位置,输出起始位置往后数2-i个位置的元素 结果输出4 5 6
}
}
7.2数组指针
不太重要,认识格式即可
本质为指针,该指针指向了一个
一维
数组,数组指针是行指针
形式:
数据类型 (*指针名)[常量表达式];
举个栗子
int (*p)[5]; //p是一个指针,该指针指向了一个int型的一维数组,该数组有五个元素
利用数组指针遍历二维数组的值
//本质为指针,该指针指向了一个一维数组 -*一维-
/*该指针指向了一个一维数组,所以数组指针是一个行指针,
二维数组也是行指针,因为二维数组是由多个一维数组堆叠而成的*/
//格 式: int (*p)[5] -比指针数组多一个小括号-
#include <stdio.h>
int main()
{
int a[2][3]={1,2,3,4,5,6},i,j;
int (*p)[3];
p=a;
for (i=0;i<2;i++)
{
for (j=0;j<3;j++)
{
printf("%d\t",p[i][j]);
}
}
}
八、数组名作函数实参
数组名作为函数的实参,传递的是该数组的首地址(首元素的地址)
没什莫新奇知识点,直接上例题
求数值之和
#include <stdio.h>
int fun(int a[],int n)
{
int i,sum=0;
for (i=0;i<n;i++)
{
sum+=a[i];
}
return sum;
}
int main()
{
int i,s;
int b[6];
printf("请输入6个数组元素:\n");
for (i=0;i<6;i++)
{
scanf("%d",&b[i]);
}
s = fun(b,6);
printf("元素之和为:%d",s); //求键盘输入数据之和
return 0;
}
利用指针编写函数最数组最大值以及其下标
//全局变量方法
// #include <stdio.h>
// int d;
// int max(int a[],int n)
// {
// int m,i;
// m=a[0];
// for (i=0;i<n;i++)
// {
// if (m < a[i])
// {
// m = a[i];
// d = i;
// }
// }
// return m;
// }
// int main()
// {
// int b[]={3,4,6,5,9},n=5,z;
// z = max(b,n);
// printf("数组最大值为:%d\n元素下标为%d\n",z,d);
// }
//指针方法
#include <stdio.h>
int max(int a[],int n,int *p)
{
int m,i;
m=a[0];
*p = 0; //赋初值防止随机数捣乱
for (i=0;i<n;i++)
{
if (m < a[i])
{
m = a[i];
*p = i;
}
}
return m;
}
int main()
{
int b[]={3,4,6,5,9},n=5,z,k;
z = max(b,n,&k);
printf("数组最大值为:%d\n元素下标为%d\n",z,k);
}
实现删除第n个元素
#include <stdio.h>
void fun(int a[],int n,int z)
{
int i;
for (i=n;i<z-1;i++) //应该是z-1,不减一的话,下面需要吧a[5]的值赋给a[4],上哪里去找a[5]的值?
//并且该编程需要最后一位的值肯定会赋值给前一位,最后一位怎末都要被舍弃的
{
a[i] = a[i+1];
}
}
int main()
{
int b[5]={1,2,3,4,5};
int n,i;
printf("请输入想要删除元素位数:\n");
scanf("%d",&n);
fun (b,n-1,5);
for (i=0;i<4;i++)
{
printf("%d\t",b[i]);
}
return 0;
}
实现冒泡排序
#include <stdio.h>
void sort(int a[],int n)
{
int i,j,t;
for (i=0;i<n-1;i++)
{
for (j=0;j<n-1-i;j++)
{
if (a[j] > a[j+1])
{
t=a[j]; a[j]=a[j+1]; a[j+1]=t; //老模板啦,记忆即可
}
}
}
}
int main()
{
int i;
int b[]={2,5,7,1,-4,45,24};
sort(b,7);
for (i=0;i<7;i++)
{
printf("%d\t",b[i]);
}
}
九、指针函数和函数指针
9.1指针函数
含义:函数可以返回整数值、字符值等 当然也可以返回指针型的数据也就是
返回地址
,返回地址的函数就叫做指针函数
格式:
数据类型 *函数名(参数列表);
老规矩 举个例子
int *fun(int a,int b[]); //fun是一个指针函数,该函数返回了一个int型的指针
注意:
1.返回的地址是指针所指向的地址
2.主调函数内接受的是一个地址,所以在主调函数内应该用 * 进行提取
9.2函数指针
本质是指针,该指针指向一个函数
举个例子
int (*p)(int a,int b); //p是指针名,该指针返回了一个int型的函数