C语言基础:008 C基础语法 - 指针

  1. 指针

    1. 指针 是用来 存放地址 的,地址是唯一标示 一块地址空间 的。
      指针的大小在 32 位平台是 4 个字节,在 64 位平台是 8 个字节。
      1. 指针 就是 地址 平时口语中说的指针,通常指的是 指针变量, 是用来 存放内存地址 的变量。
      2. 指针变量
        1. 我们可以通过 &取地址操作符)取出 变量 的内存 实际地址 ,把 地址 可以存放到一个变量中,这个 变量就是 指针变量。
        2. 指针变量 ,用来 存放地址 变量 。(存放在指针中的值都被当成地址处理)。
        3. code示例
          #include <stdio.h>
          int main()
          {
          	int a = 10;//在内存中开辟一块空间
          	int* p = &a;//对变量a,取出它的地址,可以使用&操作符。
          	//a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址存放在p变量中,p就是一个指针变量。
          	printf("%d %d %d %d %d \n", p, &p, *p, a, &a);// 869463732 869463768 10 10 869463732
          	return 0;
          }
    2. 32 位的机器上,地址是 32 0 或者 1 组成二进制序列,那地址就得用 4 个字节的空间来存储,所以 一个指针变量的大小就应该是 4 个字节。 那如果在 64 位机器上,如果有 64 个地址线,那一个指针变量的大小是 8 个字节,才能存放一个地 址。
  2. 指针类型

    1. 指针 +- 整数

      1. 指针的类型 决定了指针 向前或者向后 一步 多大 距离
      2. code示例
        #include <stdio.h>
        int main()
        {
        	char* pc_1 = NULL;  // char* 类型的指针是为了存放 char 类型变量的地址。
        	short* ps_1 = NULL; // short* 类型的指针是为了存放 short 类型变量的地址。
        	int* pi_1 = NULL;   // int* 类型的指针是为了存放 int 类型变量的地址。
        	long* pl = NULL;
        	float* pf = NULL;
        	double* pd = NULL;
        
        	int n = 1111111;
        	printf("%d\n", n);     // 1111111
        	char* pc = (char*)&n;
        	int* pi = &n;
        	printf("%d\n", n);     // 1111111
        	printf("%p\n", &n);    // 000000C7FA05FC74
        	printf("%p\n", pc);     // 000000C7FA05FC74
        	printf("%d\n", *pc);    // 71
        	printf("%p\n", pc + 1); // 000000C7FA05FC75
        	printf("%p\n", pi);      // 000000C7FA05FC74
        	printf("%d\n", *pi);     // 1111111
        	printf("%p\n", pi + 1); // 000000C7FA05FC78
        
        	return 0;
        }
    2. 指针的解引用

      1. 指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。
        比如: char * 的指针 解引用就只能访问一个字节,而 int * 的指针的 解引用就能访问 四个字节
      2. code示例
        #include <stdio.h>
        int main()
        {
        	int n = 11223344;
        	char* pc = (char*)&n;
        	int* pi = &n;
        	printf("%d\n", n);  // 11223344
        	printf("%p\n", &n); // 000000187D50F5B4
        	printf("%p\n", pc); // 000000187D50F5B4
        	printf("%d\n", *pc);// 48
        	printf("%p\n", pi); // 000000187D50F5B4
        	printf("%d\n", *pi);// 11223344
        	*pc = 0; //重点在调试的过程中观察内存的变化。
        	*pi = 0; //重点在调试的过程中观察内存的变化。
        	return 0;
        }
  3. 野指针

    1. 野指针概念

      1. 野指针就是 指针指向的位置 不可知 的(随机的、不正确的、没有明确限制的)
    2. 野指针成因

      1. 野指针形成的三个原因
        1. 指针未初始化
        2. 指针越界访问
        3. 指针指向的空间释放
      2. code示例
        #include <stdio.h>
        int main()
        {
        	int* p_0;// 1. 指针未初始化:局部变量指针未初始化,默认为随机值
        	*p_0 = 20;
        
        	int arr[10] = { 0 };
        	int* p = arr;
        	int i = 0;
        	for (i = 0; i <= 11; i++)
        	{
        		//2. 指针访问越界:当指针指向的范围超出数组arr的范围时,p就是野指针
        		*(p++) = i;
        	}
        
        	return 0;
        }
    3. 如何规避野指针

      1. 规避野指针的几种方式
        1. 指针初始化
        2. 小心指针越界
        3. 指针指向空间释放即使置NULL
        4. 避免返回局部变量的地址
        5. 指针使用之前
      2. code示例
        #include <stdio.h>
        int main()
        {
        	int* p = NULL; // 1. 指针初始化
        	int a = 10;
        	p = &a;
        	if (p != NULL) // 5. 指针使用之前检查有效性
        	{
        		*p = 20;
        	}
        	return 0;
        }
  4. 指针运算

    1. 指针有哪些运算

      1. 指针 +- 整数

      2. 指针 - 运算

      3. 指针的关系运算

    2. 实际在绝大部分的编译器上是可以顺利的完成指针关系运算,但应该避免这样写,因为标准规定中并不保证它可行。

    3. 标准规定:
      1. 允许 指向数组元素的指针 指向数组最后一个元素后面的那个内存位置的指针 比较,但是 不允许 指向第一个元素之前的那个内存位置的指针 进行比较。
    4. code示例
      #define N_VALUES 5
      #include <stdio.h>
      
      int main()
      {
      	char* s = "abc";
      	char* p = s;
      	while (*p != '\0')
      	{
      		p++; // 1. + 指针
      		printf("%d %p\n", *p, p);
      	}
      	/*
      	* 98 00007FF676509C21
      	* 99 00007FF676509C22
      	* 0 00007FF676509C23
      	*/
      	// 2. - 指针
      	printf("%p %p %d\n",p, s, p - s); // 00007FF676509C23 00007FF676509C20 3
      	
      	float values[N_VALUES];
      	float* vp;
      	for (vp = &values[N_VALUES - 1]; vp >= &values[0]; vp--) {
      		*vp = 0; // 3. 指针的关系运算
      		printf("%d %p\n", *vp, vp);
      	}
      	/*
      	* 0 000000CED870F738
      	* 0 000000CED870F734
      	* 0 000000CED870F730
      	* 0 000000CED870F72C
      	* 0 000000CED870F728
      	*/
      
      	return 0;
      }
  5. 指针和数组

    1. 数组名表示的是数组首元素的地址

      1. 数组名数组首元素地址是一样的
      2. 数组名 当成 地址 存放到一个 指针 中,不仅可以通过 数组下标来访问数组,也可以 使用指针来访问一个数组
    2. code示例
      #include <stdio.h>
      int main()
      {
      	int arr[5] = { 1,2,3 };
      	printf("arr = %p\n", arr);         // arr = 000000810BD4FB98
      	printf("&arr[0] = %p\n", &arr[0]); // &arr[0] = 000000810BD4FB98
      
      	int* p = arr; // 指针 p 存放的是数组首元素的地址
      	printf("p = %p\n", p);  // p = 000000810BD4FB98
      
      	int sz = sizeof(arr) / sizeof(arr[0]); // 5
      	for (int i = 0; i < sz; i++)
      	{
      		printf("&arr[%d] = %p   <====> p+%d = %p\n", i, &arr[i], i, p + i);
      		printf("arr[%d] = %d   <====> *(p+%d) = %d\n", i, arr[i], i, *(p + i)); // 通过指针来访问数组
      	}
      	/*
      	* &arr[0] = 000000810BD4FB98 ? <====> p+0 = 000000810BD4FB98
      	* arr[0] = 1 ? <====> *(p+0) = 1
      	* &arr[1] = 000000810BD4FB9C ? <====> p+1 = 000000810BD4FB9C
      	* arr[1] = 2 ? <====> *(p+1) = 2
      	* &arr[2] = 000000810BD4FBA0 ? <====> p+2 = 000000810BD4FBA0
      	* arr[2] = 3 ? <====> *(p+2) = 3
      	* &arr[3] = 000000810BD4FBA4 ? <====> p+3 = 000000810BD4FBA4
      	* arr[3] = 0 ? <====> *(p+3) = 0
      	* &arr[4] = 000000810BD4FBA8 ? <====> p+4 = 000000810BD4FBA8
      	* arr[4] = 0 ? <====> *(p+4) = 0
      	*/
      
      	return 0;
      }
  6. 二级指针

    1. 指针变量 也是变量,是变量就有地址,那 指针变量的地址 存放在哪里?这就是 二级指针

       

    2. 二级指针的运算
      1. *ppa 通过对 ppa 中的地址进行 解引用 ,这样找到的是 pa *pa 访问的就是 pa
      2. **ppa 先通过 *ppa 找到 pa , 然后对 pa 进行 解引用 操作,那找到的是 a
      3. code示例
        #include <stdio.h>
        int main()
        {
        	int a = 111;
        	int* pa = &a;
        	int** ppa = &pa; // 二级指针
        	// a的地址 = 000000E01CBCF8B4, pa中存放的内容 = 000000E01CBCF8B4
        	printf("a的地址 = %p, pa中存放的内容 = %p\n", &a, pa);
        	// pa的地址 = 000000E01CBCF8D8, ppa中存放的内容 = 000000E01CBCF8D8, ppa的地址 = 0000002BF390F668
        	printf("pa的地址 = %p, ppa中存放的内容 = %p, ppa的地址 =  %p\n", &pa, ppa, &ppa);
        	int b = 20; 
        	*ppa = &b;//等价于 pa = &b;
        	printf("%p\n", &b);          // 0000002BF390F684
        	printf("%p %p\n", *ppa, pa); // 0000002BF390F684 0000002BF390F684
        
        	**ppa = 30;
        	//等价于*pa = 30;
        	//等价于a = 30;
        
        	return 0;
        }
  7. 指针数组

    1. 指针数组是数组。是存放指针的数组。
    2. code示例
      #include <stdio.h>
      int main()
      {
      	int arr1[5];
      	char arr2[6];
      	int* arr3[5];//arr3是一个数组,有五个元素,每个元素是一个整形指针。
      
      	return 0;
      }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值