IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 如何深入掌握C语言指针(详解) -> 正文阅读

[C++知识库]如何深入掌握C语言指针(详解)

目录

前言

指针是什么

概念

单元大小与编址

指针和指针类型

指针类型

指针+-整数

指针的解引用

野指针

指针未初始化

指针越界访问

指针指向的空间释放

如何规避野指针

指针运算

指针+-整数

指针-指针

指针的关系运算

对于指针比较

指针和数组

二级指针

使用及运算

指针数组


前言

本文主要讲解点

  1. 指针是什么
  2. 指针和指针类型
  3. 野指针
  4. 指针运算
  5. 指针和数组
  6. 二级指针
  7. 指针数组

指针是什么

概念

  • 专业地说:

指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向 (points to)存在电脑存储器中另一个地方的值

由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元

因此,将地址形象化的称为“指针”。意思是通过它能找到以它为地址 的内存单元

  • 简单地说:

变量在内存中储存时,内存空间是一块一块的,每一块都有独定的编号(就像是门牌号)

而指针是个变量,存放内存单元(指向的对象)的地址(编号/门牌号)

#include <stdio.h>
int main()
{
 int a = 10;  //在内存中开辟一块空间
 int *p = &a;//这里我们对变量a,取出它的地址,可以使用&操作符。
            //将a的地址存放在p变量中,p就是一个之指针变量。
           //int*说明p是一个指针,而p是指针变量,一个指向int型数据的指针
 return 0;
}
  • 总结:

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

单元大小与编址

结论:一个字节给一个对应的地址(计算和权衡后最适合的大小)

  • 以32位的电脑为例:

每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0)

  • 其所产生的地址:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
...
11111111 11111111 11111111 11111111   //共有2的32次方个地址

每个地址标识一个字节

则2^32Byte == 2^32/1024KB == 2^32/1024/1024MB==2^32/1024/1024/1024GB == 4GB

那么能够4G的空间进行编址;对于64位也是同理

  • 从上述可知:

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

在64位中,64个地址线,则一个指针变量的大小是8个字节(以存放一个地址)

  • 总结:

指针是用来存放地址的,地址是唯一标示一块地址空间的

指针的大小在32位平台是4个字节,在64位平台是8个字节

指针和指针类型

指针的定义方式是: type + *?

指针类型

char  *pc = NULL; //存放char型变量的地址
int   *pi = NULL; //存放int型变量的地址
short *ps = NULL; //....
long  *pl = NULL; //..
float *pf = NULL; //.
double *pd = NULL;

指针+-整数

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

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

指针的解引用

int main()
{
 int n = 0x11223344;
 char *pc = (char *)&n;
 int *pi = &n;
 *pc = 0;   //重点在调试的过程中观察内存的变化。
 *pi = 0;   //重点在调试的过程中观察内存的变化。
 return 0;
}

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

如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节

野指针

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

指针未初始化

int main()
{
 int *p;//局部变量指针未初始化,默认为随机值
    *p = 20;
 return 0;
}

指针越界访问

int main()
{
    int arr[10] = {0};
    int *p = arr;
    int i = 0;
    for(i=0; i<=11; i++)
   {
        //当指针指向的范围超出数组arr的范围时,p就是野指针
        *(p++) = i;//先使用指针p,使用时进行解引用,对内容进行赋值,再进行++
   }
    return 0;
}

指针指向的空间释放

int* test()
{
    int n=10;
    int *p=&n;//进入test函数开辟空间
    return p;//离开时空间释放,n的空间没有了
}

int main()
{
    int *i=p;//即便有地址也找不到对象,便成了野指针
    printf("%d",*i);//err
    return 0;
}

如何规避野指针

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

指针运算

指针+-整数

上文已经提及,不再赘述

指针-指针

两个指针指向同一个数组中的(可能不同)元素,它们的差就是两个元素之间的元素个数+1

int a[5];
int* p;
int* q;
p = &a[1]; // 第二个元素
q = &a[3]; // 第四个元素

这里 q - p 等于 2 (从 p 指向的元素往后数两个,就是 q 指向的元素)

如果两个指针不是指向同一个数组中的元素,结果是未定义的(the?behavior?is?undefined)

指针的关系运算

  1. px > py 表示 px 指向的存储地址是否大于 py 指向的地址
  2. px == py 表示 px 和 py 是否指向同一个存储单元
  3. px == 0 和 px != 0 表示 px 是否为空指针

对于指针比较

for(vp = &values[N_VALUES]; vp > &values[0];)//用指针从后初始化数组
{
    *--vp = 0;
}
//优化
for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
{
    *vp = 0;
}

  • 标准规定:

允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较

但是不允许 与指向第一个元素之前的那个内存位置的指针进行比较

指针和数组

之前我们可以通过下标访问数组元素

学习了指针之后,我们可以通过指针访问数组的元素

在数组中,数组名即为该数组的首地址,结合上面指针和整数的加减,可以实现指针访问数组元素

int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr;//p存放的是数组首元素的地址

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

int main()
{
 int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
 int *p = arr; //指针存放数组首元素的地址
 int sz = sizeof(arr) / sizeof(arr[0]);
 int i = 0;
 for (i = 0; i<sz; i++)
 {
 printf("%d ", *(p + i));
 }
 return 0;
}

二级指针

指针变量也是变量,是变量就有地址

而指针变量的地址存放在二级指针里(指向指针的指针)

?

int a =100;
int *p1 = &a;
int **p2 = &p1;

?C语言不限制指针的级数,每增加一级指针,在定义指针变量时就得增加一个星号*

使用及运算

  • *ppa 通过对ppa中的地址进行解引用,这样找到的是 pa , *ppa 其实访问的就是 pa
int b = 20;
*ppa = &b;//等价于 pa = &b;
  • **ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a
**ppa = 30;
//等价于*pa = 30;
//等价于a = 30;

指针数组

指针数组是存放指针的数组

int arr1[5];
char arr2[6];
int* arr3[5];

?

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-09 10:03:37  更:2021-08-09 10:03:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/9 17:44:52-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码