一、变量 & 指针

变量 = 内存地址 + 存储值

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

作用: 间接访问内存地址

内存地址 = 地址编号

地址编号:内存中的每个字节唯一的编号,从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. Vuex 4与状态管理实战指南

    title: Vuex 4与状态管理实战指南 date: 2024/6/6 updated: 2024/6/6 excerpt: 这篇文章介绍了使用Vuex进行Vue应用状态管理的最佳实践,包括为何需 ...

  2. margin的用法 清除默认样式 display属性值 块状元素 内联元素 行内块元素

    margin的用法: 1,margin是在元素的宽高以外的 2,作用:控制元素之间的位置关系 3,margin不能改变盒子本身大小的 4,单一一个方向设置margin值: margin-left    ...

  3. ETL工具-nifi干货系列 第十七讲 nifi Input Port&Out Port 实战教程

    1.端口(Port),包含输入端口(Input Port)和输出端口(Out Port ) 使用一个或多个处理组构建的数据流需要一种方式将处理组连接到其他数据流组件. 处理组和处理组之间可以通过使用端 ...

  4. 使用 Promise.withResolvers() 来简化你将函数 Promise 化的实现~~

    引言 在JavaScript编程中,Promise 是一种处理异步操作的常用机制.Promise 对象代表了一个尚未完成但预期将来会完成的操作的结果.在本文中,我们将探讨如何通过使用 ES2024 的 ...

  5. SM4Utils加解密demo

    SM4Utils加解密demo package com.example.core.mydemo.sm4; import cn.org.bjca.utils.SM4Utils; public class ...

  6. MySQL查询关于区分字母大小写问题

    前段时间在工作中测试提出了一个BUG,让我把根据ID查询区分大小写的功能去掉,大小写都随便查,然后我在SQL的位置加上了UPPER(id) = UPPER(#{id})的写法,而同事知道这个问题后的反 ...

  7. 实验四:WinRAR漏洞

    [实验目的] 通过打开rar文件,获取到目标机shell. [知识点] winrar漏洞 [实验原理] 该漏洞是由于WinRAR所使用的一个陈旧的动态链接库UNACEV2.dll所造成的,该动态链接库 ...

  8. Mybatis 判断表达式除坑

    Mybatis 判断表达式经常有各种坑,比如数值的判断,空值的判断坑等,可以通过如下代码测试一下是否符合预期 import org.apache.ibatis.ognl.Ognl; import or ...

  9. 【论文阅读】Exploring the Limitations of Behavior Cloning for Autonomous Driving

    Column: January 16, 2022 11:11 PM Last edited time: January 21, 2022 12:23 PM Sensor/组织: 1 RGB Statu ...

  10. 案例分享!RK3568 + FPGA多通道AD采集处理与显示

    案例展示 测试数据汇总   表 1     本文带来的是基于瑞芯微RK3568J + 紫光同创Logos-2的ARM + FPGA多通道AD采集处理与显示案例. 本次案例演示的开发环境如下: Wind ...