目录
- 指针运算(补)
- 指针+指针
- 指针的关系运算(补)
- 指针与数组
- 数组名
- 二级指针
- 指针数组
指针运算(补)
指针+指针
上一篇博客我们介绍了指针运算中的三种常见运算:指针±整数,指针关系运算,指针-指针。,但类比常数的关系运算,我们好像还少了一个指针+指针的运算,那么在C语言中的指针+指针到底有没有意义呢,实际上这种运算是没有什么意义的。
举个例子,如图1:
日期加天数能等到另一个日期,类比指针加整数得到一个新指针。
日期减日期能得到天数,类比数组指针两两相减得到其中的元素个数。
而日期加日期貌似就没有什么意义了,类比指针加指针也是如此。
指针的关系运算(补)
我们来分析下面这两段代码
代码1
#define N_VALUES 5
int main()
{int values[N_VALUES] = { 0,1,2,3,4 };int* vp = 0;for (vp = &values[N_VALUES]; vp > &values[0];){*--vp = 0;printf("%d", *vp);}
}
代码2
#define N_VALUES 5
int main()
{int values[N_VALUES] = { 0,1,2,3,4 };int* vp = 0;for (vp = &values[N_VALUES]; vp > &values[0];vp--){*vp = 0;printf("%d", *vp);}
}
代码1分析如图2
虽然一开始vp被赋予的地址是超出限制范围的,但是在for循环中首先经历了一次自减,访问下标就来到了4的位置,这时候就不会越界访问了,(越界访问只存在于解引用期间,只要还没有解引用,就没有越界访问)
代码2分析如图3
和代码2相反的是,一开始并没有越界,而在最后再进行了一次自减后越界了,不过同样没有解引用就跳出循环了,乍一看二者其实并没有什么太大区别,但C语言规定:允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与
指向第一个元素之前的那个内存位置的指针进行比较。
指针与数组
数组名
什么是数组名呢?我们来看一段代码:
int main()
{int arr[10] = { 0 };printf("%p\n", arr);printf("%p\n", &arr[0]);return 0;
}
运行结果如图3
从代码和运行结果我们可以得出结论:数组名是数组首元素的地址。
既然可以把数组名当成地址存放到一个指针中,我们使用指针来访问一个就成为可能。看下面这段代码
int main()
{int arr[] = {1,2,3,4,5,6,7,8,9,0};int *p = arr; //指针存放数组首元素的地址int sz = sizeof(arr)/sizeof(arr[0]);for(i=0; i<sz; i++){printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p+i);}return 0;
}
运行结果如图4
由图我们可以得出:p+i其实就是访问下标为i的元素的地址。
那么我们利用这个特点就可以直接通过指针来访问数组。
看下面这段代码
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++){printf("%d ", *(p + i));}return 0;
}
代码运行结果如图5
二级指针
看到这个名词可能会联想到数学中学过的二阶求导,我们把取地址和求导类比一下,指针变量也是变量,是变量就会有地址来存放这个变量,就如同一阶导数本质上还是一个函数,其同样存在导数而且二级指针的写法和二阶导数写法如出一辙,如图6
这样类比理解起来就要容易多了。
指针数组
指针数组和数组指针要区分开来,数组指针是指存放数组的地址,而指针数组是指存放指针的数组。
而指针同样也分整形指针数组(即这个数组内都存放的是整形元素的地址),字符指针数组(即这个数组内都存放的是字符元素的地址),类比如图7
以上就是本篇文章全部内容,如有出入,欢迎各位大佬指正