1、认识指针#include <stdio.h>
//基本数据类型作为函数參数传递是值传递
//void moveFront(int x ,int y)
//{
//    x  = x + 2;
//}
void test()
{//  确定当前坐标int x = 20;int y = 150;printf("%p\n",&x);printf("%lu\n",&x);*((int *)(0x7fff5fbff76c)) = 22;printf("(%d,%d)\n",x,y);//    moveFront(x, y);//    printf("(%d,%d)\n",x,y);}//假设你想訪问指针所指向存储空间,就必须使用訪问指针所指向的存储空间的操作符
void moveFront(int *x ,int *y)
{
//  x  = x + 2;//此时是改变指针的指向,而不是訪问指针所指向的存储空间*x  = *x + 2;
}int main(int argc, const char * argv[]) {//  确定当前坐标int x = 20;int y = 150;printf("(%d,%d)\n",x,y);moveFront(&x, &y);printf("(%d,%d)\n",x,y);return 0;
}
2、指针的定义与初始化(重点掌握)
    内存中最小的存储单元:字节。每个字节在内存中都有一个编号,这编号就是指针
  
   指针:内存地址
   有了指针你就有了打开这块内存钥匙,就能够操作这一块内存
  
   指针变量:存放内存地址的变量
   定义指针:指针所指向数据类型  * 指针变量名称;
  在的定义变量时候,*是一个类型说明符,说明定义这个变量是一个指针变量
   在不是定义的变量的时候。*是一个操作符。訪问(读、写)指针所指向的那块存储空
     指针的初始化:
   
     注意点:
     1、仅仅有定义没有初始化指针里面是一个垃圾值。这时候我们成为这个指针为野指针
     2、假设操作一个野指针
        2.1 程序崩溃
        2.2 訪问不该你訪问存储。操作潜在逻辑错误
     3、不能够使用整形常量赋值一个指针变量
        由于内存是操作系统分配我们的,不是我们随便取的
     4、什么类型的指针。仅仅指向什么类型的变量
     5、多个指针能够指向同一变量
     6、指针的指向是能够改变的
#include <stdio.h>//指针的定义
void test()
{int num = 10;//  定义一个指针变量int *p;p = #*p = 20;printf("num = %d\n",num);
}int main(int argc, const char * argv[]) {// 先定义在进行初始化int num = 10;
//  定义一个指针变量pint * p;//    *p = # // p 还有进行初始。不可以訪问它所指向存储空间p = #//p 指向 num*p = 20;//  定义指针变量的同一时候进行初始int num2 = 20;int *p2 = &num2;*p2 = 40;printf("%d,%d\n",num2,*p2);// 不可以使用整形常量赋值一个指针变量
// 由于内存是操作系统分配我们的,不是我们随便取的//    int *p3 = 100000;//此处是错误的
//    
//    *p3 = 10;p2 = #printf("%p\n",p2);char c = 'a';int *pc = &c;*pc = 10;printf("%p\n",p2);return 0;
}3、多级指针
 通过指针訪问变量称为间接訪问。
因为指针变量直接指向变量,所以称为“一级指针”。而
 假设通过指向指针的指针变量来訪问变量则构成“二级指针”。
#include <stdio.h>void test()
{int num = 10;int *p = #//  定义一个指针来指向变量p//  pp就是一个二级指针int **pp = &p;**pp = 30;printf("%d\n",num);int ***ppp = &pp;***ppp = 50;printf("%d\n",num);//  四级指针int ****pppp = &ppp;****pppp = 100;printf("%d\n",num);   
}
void readFile(char **error)
{*error = "读取错误";   
}int main(int argc, const char * argv[]) {//    char error[100];char *error;readFile(&error);printf("%s",error);return 0;
}4、指针为什么要区分类型
1、变量的地址是变量所在占存储空间的首地址
2、指针变量只能够存储一个地址编号,假设没有类型。当通过指针就不知道要訪问多少个字节的存储空间
3、指针区分类型是为了在通过指针訪问它所指向的存储空间的时候,可以正确訪问
4、假设通过一个char类型的指针操作一个int的变量。假设值的二进制数据超过1字节,那么就造成数据错误
5、假设通过一个int 类型的指针操作一个char变量,那么你就会改动了你不该改动的内存,造成程序逻辑错误
#include <stdio.h>
/*全部指针类型都是占用八个字节的存储空间*/
void testEveryPointerIs8B()
{printf("%lu\n",sizeof(int *));printf("%lu\n",sizeof(char *));printf("%lu\n",sizeof(double *));printf("%lu\n",sizeof(float *));printf("%lu\n",sizeof(float **));
}int main(int argc, const char * argv[]) {int num = 10;char *cp = #printf("%d\n",num);return 0;
}
5、指针运算概述
指针变量:存放是内存字节的地址编号(无符号的整形数)
指针:是运算受限的无符号的整形数
运算运算:
指针 + 整形数 === 指针变量中值 + sizeof(其所指向数据类型)
指针 - 整数数 === 指针变量中值 - sizeof(其所指向数据类型)
pointer1 - pointer2 = (pointer1中值 - pointer2中值) / sizeof(其指向数据类型)
赋值运算:
=
+= 必须是一个整形数
-= 必须是一个整形数
比較运算
==
!=
>
<
>=
<=
自增自减
p++; p = p + 1;
++p; p = p + 1;
--p;
p--;
#include <stdio.h>//算术运算
void test()
{int a = 10;int *p = &a;//  指针+1p = p + 1;int nums[5] = {1,2,3,4,5};int * pointer1 = nums;int * pointer2 = &nums[4];size_t size  = pointer2 - pointer1;    printf("%lu\n",size);        //  pointer1 + pointer2;//    pointer2 * pointer1;//    pointer1 / pointer2;//    pointer1 / 2;
}
//赋值运算
void test1()
{int a = 10;//    int *p = &a;int nums[] = {1,2,3,4,5};int *p = nums;int *p2 = nums;p += 2;p = p + 2;p -= 1;printf("%d\n",*p);   
}//关系运算
int main(int argc, const char * argv[]) {int nums[] = {1,2,3,4,5};int *p = nums;p++;int result =  nums == p;result = p > nums;p--;result = p < nums;   result = p >= nums;result = p <= nums;   printf("%d\n",result);   return 0;
}数组像一个指针:訪问数组中元素,使用数组与使用指向这个数组的指针是等价
nums[1] ==== p[1]
nums+1 ==== p + 1;
nums[1] 的本质 *(nums + 1)
指针 + 整数 ===== 指针中的值 + sizeof(所指向的数据类型) * 整数
// int nums[] = {1,2,3,4,5};
//
// int *p = nums;
double nums[] = {1.0,2.0,3,4,5};
double * p = nums;
// printf("%d,%d,%d,%d,%d,%d\n",nums[1],p[1],*(nums + 1),*(p + 1),*(++p),。
);
 printf("%p\n",nums);
 printf("%p\n",nums+2);
 printf("%p\n",p);
 printf("%p\n",p+2);
   数组不是一个指针
    1、sizeof(array) != sizeof(pointer):当一个数组赋值一个指针变量的时候,那么数组中有些信息就丢失了,比方数组长度,这样的现象指针信息遗失
    2、指针的指向是能够改变的,数组的指向是不能够改变
    3、array == &array 数组名就是数组地址,pointer != &pointer : 指针所指向地址不是指针本身地址
