一.指针运算🌴
1.曾经用过的案例:写一个模拟实现字符串的函数
前提说明:字符串在传参的时候,或者说作为一个表达式的时候,它的值是首字符的地址,它并不是把“abcdef”传给了my_strlen函数,而是把首字符'a'的地址传过去了,首字符'a'的地址是char类型的地址,需要一个char*的指针接收
#include<stdio.h> int my_strlen(char* str) { int count = 0; while (*str != '\0') { count++; //str++;//指针+整数 str = str + 1; } return count; } int main() { int len = my_strlen("abcdef"); printf("%d\n", len); return 0; }
思路:看str指向的那个字符是什么,不是‘\0’,计数器count++,指针str是一个char*的指针,+1跳过一个char类型的变量,最后当遇到'\0',返回count作为返回值。
2.指针+-整数🌾
#define N_VALUES 5
float values [ N_VALUES ];
float * vp ;
// 指针 +- 整数;指针的关系运算
for ( vp = & values [ 0 ]; vp < & values [ N_VALUES ];)
{
* vp ++ = 0 ;
}
3.指针-指针🌏
指针- 指针 == 地址 - 地址
前提:
- 两个指针指向同一块空间,指针的类型是一致的
- 指针 - 指针得到的是指针和指针之间的元素个数(这是语法规定的)
由前面我们可知指针+-整数是等于指针的,那如果指针 - 指针不就是整数了吗,分两种情况
方法1:大地址-小地址或者小地址-大地址⛅
1.大地址-小地址:随着数组下标的增长,地址是由低到高变化的
int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; int n = &arr[9] - &arr[0]; printf("%d\n", n); return 0; }
执行:
- 为什么是9?答:语法规定。(但是还是不明白为什么是9)⛄
个人思路:把内存监视调出来:可以观察一下它们的地址
🍄实践证明:
用它们的地址相减:减出一个24,这个24是一个16进制数,可以代表它们之间相差的内存空间, 将16进制24转换为10进制后,是36byte也就是相差9个(整型)元素的地址空间
2.小地址 - 大地址(特殊情况)
int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; int n = &arr[0] - &arr[9]; printf("%d\n", n); return 0; }
方法2:模拟实现指针相减🌱
int my_strlen(char* str) { char* start = str; while (*str!='\0') { str++; } return str - start; } int main() { int len = my_strlen("abcdef"); printf("%d\n", len); return 0; }
执行:
图解:
4.指针的关系运算
for(vp = &values[N_VALUES]; vp > &values[0];)
{
*--vp = 0;
}
经过修改之后的代码
for ( vp = & values [ N_VALUES - 1 ]; vp >= & values [ 0 ]; vp -- )
{
* vp = 0 ;
}
关于这两种写法的理解:
关于野指针的知识:vp1:起始位置这不是越界了吗?没有。
🌵理解:
这个位置后面的空间虽然不属于values数组,但指向这个位置是没有形成越界访问的这种效果,仅仅指向是没有问题的!!!只有当对vp1解引用了或者说访问数组values[5]的元素了,通过vp1改数组values后面空间的数据了,那确实是非法访问了🌳
关于vp1和vp2指针问题:
实际在绝大部分的编译器上是可以顺利完成任务的,然而我们还是应该避免这样写,因为标准并不保证它可行。
🌐 标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与
指向第一个元素之前的那个内存位置的指针进行比较。







