1.指针是什么

2.指针和指针类型

3.野指针

4.指针运算

5.指针和数组

6.二级指针

7.指针数组

1.指针是什么

在计算机中,指针是编程语言中的一个对象,利用地址,他的值直接指向存在电脑储存器中的另外一个地方的值。由于通过地址找到所需的变量单元,可以说,地址指向该变量单元,因此,将地址形象化的称为‘指针’。意思是能通过他找到以他为地址的内存单元

指针就是个变量,存放内存单元的地址(编号

一个指针单元的内存大小是一个字节


int main()
{
    int a = 10;
    int* p = &a;//int* p就是一个指针变量,用来存放地址,也就是a的地址,也可以说&a也是个指针
}

总结:指针就是变量,用来存放地址(存放在指针中的值都被当成地址处理)

在32位的机器上,地址是32个0或1组成二进制序列,那地址就得用4个字节的空间来存储,所以一个指针变量的大小就应该是4个字节。

在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地址

2.指针和指针类型

int main()
{
    printf("%d\n, sizeof(*int));
    printf("%d\n, sizeof(*char));
    printf("%d\n, sizeof(*short)); 
    printf("%d\n, sizeof(*double));
       return 0;
}//从这里得出,指针的大小都是四个字节

指针类型都是四个字节

那指针类型有何意义?

指针类型的意义,指针类型决定了指针进行解引用操作的时候,能够访问空间的大小

当是int* p的时候,*p能够访问4个字节的大小

是char8* p的时候 ,*p只能够访问1个字节的大小

doule* p 的时候,*p能够访问8个字节的大小

指针+-整数

#define _

#include<stdio.h>

int main()
{    
     int a = 0x11223344;
     int* pa = &a;
     char* pc = &a;
    printf("%p\n", pa);
    printf("%p\n", pa+1);
    printf("%p\n", pc);
    printf("%p\n", pc+1);
        return 0;
}

通过上面的打印我们发现,程序出来分别答案是

0095FB58(int*类型的指针本来是8)

0095FB5C(但是在+1之后变成了c,说明改变了)

0095FB58(char*类型本来是8)

0095FB59(但是在+1之后却才变9)

所以指针类型又决定了:指针走一步走多远

当是int* p的时候:p+1是指针向后平移了四个字节

当是char* p的时候,p+1是指针向后平移了1个字节

当是double* p的时候p+1是指针向后平移了8个字节

总结:指针的类型决定了指针向前或者向后移动的步子距离,指针的类型决定了,对指针解引用的时候能有多大的权限(能操作几个字节)

3.野指针

野指针就是指针指向的位置是不可知的(随机的,不正确的,没有明确限制的)

野指针成因

1.1指针未初始化

int main()
{
       int a;//局部变量不初始化,默认值是随机值
       int *p;//局部的指针变量,不初始化,就被初始化随机值
       *p = 20;//
   //  如果我要解引用p,赋值给他20进去,但是由于他没有初始化,所以他没有指定指向的对象空间,是随机的放进去
  return 0;
}

1.2指针的越界访问

#define _

#include<stdio.h>

int main()
{
      int arr[10] = {0};
      int *P = arr;
      int i = 0;
      for(i=0; i<=11; i++);
       {
         //当指针指向的范围超出了数组的范围是,p就是野指针
            *(p++) = i; 
            //*p = i;与上面的方法等价
         //   *p++;
       }  //数组的范围只能存10个元素,而这里却+到了12个元素,所以就是野指针 ,非法越界访问
         return 0;
}

1.3指针指向的空间释放

int *test()
{
      int a = 10;//这是一个局部变量,当创建了一个a=10的时候他就自动销毁了
      return &a;//这时候我取出a的地址返回去给int *p,他接收了a的地址
} 
int main()
{
         int *p = test()//接收了a的地址,这时候已经存了a的地址
         *p = 20;//这时候解引用p通过p找到a的地址,然后把它的内容改成20,它指向了一块已经被空间释放的内存块,所以就是野指针
        return 0;//但是,像这样的操作就称为野指针,因为a =10已经销毁了,空间释放了,
}

如何避免野指针

1.指针初始化

2.小心指针越界

3.指针指向空间释放及时设置NULL(空指针),如果不知道初始化什么,就赋值空指针,和(int a = 0);一个道理

4.指针使用之前检查有效性

4.指针运算

指针+-整数

指针-指针

指针的关系运算

4.1指针运算

指针+一个整数,用指针的方法不用下标的方法访问元素

#define _

#include<stdio.h>

int main()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    int i =0;
    int sz = sizeof(arr)/sizeof(arr[0]);//计算元素个数
    int* p = arr;//放着数组第一个元素的地址
    for(i=0, i<=sz, i++)
    {
         printf("%d ", *p);//*p放着第一个元素的地址,打印第一个
         p = p + 1;//p+1向后跳一个整型,这时候就指向了2,下次循环的时候就是2+1了,以此类推
         //p++//也可以换成p++,一样的效果
    }//减法也是同样的道理
}

4.2指针-指针

#include<stdio.h>

int main()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    printf("%d ", &arr[9] - &arr[0]);//指针减去指针得到的是中间元素的个数,0和9之间的个数为9所以程序执行的结果也是9
    return 0;//如果想得到元素个数必须是大数减去小的数,不然像上面的我把9改成0,0改成9,那得到的答案是-9是个负数
}

指针-指针是得到中间元素的个数,大值减去小值得到的是他的元素个数,如果是小值减去大值,它的绝对值才是元素的个数,指针与指针相减,必须是同一类型的都是指向同一块空间的才能相减,不是指向同一块空间的不能向减,比如一个int类型的去减char类型的,这是错误的

4.3指针的关系运算

说白了就是比较大小

5指针和数组

数组是可以通过指针来进行访问的

通常说数组名是首元素地址,但是有下面这两个例外

5.1.&数组名,数组名不是首元素地址,数组名代表整个数组的地址,取出的是整个数组的地址

5.2.sizeof(数组名),数组名是代表计算整个数组的大小,单位是字节


初级指针_初始化

6.二级指针

int main()
{
  int a = 10;
  int * pa = &a;//int* 就是一级指针类型,pa就是一级指针,把a的地址放到pa里去
  int* * ppa = &pa;//int** 是二级指针类型 ppa就是二级指针,把pa的地址放到ppa里去
  return 0;
}

把二级指针ppa类型(int *  *)  分解来看,最右边这个'*',表达ppa是一个指针,     而(int *)表达ppa指向的那个对象'pa',是(int *)类型

如果想通过ppa的地址找出a的值并打印出来,可以这样写

int main()
{
   int a = 10;
   int * pa = &a;
   int* * ppa = &pa;
   printf("%d\n", **ppa);//*ppa可以找到pa的地址,然后pa里面存放着a的地址,
   //a就存放着a的值,所以我们可以通过两次解引用ppa来找到a的值,ppa->pa->a->10
   //**ppa = 20;// 如果想把a的值改掉,也可以通过这样的方法解引用两次
   return 0;
}

7.指针数组

指针数组---(本质这是个数组)

数组指针---(本质这是个指针)

7.1指针数组

存放指针的数组

int main()
{
   int a = 10;
   int b = 20;
   int c = 30;
      
   int* arr[3] = {&a,&b,&C};//指针数组
  // arr[0]//这就是第一个元素地址arr[1],这是第二个元素的地址arr[2],这是第三个元素的地址
}