【C】Re05 指针
一、变量 & 指针
变量 = 内存地址 + 存储值
指针变量 = 内存地址 + 存储值【变量的内存地址】
作用: 间接访问内存地址
内存地址 = 地址编号
地址编号:内存中的每个字节唯一的编号,从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 = #
// 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 = #
printf("*p4 -> %#x\n", *p4); // *p4 -> 0x1020304
short * p5 = #
printf("*p5 -> %#x\n", *p5); // *p5 -> 0x304
char * p6 = #
printf("*p6 -> %#x\n", *p6); // *p5 -> 0x304
}
int main() {
differFromPointers();
return 0;
}
【C】Re05 指针的更多相关文章
- TODO:Golang指针使用注意事项
TODO:Golang指针使用注意事项 先来看简单的例子1: 输出: 1 1 例子2: 输出: 1 3 例子1是使用值传递,Add方法不会做任何改变:例子2是使用指针传递,会改变地址,从而改变地址. ...
- enote笔记法使用范例(2)——指针(1)智能指针
要知道什么是智能指针,首先了解什么称为 “资源分配即初始化” what RAII:RAII—Resource Acquisition Is Initialization,即“资源分配即初始化” 在&l ...
- C++虚函数和函数指针一起使用
C++虚函数和函数指针一起使用,写起来有点麻烦. 下面贴出一份示例代码,可作参考.(需要支持C++11编译) #include <stdio.h> #include <list> ...
- C++11 shared_ptr 智能指针 的使用,避免内存泄露
多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...
- c 数组与指针的使用注意事项
数组变量和指针变量有一点小小的区别 所以把数组指针赋值给指针变量的时候千万要小心 加入把数组赋值给指针变量,指针变量只会包含数组的地址信息 而对数组的长度一无所知 相当于指针丢失了一部分信息,我们把这 ...
- Marshal.Copy将指针拷贝给数组
lpStatuss是一个UNITSTATUS*的指针类型实例,并包含SensorDust字段 //定义一个数组类型 byte[] SensorDust = new byte[30] //将指针类型拷贝 ...
- C++智能指针
引用计数技术及智能指针的简单实现 基础对象类 class Point { public: Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) { ...
- EC笔记:第三部分:17、使用独立的语句将newed对象放入智能指针
一般的智能指针都是通过一个普通指针来初始化,所以很容易写出以下的代码: #include <iostream> using namespace std; int func1(){ //返回 ...
- 智能指针shared_ptr的用法
为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer). 智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,当程序退出栈的作用域范围后,由于栈 ...
- 智能指针unique_ptr的用法
unique_ptr是独占型的智能指针,它不允许其他的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr,如下面错误用法: std::unique_pt ...
随机推荐
- vant做城市列表
vant: https://youzan.github.io/vant/#/zh-CN/ 安装 cnpm i -S vant 按需加载配置 # 在 babel.config.js 中配置 module ...
- kettle从入门到精通 第三十四课 kettle 错误处理
1.我们在平常写应用程序的时候,需要主动捕获异常或者错误,不然程序有可能异常退出.同样kettle 也支持异常或者错误处理,下图展示的是在批量插入数据的时候捕获异常,如唯一健冲突,死锁等,并将错误信息 ...
- leetcode | 107. 二叉树的层序遍历 II | javascript实现 | c++实现
题目 给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 . (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历) 思路 题目的要求相当于是求层序遍历数组的转置,我们只需利用js的 ...
- .NET 个人博客-给文章添加上标签
个人博客-给文章添加上标签 优化计划 置顶3个且可滚动或切换 推荐改为4个,然后新增历史文章,将推荐的加载更多放入历史文章,按文章发布时间降序排列. 标签功能,可以为文章贴上标签 推荐点赞功能 本篇文 ...
- Android日志系统(logging system)
Android日志系统(logging system) 背景 不管是做Android应用还是做Android中间层和底层,在做一些调试工作的时候,使用adb logcat非常关键.特意学习了一下安卓的 ...
- 详细讲解 Keil Pack Installer,以及通过 Keil 官网获取 Pack
前言 大家好,我是梁国庆. 收到粉丝留言,说 Keil 安装 Pack 不太明白,可不可以详细演示一下? 当然可以有,直接视频+文章全部安排,我就是宠粉. PS:第一次录视频有些紧张,见谅哈. 微信视 ...
- React项目国际化-React-intl
npx create-react-app react-intl-demo && cd react-intl-demo,创建react-intl-demo项目.npm install r ...
- 写给rust初学者的教程(一):枚举、特征、实现、模式匹配
这系列RUST教程一共三篇.这是第一篇,介绍RUST语言的入门概念,主要有enum\trait\impl\match等语言层面的东西. 安装好你的rust开发环境,用cargo创建一个空项目,咱们直接 ...
- BZOJ 1461 题解
考虑设计一个哈希函数 \(hash(x) = f(x) \times base^x\). 其中 \(f(x)\) 表示 \(\sum_{j=1}^{i-1} [j <i]\). 然后类似于滑动窗 ...
- vulnhub - LAMPSECURITY: CTF5
vulnhub - LAMPSECURITY: CTF5 信息收集 端口扫描 nmap -sT --min-rate 10000 -p- 192.168.157.164 详细扫描 sudo nmap ...