c语言-指针

2023-05-16

目录

1、指针是什么?

2. 指针和指针类型

2.1 指针+-整数

2.2 指针的解引用

3. 野指针

3.1 野指针成因

3.2 如何规避野指针

4. 指针运算

4.1 指针+-整数

4.2 指针-指针

4.3 指针的关系运算

5. 指针和数组

 6. 二级指针

7. 指针数组

1、指针是什么?
指针是什么?

指针理解的2个要点:

1. 指针是内存中一个最小单元的编号,也就是地址,即我们常说的指针即地址
2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量,即指针即变量
总结:指针就是地址,口语中说的指针通常指的是指针变量。

那么我们就可以这样理解:

内存

指针变量

我们可以通过&(取地址操作符)取出变量的内存其实地址,把地址可以存放到一个变量中,这个 变量就是指针变量。

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

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

那这里的问题是:

一个小的单元到底是多大?(1个字节)
如何编址?
经过仔细的计算和权衡我们发现一个字节给一个对应的地址是比较合适的。

对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0);

那么32根地址线产生的地址就会是:

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位机器,如果给64根地址线,那能编址多大空间,自己计算,计算方法如上所示,此处不再计算。

这里我们就明白: 在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以 一个指针变量的大小就应该是4个字节。 那如果在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地 址。

总结: 指针是用来存放地址的,地址是唯一标示一块地址空间的。 指针的大小在32位平台是4个字节,在64位平台是8个字节。

2. 指针和指针类型
这里我们在讨论一下:指针的类型 我们都知道,变量有不同的类型,整形,浮点型等。

那指针有没有类型呢? 准确的说:有的。 当有这样的代码:

int num = 10;
p = &num;
要将&num(num的地址)保存到p中,我们知道p就是一个指针变量,那它的类型是怎样的呢? 我们给指针变量相应的类型。

char  *pc = NULL;
int   *pi = NULL;
short *ps = NULL;
long  *pl = NULL;
float *pf = NULL;
double *pd = NULL;
这里可以看到,指针的定义方式是: type + * 。

其实: char* 类型的指针是为了存放 char 类型变量的地址。

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

int* 类型的指针是为了存放 int 类型变量的地址。 那指针类型的意义是什么?下面我们会进行讲解!

2.1 指针+-整数
#include <stdio.h>
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;
}


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

2.2 指针的解引用
#include <stdio.h>
int main()
{
    int n = 0x11223344;
    char* pc = (char*)&n;
    int* pi = &n;
    *pc = 0;   //重点在调试的过程中观察内存的变化。
    *pi = 0;   //重点在调试的过程中观察内存的变化。
    return 0;
}
下图为执行完*pc = 0之后n的内存空间

由图可以看出,我们执行完该语句后,只改变了一个字节的空间所对应的值!

 下图为执行完*pi = 0之后的内存空间,与我们定义的指针类型一致,因为我们定义的pc是char类型的指针变量,char只占据四个字节的内存空间。

 由图可以看出,我们这次是改变了四个字节的空间所对应的值,与我们定义的指针类型所一致,因为pi是int 类型的指针变量,int在内存中占据四个字节的空间。

总结:

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

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

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

3.1 野指针成因
1. 指针未初始化

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

#include <stdio.h>
int main()
{
    int arr[10] = { 0 };
    int* p = arr;
    int i = 0;
    for (i = 0; i <= 11; i++)
    {
        //当指针指向的范围超出数组arr的范围时,p就是野指针
        *(p++) = i;
    }
    return 0;
}
3. 指针指向的空间释放(后续会讲,此处暂时不讲)

