指针概念
在计算机科学中,指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向(points to)存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”。意思是通过它能找到以它为地址的内存单元。
指针和指针类型
指针简单举例
#include<stdio.h>
int main(){
int a=10;//在内存中开辟一块空间
int * pa=&a; //pa就是存放地址的指针,而pa就是指针变量。
return 0;
}
总结:指针就是变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)。
指针类型的意义
#include<stdio.h>
int main() {
int a = 0x11223344;
int *pa = &a;
*pa = 0;
return 0;
}
快捷键:Fn+F10或者F10,一步步看调试代码是地址中内容的变化:
继续按F10向下调试:当调试*pa=0;后可以发现地址的内容变化:
而将int*pa=&a ;换成char *pc=&a ;时,会不会发生变化,下面我们就验证一下吧!
#include<stdio.h>
int main() {
int a = 0x11223344;
char *pc = &a;
*pc = 0;
return 0;
}
继续调试,看内存的变化:可以看出在第四行时a地址中的内容依然是十六进制的0x11223344;
继续往下调试 * pc=0 ;后观察a地址中的内容变化:可以看出char *类型只改变一个字节的内容。
总结:指针类型决定了指针解引用操作的时候,一次访问几个字节(访问内存的大小)。
例如:int * 解引用操作时访问4个字节;char * 解引用操作访问1个字节。
下面继续探索指针类型的意义:
#include<stdio.h>
int main() {
int a = 0x11223344;
int *pa = &a;
char *pc = &a;
printf("%p\n", pa);
printf("%p\n", pa + 1);
printf("\n");
printf("%p\n", pc);
printf("%p\n", pc + 1);
return 0;
}
运行结果如图所示:
可以看出,指针类型+1步或者-1步时的步长。
由运行图可以看出:
int *类型到下一步步长为4个字节,char *到下一步的步长为1个字节。
野指针
野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
野指针的原因
指针未初始化
#include <stdio.h>
int main()
{
int *p;//局部变量指针未初始化,默认为随机值
*p=20;
return 0;
}
指针越界访问
#include <stdio.h>
int main()
{
int arr[10] = {0};
int *p = arr;
int i = 0;
for(i=0; i<=10; i++)
{
//当指针指向的范围超出数组arr的范围时,p就是野指针
*(p++) = i;
}
return 0;
}
指针指向的空间释放
int * test(){
int a=10;
return &a;
}
#include<stdio.h>
int main(){
int *p=test();
printf("%d\n",*p);
return 0;
}
如何规避野指针
各种例子说明:
#include <stdio.h>
int main()
{
int *p = NULL;
//指针指向NULL初始化
int a = 10;
p = &a;
if(p != NULL)
{
*p = 20;
}
return 0;
}
- 进行指针的初识化
- 指针使用之前检查有效性
- 避免数组越界
- 指针指向空间释放即使置NULL
指针的运算
指针减指针的运算
举一个简单的例子看一下指针-指针的运算:
int main() {
int a[10] = { 1,2,3,4,5,6,7,8,9,0 };
printf("%d\n", &a[9] - &a[0]);
printf("%d", &a[0] - &a[9]);
return 0;
}
运行上面的代码;运行结果如图:
而&a[9]和&a[0]之间的指针内存空间画图所示
可以得出:指针-指针的结果的绝对值是指针和指针之间的元素个数。
**注意:**指针-指针的用法的前提是两个指针指向同一片区域。
- 指针-指针实际运用
一般我们模拟实现strlen()函数的用法:
#include<stdio.h>
int myStrlen(char *s) {
int count = 0;
while (*s != '\0') {
count++;
s++;
}
return count;
}
int main() {
char ch[] = "abcdefgh";
int len = myStrlen(ch);
printf("%d", len);
return 0;
}
而利用指针-指针的方法可以是:
#include<stdio.h>
int myStrlen(char *s) {
//int count = 0;
int *start=s;
while (*s != '\0') {
//count++;
s++;
}
return s-start;
}
int main() {
char ch[] = "abcdefgh";
int len = myStrlen(ch);
printf("%d", len);
return 0;
}
指针与数组
首先我们举一个简单的例子:
#include<stdio.h>
int main() {
int a[10] = { 1,2,3,4,5,6,7,8,9,0 };
printf("%p\n", a);
printf("%p\n", &a[0]);
return 0;
}
运行结果可以看的出**a,&a[0]**都是得到的同一个内存空间地址。
结论:数组名表示的是数组首元素的地址。
但是有2个例外:
- sizeof(数组名)–这里的数组名不是首元素的地址,是表示整个数组的,这里计算的是整个数组的大小,单位还是字节
- &数组名–这里的数组名不是首元素的地址,是表示整个数组的,拿到的是这个数组的地址
那我们就要验证一下吧:
#include<stdio.h>
int main() {
int a[10] = { 0 };
printf("%p\n", a);//数组名是首元素的地址
printf("%p\n", a+1);
printf("\n");
printf("%p\n", &a[0]);//第一个元素的地址
printf("%p\n", &a[0]+1);
printf("\n");
printf("%p\n", &a);//整个数组的地址
printf("%p\n", &a+1);
return 0;
}
运行结果如图:
结果显而易见,&a是取的整个数组的地址,其余都是取的数组元素的第一个元素的地址。
觉得内容还不错的小伙伴们,麻烦留下自己的足迹哦!!!