⛺️生活的理想,就是为了理想的生活!
文章目录
- 📋 前言
- 💬 指针运算
- 💭 指针+-整数
- 💭 指针-指针
- 💭 指针的关系运算
- 💬 指针和数组
- 💭 指针和数组变种推演
- 💭 指针和数组的关系
- 💬 二级指针
- 💬 二级指针的运算
- 📝全篇总结
📋 前言
🌈hello! 各位宝子们大家好啊,前面给大大家介绍了指针的基础知识。那么这一章就来给大家介绍下一部分内容! ⛳️指针的运算 以及 数组与指针的关系 也是我们在指针的学习过程中非常重要的!
💬 指针运算
💭 指针±整数
其实在上一章我们就见过指针加减整数了对于 type * p 的指针想要加n
减n
是这样计算的
- n*sizeof(type)
📚 代码演示:
#include <stdio.h>
int main()
{
int arr[10] = { 0 };
int* p = &arr[0];
//不用下标访问
int sz = sizeof(arr) /sizeof(arr[0]);
int i = 0;
for (i = 0; i < sz; i++)
{
*p = i;
p = p+1;
}
p = &arr[0];
for (i = 0; i < sz; i++)
{
printf("%d\n",*(p+i));
}
return 0;
}
这里我们就使用指针加减整数的方式来进行访问数组进行赋值
- 每次让指针p 向前指4个字节,然后进行赋值!
- 之后再把指针p 归位到最开始的指向位置进行访问
前面的例子懂了我们再来看这个例子大家看看! 📚 代码演示:
#define N_VALUES 5
float values[N_VALUES];
float *vp;
//指针+-整数;指针的关系运算
for (vp = &values[0]; vp < &values[N_VALUES];)
{
*vp++ = 0;
}
这个例子其实和前面很像,数组中是从地址值向高地址使开辟的一份连续的空间!这里我们把 数组的第一个地址赋给指针 p
- 所以指针
p
肯定没有 &values[5]的地址大! - 而
p++
每次向前指向下一个元素给每个元素赋值,直到把前五个都赋完!
💭 指针-指针
指针加减整数的例子我们了解完了,下面就来了解了解指针加减指针的应用把!
- 不知道大家了解个库函数strlen 的实现嘛/
- 今天就用指针-指针的方法实现一下!
📚 代码演示:
#include <stdio.h>
int my_strlen(char* s)
{
char* p = s;
while (*p != '\0')
p++;
return p - s;
}
int main()
{
char arr[] = "abcdef\0";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
⛳️ 诶这里就巧妙的应用了指针里面存放的地址来进行减法运算,用差做取值。刚好能求字符的长度的。
- 因为一个字符也就只能只能存放一个字节
- 而每一个字节都有地址连续的空间地址就是递增的!
💭 指针的关系运算
指针减指针的运算我们学了其实指针的运算还有一条规定:C语言标准规定:
- 允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
- 我们来看一下这段代码:
📚 代码演示:
for(vp = &values[5-1]; vp >= &values[0];vp--)
{
*vp = 0;
}
这段代码有什么问题呢?其实这段代码是倒着往回赋值的从数组 values[4],一直向后赋值但是
- 当最后一个元素 values[0] 赋完值的时候
- 循环调整部分
vp--
还会执行一次导致vp
成为野指针 - 所以,当我们在次想用
vp
的是就需出现访问越界的问题!
📚 代码改进:
for(vp = &values[5-1]; vp > &values[0];)
{
*--vp = 0;
}
这样当指针 vp 赋完值之后就不会再进行减减的动作了。因为根本就进不来循环里面所以想前面的错误我们就避免了。 🔥 但是:这并不符合C语言的标准,所以我们尽量不要这样写以免有些编译器跑不过去。
💬 指针和数组
📚 代码演示:
#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
printf("%p\n", arr);
printf("%p\n", &arr[0]);
return 0;
}
📑 代码结果:
⛳️ 诶这里就可以看到,其实数组名和数组第一个元素的地址是一样,所以可见数组名和数组首元素的地址是一样的。
- 那么这样写代码是可行的:
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr;//p存放的是数组首元素的地址
//等同于 *p= &arr[0];
💭 指针和数组变种推演
而指针是用来存放地址的,数组又是一块连续的空间。所以我们可以拿指针变量来接收数组首元素的地址,用来遍历数组!
- 所以我们对指针解引用 和 数组下标是相等的。
- arr[ i ] == *(p+i)
- 而 *(i+p) == arr[ i ]
- 所以 *(i+p) == i[ arr ]
- 而 : p == arr == &arr[ 0 ]
- 所以 *() 操作符 等同于 [ ]
📚 代码演示:
#include <stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,0 };
int* p = arr; //指针存放数组首元素的地址
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i < sz; i++)
{
arr[i] = i;
printf("%d %d %d %d\n",arr[i],i[arr],*(p+i),p[i]);
}
return 0;
}
📑 代码结果:
- 既然这俩个操作符是相等的那么又能推演出:
- *(arr+i) == arr[ i ] == *(i+arr) 🔥 注:这里就不给大家演示了,大家可以自己去试着练一下呢。
💭 指针和数组的关系
⛳️前面我们看到了,数组和指针的应用也给大家带来不一样的数组写法是不是很有趣!那么他们究竟有什么关系?既然指针和数组使用使用起来一样的效果那么我们可以把指针理解为数组嘛?
- 其实我们可以这样理解
- 指针变量就是指针变量,不是数组。指针变量的大小是4/8个字节,是用来专门存放地址的.
- 数组就是数组,不是指针,数组是一块连续的空间。可以存放一个或,多个类型相同的数据。
🔰 那么他们的联系是什么?
- 🌱 数组中,数组名其实是数组首元素的地址,数组名 == 地址 == 指针
- 🌱 当我们知道数组首元素地址的时候,因为数组又是连续存放的,所以通过指针就可以来遍历访问我们的数组。
💬 二级指针
⛳️ 指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?答案是二级指针,存放指针变量的地址我们叫做二级指针!
📚 代码演示:
#include <stdio.h>
int main()
{
int a = 10;
int* p = &a;//p是一级指针变量,指针变量也是变量,
//变量是在内存中开辟空间的,是变量就有地址
int** pp = &p;//pp就是二级指针变量,
//二级指针变量就是用来存放一级指针变量的地址
return 0;
}
⛳️ 二级指针变量就是用来存放一级指针的地址,那么怎么来理解 int**
- int** 第一个 int* 说明了
pp
是个指针变量 - 而第二个
*
则说明了pp
里面存放的是指针变量的地址
💬 二级指针的运算
所以我们对 pp 指针解引用一次是找到一级指针的内容
- 所以:*pp 等价于 p == &a
所以我们想用二级指针找到一级指针所指向的对象 a 就需要进行俩次解引用
📚 代码演示:
#include <stdio.h>
int main()
{
int a = 10;
int* p = &a;
int** pp = &p;
**pp = 100;
printf("%d", a);
return 0;
}
📑 代码结果:
📝全篇总结
✅ 归纳: 好了以上就是关于指针的运算 数组和指针的关系 以及 二级指针的概念我们就全讲解完毕了! 指针的运算数组和指针的关系二级指针
☁️ 本章的内容就是这么多啦!不知道大家了解了没有呢?有不懂的可以私信评论嗷!