当前位置: 首页 > news >正文

对于指针的基本了解

低阶指针

文章目录

  • 低阶指针
    • 1.理解指针
    • 2.指针与指针类型
    • 3.野指针
    • 4.指针运算
    • 5.指针与数组
    • 6.二级指针
    • 7.指针数组


1.理解指针

指针的理解:指针就是地址,平时说的指针是指针变量,是用来存放内存地址的变量

指针在内存中的存储:

请添加图片描述

我们可以通过==&==(取地址操作符)取出变量的内存起始地址,把地址可以存放到一个变量中,这个变量就是指针变量,比如上图的p

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
 	int a = 10;//在内存中开辟一块空间
 	int *p = &a;//这里我们对变量a,取出它的地址,可以使用&操作符
    //a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址存放在p变量中,p就是一个指针变量
 	return 0;
}

请添加图片描述

调节内存监视窗口显示规格为4个位,则2个数表示一个字节,int是4个字节,则0a表示的是10,存储了a=10

指针的大小:

补充:

对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电 平(低电压)就是(1或者0);这里就有2的32次方个地址,每个地址标识一个字节,那我们就可以给 (2^32Byte == 2^32/1024KB == 2^32/1024/1024MB==2^32/1024/1024/1024GB == 4GB) ,则有4G的空闲进行编址

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

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

==结论:==指针的大小只与地址线个数有关


2.指针与指针类型

指针类型:

char  *pc = NULL;
short *ps = NULL;
int   *pi = NULL;

char* 类型的指针是为了存放 char 类型变量的地址
short* 类型的指针是为了存放 short 类型变量的地址
int* 类型的指针是为了存放 int 类型变量的地址

指针类型的含义:指针的类型决定了指针向前或者向后走一步有多大(距离)

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
	int n = 10;
	char* pc = (char*)&n;
	int* pi = &n;

	printf("&n=%p\n", &n);
	printf("pc=%p\n", pc);
	printf("pc+1=%p\n", pc + 1);//pc存储的char类型,pc+1,地址往后移动一个类型大小,大小为char的大小 1字节
	printf("pi=%p\n", pi);
	printf("pi+1=%p\n", pi + 1);//pi存储的int类型,pi+1,地址往后移动一个类型大小,大小为int的大小 4字节
	return  0;
}

请添加图片描述

指针的解引用:指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
	int n = 0x11223344;
	char* pc = (char*)&n;
	int* pi = &n;
    //pc和pi指向同一块空间&n
	*pc = 0;//pc是char类型,只能操作一个字节,即它赋值为0只是让第一个字节赋值为0,其他三个字节没有变,结果没让n为0   
	*pi = 0;//pi是int类型,可以操作四个字节,即四字节全赋值为0,结果让n为0   
	return 0;
}

请添加图片描述


3.野指针

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

野指针的形成原因:

①指针未初始化 ②指针越界访问 ③指针指向的空间释放

//①指针未初始化
#include <stdio.h>
int main()
{ 
 	int *p;//局部变量指针未初始化,默认为随机值
    	*p = 20;
 	return 0;
}

//②指针越界访问
#include <stdio.h>
int main()
{
        int arr[10] = {0};
        int *p = arr;
        for(int i=0; i<=11; i++)
        {
            //当指针指向的范围超出数组arr的范围时,p就是野指针
            *(p++) = i;
        }
        return 0;
}

//③指针指向的空间释放
#include<stdio.h>
int main()
{
    int* a=(int)malloc(sizeof(int)*4);
    int *p=a;
    free(a);
    //如果后续再使用*p就会引发野指针问题,因为p所指向的内存空间已经被free清理了
    return 0;
}

避免野指针的方法:

  1. 指针初始化
  2. 小心指针越界
  3. 指针指向空间释放时就赋值为NULL
  4. 避免返回局部变量的地址
  5. 指针使用之前检查有效性

4.指针运算

指针运算的常见情况:①指针±整数 ②指针-指针

//①指针+-整数---分为两种情况:*(p+i)是由首元素地址往后移动i个元素地址;*p+i是*p的元素去加i
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	int arr[10] = { 0 };
	int* p = arr;
	int length = sizeof(arr) / sizeof(arr[0]);
	for (int i = 0; i < length; ++i)
		*(p + i) = i;
	for (int i = 0; i < length; ++i)
		printf("%d ", *(p + i));
	printf("\n");
	int a=*p + 1;
	printf("a=%d\n", a);
	a = *(p + 2) + 3;
	printf("a=%d\n", a);
	return 0;
}

请添加图片描述