#include <stdio.h>
int main(int argc, const char * argv[]) {int nums[] = {1,2,3,4,5};int *p = nums;p = nums;
//    nums = nums + 1;    printf("%lu,%lu\n",sizeof(nums),sizeof(p));       printf("%p\n",nums);printf("%p\n",&nums);      printf("%p\n",p);printf("%p\n",&p);        return 0;
}7、指针与二维数组
指针数组与二维数组指针变量的差别
应该注意指针数组和二维数组指针变量的差别。这两者尽管都可用来表示二维数组,可是其表示方法和意义是
不同的。
二维数组指针变量是单个的变量,其一般形式中"(*指针变量名)"两边的括号不可少。而指针数组类型表示的
是多个指针(一组有序指针)在一般形式中"*指针数组名"两边不能有括号。
比如:
 int (*p)[3];
 表示一个指向二维数组的指针变量。该二维数组的列数为3或分解为一维数组的长度为3。
 int *p[3]
 表示p是一个指针数组,有三个下标变量p[0]。p[1],p[2]均为指针变量。 
#include <stdio.h>void test()
{int nums[3][2] = {{1,2},{3,4},{5,6}};   int *p = nums[0];    printf("%p\n",p);printf("%p\n",nums);    for (int i = 1; i < 6; i++) {printf("%d ",*(p + i));}}
/*定义指针数组的格式:数据类型 * 指针变量名称[指针个数]*/
void test2()
{int nums[3][2] = {{1,2},{3,4},{5,6}};//    int * p[2] = {nums[0],nums[1]};//        p = nums;////    printf("%d\n",p[0][1]);int a = 10;int b = 20;int c = 30;int *p = &a;//    *p === p[1]; 没有这么写的int *ps[3] = {&a,&b,&c};printf("%d,%d,%d",*ps[0],*ps[1],*ps[2]);}
/*定义一个指向一维数组的指针数据类型 (*指针名称)[所指向的一维数组的元素个数]指针 + 整数 === 指针中的值 + 所指向数据类型的长度 * 整数*/int main(int argc, const char * argv[]) {int nums[3][2] = {{1,2},{3,4},{5,6}};int (*ps)[2];ps = nums;//能够觉得ps 与 nums是等价的 int num = ps[0][1];printf("%d\n",num);   printf("%p\n",nums);printf("%p\n",nums+1);    printf("%p\n",ps);printf("%p\n",ps+1);    for (int i =0 ; i < 3; i++) {for (int j = 0; j < 2 ; j++) {printf("%d ",ps[i][j]);}printf("\n");}//    nums   nums[0]//    同样点:相应地址都是一样的
//    不同点:指针类型是不同
//    nums + 1 = nums + sizeof(nums[0])
//    nums[0] + 1 = nums + sizeof(int)//   sizeof(nums) 二维数组所用占用存储空间字节数
//   sizeof(nums) / sizeof(int) 二维数组中一共同拥有多少个int的数据int *p = nums[0];for (int i = 0; i < sizeof(nums) / sizeof(int); i++) {printf("%d ",p[i]);}return 0;
}