一、变量 & 指针

变量 = 内存地址 + 存储值

指针变量 = 内存地址 + 存储值【变量的内存地址】

作用: 间接访问内存地址

内存地址 = 地址编号

地址编号:内存中的每个字节唯一的编号,从0开始记录,使用十六进制显示

可以使用指针变量存储变量的地址

不同数据类型就有对应的指针的数据类型

二、使用

#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h> void pointer () {
// 指针变量
int * pointer;
// 变量
int varA = 100; printf("pointer -> x16 %x, x10 %d, x8 %o\n", pointer, pointer, pointer);
printf("varA -> %d\n", varA); printf("- - - - - - - - - - - - - - -\n"); // 把varA的地址赋值给指针变量pointer
pointer = &varA;
// 通过指针变量pointer取地址访问varA变量
*pointer = 20; printf("pointer -> x16 %x, x10 %d, x8 %o\n", pointer, pointer, pointer);
printf("varA -> %d\n", varA);
} int main() {
pointer();
return EXIT_SUCCESS;
}

输出格式注意:

 // %p显示完整十六进制位数, %x只显示进制数

语法递进:

    int tf = (*pointer == *&varA); // 0 false, 1 true
int tf2 = (pointer == &varA);
int tf3 = (*pointer == varA); printf(" %d\n",tf);
printf(" %d\n",tf2);
printf(" %d\n",tf3);

三、空指针& 野指针

空指针定义

void nullPointerAndWildPointer () {
// 定义一个空指针
int * nullPointer = NULL;
}

指向的NULL常量来自于STDLIB标准库头文件的这一段

#else
#define NULL ((void *)0)
#endif
#endif

最后指向的还是一个0而已

void nullPointerAndWildPointer () {
// 定义一个空指针
int * nullPointer = 0;
}

实际上不建议直接写0,容易混淆指针变量与变量

空指针不能被访问到:

void nullPointerAndWildPointer () {
// 定义一个空指针
int * nullPointer = NULL;
printf("nullPointer -> %p", *nullPointer);
} int main() {
nullPointerAndWildPointer();
return EXIT_SUCCESS;
}

因为内存地址编号0 - 255已经被操作系统占用了

空指针的作用:

不知道应该对指针定义多少合适时使用

野指针定义:

void nullPointerAndWildPointer () {
int * wildPointer = 0xffff;
printf("wildPointer -> %p\n", *wildPointer);
}

指针变量存储了非法的、未知的一个内存地址,该地址存储的内容将无法访问

但是允许查看地址

void nullPointerAndWildPointer () {
// 定义一个空指针
// int * nullPointer = NULL;
// printf("nullPointer -> %p\n", *nullPointer); // 定义一个野指针
// int * wildPointer = 0xffff;
// printf("wildPointer -> %p\n", *wildPointer); int * nullPointer = NULL;
printf("nullPointer -> %p\n", nullPointer); int * wildPointer = 0xffff;
printf("wildPointer -> %p\n", wildPointer);
} int main() {
nullPointerAndWildPointer();
return EXIT_SUCCESS;
}

野指针的第二种情况:

也是一样,地址可以访问,但是内部存储的值无法访问

    // 野指针的第二种情况
int * wildPointer2;
printf("wildPointer2 -> %p\n", wildPointer2);
// printf("wildPointer2 value -> %d\n", *wildPointer2);

四、无类型指针 和 万能指针

1、Void类型概述

void voidUsage() {
// void 是一个数据类型,所以也具备对于的指针类型 void *
// void 的用途是修饰函数返回类型和形参类型
} // 形参修饰了void 表示 该函数不需要参数
void noNeedParam( void ) { }

2、函数返回类型省略

当函数的返回值类型声明的是void时,我们可以省略,不需要return

不过不建议这样书写,C++并不支持这样的语法

aaa () {
printf("void返回类型省略的函数调用!!!");
} int main() {
aaa();
return EXIT_SUCCESS;
}

如果函数不需要注入任何类型的参数,编写时是可以明确标注void 数据类型即可

3、无类型指针与万能指针:

无类型指针可以强转任意类型接收对于的类型的变量地址