3.2 如何规避野指针
1. 指针初始化
2. 小心指针越界
3. 指针指向空间释放即使置NULL
4. 避免返回局部变量的地址
5. 指针使用之前检查有效性
#include <stdio.h>
int main()
{
    int* p = NULL;
    //....
    int a = 10;
    p = &a;
    if (p != NULL)
    {
        *p = 20;
    }
    return 0;
}
4. 指针运算
4.1 指针+-整数
#include<stdio.h>
int main()
{
    int x = 0;
    int* p = &x;
    printf("%p\n", p);
    printf("%p\n", p + 1);
    char* p2 = (char*)&x;
    printf("%p\n", p2);
    printf("%p\n", p2+1);
    return 0;
}


 指针+-整数实际上是跨越指针所指变量类型的字节数乘以我们加的数字,比如在上面的例子中,我们一开始是将整型指针p进行了+1操作,然后我们对p+1进行以地址形式打印后,相比原来的p,增加了4个字节,同理,后面的p2是char类型的指针,我们对其进行+1操作后,相比原来的p2的地址,增加了1个字节。

4.2 指针-指针
#include<stdio.h>
int main()
{
    int arr[5] = { 1,2,3,4,5 };
    int* p1 = &arr[4];
    int* p2 = &arr[0];
    printf("%d", p1 - p2);
    return 0;
}


上面进行相减后得出的结果是4,为什么会得出4这个结果呢?因为p1和p2之间相差4个整型元素,这个地方为什么我们要强调是整形元素呢?因为我们在运算符两侧的指针类型均是整型指针,实际上指针类型的变量进行相减是指针所代表的地址进行相减,将得出的值除以指针所指向的空间所占据的字节数,这样将大家不是很容易理解,有一点点抽象,我给大家简单举一下例子,比如在上面这个例子中p1中所存储的地址值是16,而p2中所存储的值是0,那么我们将p2减去p1后得出的16除以p1和p2所指向的数据类型即整型类型,每个整型元素所占据的字节数为4,所以16除以4之后的结果为4,即最终在屏幕上的输出结果为4,那么很多小伙伴就问了,在上面这个例子中,我们将两个指针的类型进行强制转换为char类型后得出的结果是不是就会改变为16了呢,因为根据上面的我给出的推理方式确实应该是这样的,因为char类型占据的字节数为1,16除以1之后的结果仍为16,接下来我们代码展示一下是不是就像我们的推理一样,得出的结果是16.

 

 同我们的推导一样,这就印证了我们的推导是正确的!

4.3 指针的关系运算
既然指针变量中所存储的是地址,地址从本质上来说也只是一串数据,那么也是可以进行比较大小的!此处不再进行举例给大家进行展示,因为不难理解,但是下面会给大家进行强调一个要点!

标准规定:

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

5. 指针和数组
我们看一个例子:

#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;
}
运行结果:

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

结论:数组名表示的是数组首元素的地址。(2种情况除外,数组章节讲解了)

那么这样写代码是可行的:

int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr;//p存放的是数组首元素的地址
既然可以把数组名当成地址存放到一个指针中,我们使用指针来访问一个就成为可能。

例如:

#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 (int 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的地址。

那我们就可以直接通过指针来访问数组。

如下:

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;
}


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

 

对于二级指针的运算有:

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

答案:是数组。是存放指针的数组。

数组我们已经知道整形数组,字符数组。

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


 那指针数组是怎样的?

int* arr3[5];//是什么?
arr3是一个数组,有五个元素,每个元素是一个整形指针。


 