//②指针-指针---前提条件:两个指针指向同一块空间才可以
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	int arr[10] = { 0 };
	printf("%d\n", &arr[0] - &arr[9]);
	printf("%d\n", &arr[9] - &arr[0]);
	return 0;
}

请添加图片描述

补充:允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较

5.指针与数组

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
 int arr[10] = {1,2,3,4,5,6,7,8,9,0};
    printf("%p\n", arr);
    printf("%p\n", &arr[0]);
    return 0;
}

请添加图片描述

可见数组名和数组首元素的地址是一样的

既然可以把数组名当成地址存放到一个指针中,我们使用指针来访问就成为可能

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
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;
}

请添加图片描述

结论: p+i 其实计算的是数组 arr 下标为i的地址


6.二级指针

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

请添加图片描述

//*ppa通过对ppa中地址进行解引用,这样就找到了pa,*ppa其实访问的就是pa
int a = 10;
int *pa=&a
int **ppa=&pa;
*ppa = &a;//等价于 pa = &a;

//**ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,找到的是a
**ppa=30;//*ppa等价于pa,**ppa等价于*pa,这里就等价于a=30;

7.指针数组

指针数组是指针还是数组?—存放指针的数组

int arr1[5];//arr1数组中存放5个int类型元素---整形数组
char arr2[6];//arr2数组存放6个char类型元素---字符数组
int* arr3[5];//arr3数组存放5个int*类型元素---指针数组

请添加图片描述


相关文章:

  • 基于BiGRU-Attention网络的 新型冠状病毒肺炎疫情预测学习记录
  • 生成对抗网络
  • C++【算法】【动态规划问题】
  • Flink中Table Api和SQL(二)
  • hook函数之useEffect的使用——自定义hook函数网络请求——
  • Windows 窗体显示的“模式方式”与“非模式方式”
  • JDBC详讲Connection与 jdbc-Statement
  • 外部 SRAM 实验
  • Redis从入门到精通(二)
  • 2021.09青少年软件编程(Python)等级考试试卷(四级)
  • JAVA计算机毕业设计毕业论文管理系统Mybatis+系统+数据库+调试部署
  • Redis实战 - 01 Redis 和 SpringSecurity Oauth2 实现认证授权中心
  • 数据结构:堆
  • 基于机器学习的搜索推荐系统
  • MATLAB | 分段赋色折线图及其图例绘制
  • JS 中的深拷贝与浅拷贝
  • classpath对获取配置文件的影响
  • express如何解决request entity too large问题
  • input的行数自动增减
  • Java,console输出实时的转向GUI textbox
  • Java比较器对数组,集合排序
  • leetcode388. Longest Absolute File Path
  • Python进阶细节
  • Theano - 导数
  • 规范化安全开发 KOA 手脚架
  • 基于阿里云移动推送的移动应用推送模式最佳实践
  • 山寨一个 Promise
  • 走向全栈之MongoDB的使用
  • 阿里云服务器购买完整流程
  • ​虚拟化系列介绍(十)
  • # 数论-逆元
  • #我与Java虚拟机的故事#连载08:书读百遍其义自见
  • $(document).ready(function(){}), $().ready(function(){})和$(function(){})三者区别
  • (7)STL算法之交换赋值
  • (Ruby)Ubuntu12.04安装Rails环境
  • (编译到47%失败)to be deleted
  • (附源码)springboot宠物管理系统 毕业设计 121654
  • (附源码)ssm旅游企业财务管理系统 毕业设计 102100
  • (十)DDRC架构组成、效率Efficiency及功能实现
  • (转) 深度模型优化性能 调参
  • (转)详解PHP处理密码的几种方式
  • **PyTorch月学习计划 - 第一周;第6-7天: 自动梯度(Autograd)**
  • .bat批处理(八):各种形式的变量%0、%i、%%i、var、%var%、!var!的含义和区别
  • .NET Reactor简单使用教程
  • .NET 使用配置文件
  • .Net(C#)常用转换byte转uint32、byte转float等
  • /usr/bin/env: node: No such file or directory
  • @selector(..)警告提示
  • [ MSF使用实例 ] 利用永恒之蓝(MS17-010)漏洞导致windows靶机蓝屏并获取靶机权限
  • [ vulhub漏洞复现篇 ] GhostScript 沙箱绕过(任意命令执行)漏洞CVE-2019-6116
  • [<死锁专题>]
  • [20180224]expdp query 写法问题.txt
  • [Apio2012]dispatching 左偏树
  • [C/C++]_[初级]_[关于编译时出现有符号-无符号不匹配的警告-sizeof使用注意事项]
  • [c]扫雷