void noTypePointer() {
void * p = NULL;
printf("sizeof p = %d\n", sizeof(p)); // 64位 sizeof p = 8 32位 sizeof p = 4 int num = 10;
p = &num;
// printf("p = %d\n", *p); int指针类型赋值给void指针类型, 类型不匹配错误
// 使用强转来转换指针类型
printf("p = %d\n", *(int *)p);
}

另外可以作为万能指针使用:

void anyTypePointer() {

    void * pointer = NULL;

    int * varA = NULL;
char * varB = NULL; // 一个是int指针类型一个是char指针类型,直接这样赋值不会有语法错误提示
// 但是在编译执行时会有警告提示,另外,如果指针调用了就会报错。。。
// varA = varB;
// 所以需要强转处理
varA = (int *)varB; // void*指针类型的指针可以赋值给任何指针类型,不需要强转【自动转换?】
varA = pointer;
} // 因为void*指针类型 第二用,作为参数类型
void function ( void * sss) { }

五、Const修饰指针变量

void constWithPointer() {
// 1、const修饰的是*, *p 是只读的, p可读可写的
int varA = 100;
const int * pToVarA = &varA; // 如何判断是修饰* 还是 p? 看*还是p靠前,和const近, 等同于 int const * pToVarA = &varA;
// *pToVarA = 20; 不允许访问地址写入了 printf("pointer -> %p\n", pToVarA); int varB = 200;
pToVarA = &varB; // 更改赋值地址是允许的 printf("pointer -> %p\n", pToVarA); // 总结下来就是:指针指向地址的存储值不可以改变,指向地址可以改变 // -------------------------------------------------------------- // 2、const修饰的是p, p 是只读的, *p可读可写的
int c = 150; // 语法
int * const p = &c; // 可以对指向地址的存储值进行写入更改
*p = 20;
// p = &varA; 但是不再允许指向其他地址了 // 指针指向地址的存储值可以修改,但是指针的指向地址不可以修改 // -------------------------------------------------------------- // 3、const修饰的是*和p, *和p都是只读的
int d = 120;
int const * const p2 = &d;
// p2 = &c; 更改指向 不允许
// *p2 = 230; 更改存储值 不允许
} int main() {
constWithPointer();
return 0;
}

六、不同指针类型的区别?

void differFromPointers() {
char * p1 = NULL;
int * p2 = NULL;
double * p3 = NULL; printf("p1 -> %p\n", p1);
printf("p2 -> %p\n", p2);
printf("p3 -> %p\n", p3); // 区别1 不同指针类型 叠加字面值的步长不一样,这取决于他们的数据类型长度
printf("p1 + 1 -> %p\n", p1 + 1); // char指针类型向前移动一个字节
printf("p2 + 1 -> %p\n", p2 + 1); // int指针类型向前移动4个字节
printf("p3 + 1 -> %p\n", p3 + 1); // 区别2 解引用的字节数量也不一样,取到的值也就不一样
int num = 0x01020304; // int num = 0x01020304; int num = 0x21348903;
int * p4 = &num;
printf("*p4 -> %#x\n", *p4); // *p4 -> 0x1020304 short * p5 = &num;
printf("*p5 -> %#x\n", *p5); // *p5 -> 0x304 char * p6 = &num;
printf("*p6 -> %#x\n", *p6); // *p5 -> 0x304
} int main() {
differFromPointers();
return 0;
}