转载于:https://blog.csdn.net/m0_57304511/article/details/122259605

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c语言-指针 的相关文章

  • WindowsAPI-Findwindow函数和FindWindowEx用法

    1 函数说明 FindWindow xff0c Win32 API函数 FindWindow函数返回与指定字符串相匹配的窗口类名或窗口名的最顶层窗口的窗口句柄 这个函数不会查找子窗口 2 函数原型 xff1a HWND FindWindow
  • 利用FindWindow和SendMessage进程通信

    利用FindWindow和SendMessage xff0c 特此记下 首先说FindWindow FindWindow返回与指定字符创相匹配的窗口类名或窗口名的最顶层窗口的窗口句柄 函数原型为 xff1a C 43 43 xff1a HW
  • vnc viewer,什么是vnc viewer

    在日常工作中 xff0c 经常会用到vnc xff0c 自然也会用到vncviewer xff0c 那你知道什么是vncviewer吗 xff1f 怎么使用vncviewer呢 xff1f 接下来让我们一起去看看吧 首先先让我们来看看一款v
  • 句柄的概念详解

    1 这里将句柄所能标识的所有东西 xff08 如窗口 文件 画笔等 xff09 统称为 对象 2 图中一个小横框表示一定大小的内存区域 xff0c 并不代表一个字节 xff0c 如标有0X00000AC6的横框表示4个字节 程序运行到某时刻
  • Server.Transfer 和 Response.Redirect 的用法

    在ASP NET中 xff0c 在后台传值方式目前大多都是用 Response Redirect 34 页面地址 34 来重定向页面的 xff0c 但是现在还有一种方式也可以达到重定向页面的作用 xff0c 而且在某些时刻会起到一种很棒的效
  • WebForm连接数据库实例

    登录页面 xff1a 用户名文本框 密码文本框 登录按钮 当用户名密码输入正确 xff0c 点击确定可以跳转到下一个页面 我们需要先引入命名空间 xff1a using System Data using System Data SqlCl
  • ASP.NET WebForm和Mvc开发的比较

    在初步了解MVC后 xff0c 发现很多人对于MVC和三层架构开发概念上会有很大的混淆 xff0c 所以把这两天的学习笔记整理一下 xff0c 分享给自己的同学们 同时也做一个小Demo xff0c 让没有接触过MVC开发的同学 xff0c
  • ASP.NET - MVC框架及搭建教程

    一 MVC简介 MVC xff1a Model View Controller xff08 模型 视图 控制器 xff09 xff0c MVC是一种软件开发架构模式 1 模型 xff08 Model xff09 模型对象是实现应用程序数据域
  • Web 绘图—服务器端绘图

    Web服务器端绘图的基本原理是 xff1a 首先在内存中创建一个Bitmap位图 xff0c 然后在此位图上绘制任意想要的图形 xff0c 绘制完成后保存输出到页面的输出流 这样 xff0c 一个页面就转换成了绘制的图片 1 xff0e 简
  • 在VS2015中安装Qt环境

    1 安装Qt 1 xff09 下载 下载网址 xff1a https download qt io archive qt 选择要下载的版本 xff0c 我选择5 12 5 xff0c 点击下载即可 点击 Detail 按钮可以看到安装文件资
  • Qt Quick 中 QML 与 C++ 混合编程详解

    Qt Quick 技术的引入 xff0c 使得你能够快速构建 UI xff0c 具有动画 各种绚丽效果的 UI 都不在话下 但它不是万能的 xff0c 也有很多局限性 xff0c 原来 Qt 的一些技术 xff0c 比如低阶的网络编程如 Q
  • windows消息机制深入详解-1

    Windows 是一个事件驱动的操作系统 事件驱动围绕着消息的产生与处 理展开 xff0c 事件驱动是靠消息循环机制来实现的 也可以理解为消息是一种报告有关事件发生 的通知 xff0c 消息是Windows 操作系统的灵魂 在屏幕显示一个窗
  • windows消息机制详解-3

    1 引言 Windows 在操作系统平台占有绝对统治地位 xff0c 基于Windows 的编程和开发越来越广泛 Dos 是过程驱动的 xff0c 而Windows 是事件驱动的 6 xff0c 这种差别的存在使得很多Dos 程序员不能 习
  • vnc server安装教程,在win系统下如何进行vnc server安装

    在日常工作中 xff0c 经常会使用到vnc server xff0c 那有小伙伴知道vnc server是什么吗 xff1f vnc server 是一般 Linux 发行版都会附带的 vnc服务器软件 vncserver 是一个为了满足
  • Windows消息机制详解-2

    消息是指什么 xff1f 消息系统对于一个win32程序来说十分重要 xff0c 它是一个程序运行的动力源泉 一个消息 xff0c 是系统定义的一个32位的值 xff0c 他唯一的定义了一个事件 xff0c 向 Windows发出一个通知
  • windows消息机制-4(MFC)

    消息分类与消息队列 Windows中 xff0c 消息使用统一的结构体 xff08 MSG xff09 来存放信息 xff0c 其中message表明消息的具体的类型 xff0c 而wParam xff0c lParam是其最灵活的两个变量
  • Windows消息机制详解-5

    一 什么是消息 在解释什么是消息之前 xff0c 我们先讨论一下程序的执行机制问题 大体上说 xff0c 程序按照执行机制可以分为两类 xff1a 第一类是过程驱动 比如我们最早接触编程时写的C程序 xff0c 又或者单片机程序 这类程序往
  • Windows句柄-2

    这里需要说明 xff1a 1 这里将句柄所能标识的所有东西 xff08 如窗口 文件 画笔等 xff09 统称为 对象 2 图中一个小横框表示一定大小的内存区域 xff0c 并不代表一个字节 xff0c 如标有0X00000AC6的横框表示
  • Windows消息机制详解-6

    消息系统对于一个win32程序来说十分重要 xff0c 它是一个程序运行的动力源泉 一个消息 xff0c 是系统定义的一个32位的值 xff0c 他唯一的定义了一个事件 xff0c 向 Windows发出一个通知 xff0c 告诉应用程序某
  • TranslateMessage ,GetMessage, DispatchMessage分析

    TranslateMessage amp msg TranslateMessage是用来把快捷键消息转换为字符消息 并将转换后的新消息投递到调用线程的消息队列中 由于Windows对所有键盘编码都是采用虚拟键的定义 xff0c 这样当按键按

随机推荐

  • Windows消息机制-PreTranslateMessage

    PreTranslateMessage作用和使用方法 Windows消息机制的流程 xff1a A 操作系统接收应用程序的窗口消息 xff0c 将消息投递到该应用程序的消息队列中 B 应用程序在消息循环中调用GetMessage函数从消息队
  • 线程中发送消息阻塞问题解决

    发送消息时阻塞的两种方案1 此处应post发送消息放到消息队列中 xff0c 直接send调用响应过程的话如果消息响应未结束则会一直阻塞工作线程2 用send的话在此处开辟工作线程执行逻辑
  • qt+visa实现程控实例

    软件环境 系统 windows 10开发环境 Qt 5 80visa库版本 visa 6 0 软件下载 QtNI MAXIVI 步骤 1 添加依赖库 在Demo pro中添加依赖 win32 INCLUDEPATH 43 61 34 C P
  • Qt中标准对话框实例,QObject::tr()的作用

    函数 tr 全名是QObject tr 被它处理的 字符串可以 使用工具提 取出来翻译 成其他语言 也就是做国际化使用 只要记住 Qt 的最佳实践 如果你想让你的程序国际化的话 那么 所有用户可见的字符串都要使用 QObject tr 但是
  • 公司电脑安装了vncserver,公司电脑安装了vncserver怎么卸载vncserver

    在使用vncserver时感觉很方便 xff0c 但在卸载vncserver时往往比较让人头疼 xff0c 之前公司电脑安装了vncserver使用时我还比较庆幸 xff0c 但当我卸载时真的费了很多力气 xff0c 那今天小编就来教教大家
  • 进程,线程,消息循环的关系

    一个进程有n个线程 xff0c 一个线程有一个消息队列或事件队列和一个活动的消息循环 xff0c 每个模态窗体有一个消息循环函数和一个消息响应过程函数 xff0c 一个线程里哪个模态窗体激活即运行哪个窗体的消息循环 xff0c 一个模态窗体
  • Qt匿名函数的写法

    匿名函数也可以被叫做Lambda表达式 xff0c 自C 43 43 11中引入该特性 本文主要介绍Qt里使用到的匿名函数 c11新特性中加入了lambda表达式 xff0c 所以Qt 也支持 需在 pro文件中加入 CONFIG 43 6
  • QT c++ 中使用PostMessage/SendMessage实例

    PostMessage是Windows API 应用程序接口 中的一个常用函数 xff0c 用于将一条消息放入到消息队列中 并且不会等待响应的线程处理消息 xff0c 而是直接返回 xff08 简单的理解就是异步 xff09 而SendMe
  • Qt-线程启动与关闭实例

    养成资源回收的好习惯 xff0c 任何时候都要想起开辟过的内存回收 就是利用关闭窗口时调用槽函数回收掉 具体步骤不难 xff0c 如下 xff1a 1 xff09 退出线程 xff1b 2 xff09 回收子线程 xff1b 3 xff09
  • qt中QListView的用法和QModelIndex的使用

    使用QTreeView xff0c 对于很多函数中针对item的唯一标识QModelIndex的使用 xff0c 记录下两种对于QModelIdex的使用 1 xff0c 树形结构的item设置为选中 QModelIndex rootInd
  • Qt-QMessageBox用法详解

    QMessageBox 是 Qt 框架中常用的一个类 xff0c 可以生成各式各样 各种用途的消息对话框 xff0c 如图 1 所示 图 1 QMessageBox消息对话框 很多 GUI 程序都会用到消息对话框 xff0c 且很多场景中使
  • Qt-手动布局

    简述 手动布局 xff0c 可以实现和水平布局 垂直布局 网格布局等相同的效果 xff0c 也可实现属于自己的自定义布局 xff0c 当窗体缩放时 xff0c 控件可以随之变化 其对于坐标系的建立有严格要求 xff0c 纯代码思维 xff0
  • Qt-5种布局控件详解

    实际开发中 xff0c 一个界面上可能包含十几个控件 xff0c 手动调整它们的位置既费时又费力 作为一款成熟的 GUI 框架 xff0c Qt 提供了很多摆放控件的辅助工具 xff08 又称布局管理器或者布局控件 xff09 xff0c
  • vnc怎么设置自适应屏幕,2种方法教你vnc怎么设置自适应屏幕

    VNC 是在基于 UNIX和 LINUX 操作系统的免费的开源软件 xff0c 远程控制能力强大 xff0c 高效实用 xff0c 其性能可以和 WIndows和 MAC 中的任何远程控制软件媲美 在使用vnc软件的过程中 xff0c 往往
  • C++中的野指针问题

    文章目录 1 C和C 43 43 中的野指针问题 1 1 野指针的概念 1 2 野指针的由来 1 3 杜绝野指针的基本原则 2 C和C 43 43 中的常见内存错误 2 1 常见内存错误 2 2 内存操作的基本规则 1 C和C 43 43
  • Qt-调用dll动态链接库

    事先写一个简单的dll文件 myDLL dll C版接口的 并且用我前两篇有关DLL文章里面的方法 xff0c 从dll中导出了导入库 lib 文件 xff0c dll中有两个函数 xff0c 原型如下 xff1a void HelloWo
  • Qt调用动态链接库ControlCAN.dll实例

    注意 xff1a controlCan引用静态库时需要将kerneldlls文件夹放置程序的输出路径下设备才能链接成功 首先添加外部库文件 xff08 lib文件 xff09 一 添加第三方的头文件 这个问题再简单不过了 xff0c 不过我
  • asposeword.dll通过word模板生成word、PDF

    效果图 1 word模板 xff08 部分 xff09 书签 2 生成结果图 开始上代码 Dictionary lt string string gt dictSource 61 new Dictionary lt string strin
  • Qt-捕获Windows消息

    Qt4版本的实现 方法1 xff1a 通过继承QWidget的类中重新实现winEvent接口 xff0c 以接收在消息参数中传递的本机Windows事件 bool QWidget winEvent MSG message long res
  • c语言-指针

    目录 1 指针是什么 xff1f 2 指针和指针类型 2 1 指针 43 整数 2 2 指针的解引用 3 野指针 3 1 野指针成因 3 2 如何规避野指针 4 指针运算 4 1 指针 43 整数 4 2 指针 指针 4 3 指针的关系运算