【C】Re05 指针的更多相关文章

  1. TODO:Golang指针使用注意事项

    TODO:Golang指针使用注意事项 先来看简单的例子1: 输出: 1 1 例子2: 输出: 1 3 例子1是使用值传递,Add方法不会做任何改变:例子2是使用指针传递,会改变地址,从而改变地址. ...

  2. enote笔记法使用范例(2)——指针(1)智能指针

    要知道什么是智能指针,首先了解什么称为 “资源分配即初始化” what RAII:RAII—Resource Acquisition Is Initialization,即“资源分配即初始化” 在&l ...

  3. C++虚函数和函数指针一起使用

    C++虚函数和函数指针一起使用,写起来有点麻烦. 下面贴出一份示例代码,可作参考.(需要支持C++11编译) #include <stdio.h> #include <list> ...

  4. C++11 shared_ptr 智能指针 的使用,避免内存泄露

    多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...

  5. c 数组与指针的使用注意事项

    数组变量和指针变量有一点小小的区别 所以把数组指针赋值给指针变量的时候千万要小心 加入把数组赋值给指针变量,指针变量只会包含数组的地址信息 而对数组的长度一无所知 相当于指针丢失了一部分信息,我们把这 ...

  6. Marshal.Copy将指针拷贝给数组

    lpStatuss是一个UNITSTATUS*的指针类型实例,并包含SensorDust字段 //定义一个数组类型 byte[] SensorDust = new byte[30] //将指针类型拷贝 ...

  7. C++智能指针

    引用计数技术及智能指针的简单实现 基础对象类 class Point { public: Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) { ...

  8. EC笔记:第三部分:17、使用独立的语句将newed对象放入智能指针

    一般的智能指针都是通过一个普通指针来初始化,所以很容易写出以下的代码: #include <iostream> using namespace std; int func1(){ //返回 ...

  9. 智能指针shared_ptr的用法

    为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer). 智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,当程序退出栈的作用域范围后,由于栈 ...

  10. 智能指针unique_ptr的用法

    unique_ptr是独占型的智能指针,它不允许其他的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr,如下面错误用法: std::unique_pt ...

随机推荐

  1. vant做城市列表

    vant: https://youzan.github.io/vant/#/zh-CN/ 安装 cnpm i -S vant 按需加载配置 # 在 babel.config.js 中配置 module ...

  2. kettle从入门到精通 第三十四课 kettle 错误处理

    1.我们在平常写应用程序的时候,需要主动捕获异常或者错误,不然程序有可能异常退出.同样kettle 也支持异常或者错误处理,下图展示的是在批量插入数据的时候捕获异常,如唯一健冲突,死锁等,并将错误信息 ...

  3. leetcode | 107. 二叉树的层序遍历 II | javascript实现 | c++实现

    题目 给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 . (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历) 思路 题目的要求相当于是求层序遍历数组的转置,我们只需利用js的 ...

  4. .NET 个人博客-给文章添加上标签

    个人博客-给文章添加上标签 优化计划 置顶3个且可滚动或切换 推荐改为4个,然后新增历史文章,将推荐的加载更多放入历史文章,按文章发布时间降序排列. 标签功能,可以为文章贴上标签 推荐点赞功能 本篇文 ...

  5. Android日志系统(logging system)

    Android日志系统(logging system) 背景 不管是做Android应用还是做Android中间层和底层,在做一些调试工作的时候,使用adb logcat非常关键.特意学习了一下安卓的 ...

  6. 详细讲解 Keil Pack Installer,以及通过 Keil 官网获取 Pack

    前言 大家好,我是梁国庆. 收到粉丝留言,说 Keil 安装 Pack 不太明白,可不可以详细演示一下? 当然可以有,直接视频+文章全部安排,我就是宠粉. PS:第一次录视频有些紧张,见谅哈. 微信视 ...

  7. React项目国际化-React-intl

    npx create-react-app react-intl-demo && cd react-intl-demo,创建react-intl-demo项目.npm install r ...

  8. 写给rust初学者的教程(一):枚举、特征、实现、模式匹配

    这系列RUST教程一共三篇.这是第一篇,介绍RUST语言的入门概念,主要有enum\trait\impl\match等语言层面的东西. 安装好你的rust开发环境,用cargo创建一个空项目,咱们直接 ...

  9. BZOJ 1461 题解

    考虑设计一个哈希函数 \(hash(x) = f(x) \times base^x\). 其中 \(f(x)\) 表示 \(\sum_{j=1}^{i-1} [j <i]\). 然后类似于滑动窗 ...

  10. vulnhub - LAMPSECURITY: CTF5

    vulnhub - LAMPSECURITY: CTF5 信息收集 端口扫描 nmap -sT --min-rate 10000 -p- 192.168.157.164 详细扫描 sudo nmap ...