铁律1:指针是一种数据类型

1)指针也是一种变量,占有内存空间,用来保存内存地址
测试指针变量占有内存空间大小

2)*p操作内存
在指针声明时,*号表示所声明的变量为指针
在指针使用时,*号表示 操作 指针所指向的内存空间中的值
*p相当于通过地址(p变量的值)找到一块内存;然后操作内存
*p放在等号的左边赋值(给内存赋值)
*p放在等号的右边取值(从内存获取值)

3)指针变量和它指向的内存块是两个不同的概念
//含义1 给p赋值p=0x1111; 只会改变指针变量值,不会改变所指的内容;p = p +1; //p++
//含义2 给p赋值p=‘a’; 不会改变指针变量的值,只会改变所指的内存块的值
//含义3 =左边p 表示 给内存赋值, =右边p 表示取值 含义不同切结!
//含义4 =左边char *p
//含义5 保证所指的内存块能修改

4)指针是一种数据类型,是指它指向的内存空间的数据类型
含义1:指针步长(p++),根据所致内存空间的数据类型来确定
p++=➜(unsigned char )p+sizeof(a);
结论:指针的步长,根据所指内存空间类型来定。

注意:建立指针指向谁,就把把谁的地址赋值给指针。图和代码和二为一。
不断的给指针变量赋值,就是不断的改变指针变量(和所指向内存空间没有任何关系)。

铁律2:间接赋值(*p)是指针存在的最大意义

1)两码事:指针变量和它指向的内存块变量
2)条件反射:指针指向某个变量,就是把某个变量地址否给指针
3)*p间接赋值成立条件:3个条件
a)2个变量(通常一个实参,一个形参)
b) 建立关系,实参取地址赋给形参指针
c) *p形参去间接修改实参的值

Int iNum = 0; //实参int *p = NULL;p = &iNum;iNum = 1;*p =2 ; //通过*形参 == 间接地改变实参的值*p成立的三个条件:

4)引申: 函数调用时,用n指针(形参)改变n-1指针(实参)的值。
//改变0级指针(int iNum = 1)的值有2种方式
//改变1级指针(eg char *p = 0x1111 )的值,有2种方式
//改变2级指针的(eg char **pp1 = 0x1111 )的值,有2种方式

//函数调用时,形参传给实参,用实参取地址,传给形参,在被调用函数里面用*p,来改变实参,把运算结果传出来。
//指针作为函数参数的精髓。

铁律3:理解指针必须和内存四区概念相结合

1) 主调函数 被调函数
a) 主调函数可把堆区、栈区、全局数据内存地址传给被调用函数
b) 被调用函数只能返回堆区、全局数据
2) 内存分配方式
a) 指针做函数参数,是有输入和输出特性的。

铁律4:应用指针必须和函数调用相结合(指针做函数参数)

编号 指针函数参数内存分配方式(级别+堆栈) 主调函数实参 被调函数形参 备注
01 1级指针(做输入) 分配 使用 一般应用禁用
分配 使用 常用
Int showbuf(char *p); int showArray(int *array, int iNum)
02 1级指针(做输出) 使用 结果传出 常用
int geLen(char *pFileName, int *pfileLen);
03 2级指针(做输入) 分配 使用 一般应用禁用
分配 使用 常用
int main(int arc ,char *arg[]); 指针数组int shouMatrix(int [3][4], int iLine);二维字符串数组
04 2级指针(做输出) 使用 分配 常用,但不建议用,转化成02
int getData(char **data, int *dataLen);Int getData_Free(void *data);Int getData_Free(void **data); //避免野指针
05 3级指针(做输出) 使用 分配 不常用
int getFileAllLine(char ***content, int *pLine);int getFileAllLine_Free(char ***content, int *pLine);

指针做函数参数,问题的实质不是指针,而是看内存块,内存块是1维、2维。

  1. 如果基础类int变量,不需要用指针;
  2. 若内存块是1维、2维。

铁律5:一级指针典型用法(指针做函数参数)

一级指针做输入

int showbuf(char *p)int showArray(int *array, int iNum)

一级指针做输出

int geLen(char *pFileName, int *pfileLen);

理解

主调函数还是被调用函数分配内存
被调用函数是在heap/stack上分配内存

铁律6:二级指针典型用法(指针做函数参数)

二级指针做输入

int main(int arc ,char *arg[]); 字符串数组int shouMatrix(int [3][4], int iLine);

二级指针做输出

int Demo64_GetTeacher(Teacher **ppTeacher);int Demo65_GetTeacher_Free(Teacher **ppTeacher);int getData(char **data, int *dataLen);Int getData_Free(void *data);Int getData_Free2(void **data); //避免野指针

理解

主调函数还是被调用函数分配内存
被调用函数是在heap/stack上分配内存

铁律7: 三级指针输出典型用法

三级指针做输出

int getFileAllLine(char ***content, int *pLine);int getFileAllLine_Free(char ***content, int *pLine);

理解

主调函数还是被调用函数分配内存
被调用函数是在heap/stack上分配内存

铁律8:杂项,指针用法几点扩充

1)野指针 2种free形式

int getData(char **data, int *dataLen);int getData_Free(void *data);int getData_Free2(void **data);

2)2次调用
主调函数第一次调用被调用函数求长度;根据长度,分配内存,调用被调用函数。
3)返回值char */int/char **
4)C程序书写结构
商业软件,每一个出错的地方都要有日志,日志级别

铁律9:一般应用禁用malloc/new

【王保明老师经典语录】

1)指针也是一种数据类型,指针的数据类型是指它所指向内存空间的数据类型
2)间接赋值*p是指针存在的最大意义
3)理解指针必须和内存四区概念相结合
4)应用指针必须和函数调用相结合(指针做函数参数)
指针是子弹,函数是枪管;子弹只有沿着枪管发射才能显示它的威力;指针的学习重点不言而喻了吧。接口的封装和设计、模块的划分、解决实际应用问题;它是你的工具。
5)指针指向谁就把谁的地址赋给指针
6)指针指向谁就把谁的地址赋给指针,用它对付链表轻松加愉快
7)链表入门的关键是分清楚链表操作和辅助指针变量之间的逻辑关系
8)C/C++语言有它自己的学习特点;若java语言的学习特点是学习、应用、上项目;那么C/C++语言的学习特点是:学习、理解、应用、上项目。多了一个步骤吧。
9)学好指针才学会了C语言的半壁江山,另外半壁江山在哪里呢?你猜,精彩剖析在课堂。
10) 理解指针关键在内存,没有内存哪来的内存首地址,没有内存首地址,哪来的指针啊。

代码解析

#define  _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <string.h>
#include <stdio.h>void main00()
{int a = 10;char *p1 = 100;  //分配4个字节的内存char ****p2 = 100;int *p3 = NULL;p3 = &a;*p3 = 20; //间接的修改a的值//*就像一把钥匙 通过一个地址(&a),去修改a变量的标示的内存空间{int c = 0;c = *p3;  //c=20//*p放在=号左边 写内存//*p放=号的右边 读内存printf("c:%d \n", c);}{char *p4 = NULL;p4 = (char *)malloc(100);p4 = (char *)malloc(200); //0xcc11}printf("a:%d , p1:%d , p2: %d", sizeof(a), sizeof(p1), sizeof(p2));printf("hello...\n");system("pause");return ;
}char *getStr()
{char *tmp = NULL;tmp = "abcdefgf";return tmp;
}/*
int  getABC1(char    *p1);  int getABC1(char*       p1);
int getABC2(char **    p2); int getABC2(char *    *p2);   int   getABC2(char           **p2);
int getABC3(char ***p3);
int getABC4(char (*p4)[30]);  int   getABC4(char (*p4)            [30]);
int getABC5(char p5[10][30]); int   getABC5(char p5[10][30]);
//指针做函数参数 形参有多级指针的时候,
//站在编译器的角度 ,只需要分配4个字节的内存(32bit平台)
//当我们使用内存的时候,我们才关心指针所指向的内存 是一维的还是二维的
*/void main()
{char *p = getStr81();printf("p:%s \n", p);*(p+2) = 'r';  //经常出现的错误 保证指针所指向的内存空间 可以被修改system("pause");return ;
}

野指针产生的原因

//指针变量和它所指向的内存空间变量是两个不同的概念//避免方法:
//1)定义指针的时候,指针变量*p1初始化成nuLL 2)释放指针所指向的内存空间后,把它所指向的内存空间变量p1重置成NULL。
void main()
{char  *p1 = NULL;p1 = (char *)malloc(100);if (p1 == NULL){return ;}strcpy(p1, "11112222");printf("p1:%s \n", p1);if (p1 != NULL){free(p1);p1 = NULL;}printf("hello...\n");system("pause");return ;
}

一级指针技术推演

int  getFileLen(int *p)
{*p = 41;  //p的值是a的地址 *a的地址间接修改a的值 //在被调用函数里面 通过形参 去 间接的修改 实参的值...
}//形参的属性
int  getFileLen3(int b)
{int  i = 0;b = 100;//p的值是a的地址 *a的地址间接修改a的值
}//1级指针的技术推演
void main()
{int a = 10;  //条件1  定义了两个变量(实参 另外一个变量是形参p)int *p = NULL;//修改a的值a = 20; //直接修改p = &a;  //条件2 建立关联*p = 30; //p的值是a的地址 *就像一把钥匙 通过地址 找到一块内存空间 求间接的修改了a的值printf("a: %d \n", a);{*p = 40;  //  p的值是a的地址 *a的地址间接修改a的值  //条件3 *pprintf("a: %d \n", a);}getFileLen(&a); //建立关联: 把实参取地址 传递给 形参printf("getFileLen后 a: %d \n", a);getFileLen3(a); //无法修改printf("getFileLen3后 a: %d \n", a);printf("hello...\n");system("pause");return ;
}

二级指针技术推演

void getMem(char **p2)
{*p2 = 400; //间接赋值  p2是p1的地址
}void getMem2(char *p2)
{p2 = 800; //间接赋值  p2是p1的地址
}void main()
{char *p1 = NULL;char **p2 = NULL;p1 = 0x11;p2 = 0x22;//直接修改p1的值p1 = 0x111;//间接修改p1的值p2 = &p1; *p2 = 100; //间接赋值  p2是p1的地址printf("p1:%d \n", p1);{*p2 = 200; //间接赋值  p2是p1的地址printf("p1:%d \n", p1);}getMem(&p1);getMem2(p1);printf("p1:%d \n", p1);system("pause");return ;
}int  getMem3(char **myp1, int *mylen1,  char **myp2, int *mylen2)
{int        ret = 0;char   *tmp1, *tmp2;tmp1 = (char *)malloc(100);strcpy(tmp1, "1132233");//间接赋值 *mylen1 = strlen(tmp1);  //1级指针*myp1 = tmp1; //2级指针的间接赋值tmp2 = (char *)malloc(200);strcpy(tmp2, "aaaaavbdddddddd");*mylen2 = strlen(tmp2);  //1级指针*myp2 = tmp2; //2级指针的间接赋值return ret;
}int  main()
{int        ret = 0;char   *p1 = NULL;int     len1 = 0;char  *p2 = NULL;int     len2 = 0; ret = getMem3(&p1, &len1, &p2, &len2);if (ret != 0){printf("func getMem3() err:%d \n", ret);return ret;}printf("p1:%s \n", p1);printf("p2:%s \n", p2);if (p1 != NULL){free(p1);p1 = NULL;}if (p2 != NULL){free(p2);p2 = NULL;}printf("p1:%d \n", p1);system("pause");return ret;
}

间接赋值成立的三个条件

/* 条件1  //定义1个变量(实参) //定义1个变量(形参)条件2  //建立关联:把实参取地址传给形参条件3://*形参去间接地的修改了实参的值。
*///间接赋值的应用场景
void main()
{//1 2 3 这3个条件 写在有一个函数//12 写在一块   3 单独写在另外一个函数里面  =====>函数调用//1         23写在一块 ===>抛砖 ====C++会有,到时候,你别不认识......char from[128];char to[128] = {0};char *p1 = from;char *p2 = to;strcpy(from, "1122233133332fafdsafas");while (*p1 != '\0'){*p2 = *p1;p2 ++;p1 ++;}printf("to:%s \n", to);system("pause");return ;
}

指针的输入与输出特性

//指针做输出:被调用函数分配内存  -----OK
//指针做输入:主调用函数 分配内存
//求文件中的两段话的长度
int getMem(char **myp1, int *mylen1, char **myp2, int *mylen2)
{char *tmp1 = NULL;char *tmp2 = NULL;tmp1 = (char *)malloc(100);if (tmp1 == NULL){return -1;}strcpy(tmp1, "abcdefg");*mylen1 = strlen(tmp1);*myp1 = tmp1; //间接修改实参p1的值tmp2 = (char *)malloc(100);if (tmp2 == NULL){return -2;}strcpy(tmp2, "11122233333");*mylen2 = strlen(tmp2);*myp2 = tmp2; //间接修改实参p1的值return 0;
}int getMem_Free(char **myp1)
{/*if (myp1 == NULL){return ;}free(*myp1);  //释放完指针变量 所致的内存空间*myp1 = NULL;  //把实参修改成nULL*/char *tmp = NULL;if (myp1 == NULL){return -1;}tmp = *myp1;free(tmp);  //释放完指针变量 所致的内存空间*myp1 = NULL;  //把实参修改成nULLreturn 0;
}void main00()
{char  *p1 = NULL;int len1 = 0;char *p2 = NULL;int len2 = 0;int ret = 0;ret  = getMem(&p1, &len1, &p2, &len2 );printf("p1: %s \n", p1);printf("p2: %s \n", p2);getMem_Free(&p1);getMem_Free(&p2);  system("pause");return ;
}int getMem_Free0(char *myp1)
{if (myp1 == NULL){return -1;}free(myp1);  //释放完指针变量 所致的内存空间myp1 = NULL;return 0;
}void main01()
{char  *p1 = NULL;int len1 = 0;char *p2 = NULL;int len2 = 0;int ret = 0;ret  = getMem(&p1, &len1, &p2, &len2 );printf("p1: %s \n", p1);printf("p2: %s \n", p2);if (p1 != NULL){free(p1);p1 = NULL;}if (p2 != NULL){free(p2);p2 = NULL;}getMem_Free0(p1);  //在被调用函数中  把p1所指向的内存给释放掉 ,但是 实参p1不能被修改成NULLL 有野指针现象getMem_Free0(p2);  system("pause");return ;
}

C/C++学习笔记之指针体系相关推荐

  1. 梓益C语言学习笔记之指针

    梓益C语言学习笔记之指针 一.32位平台下,地址是32位,所以指针变量占32位,共4个字节 二.内存单元的地址即为指针,存放指针的变量称为指针变量,故:"指针"是指地址,是常量,& ...

  2. CISAW风险管理学习笔记(1)-认证体系

    个人学习总结,CISAW学习笔记之认证体系介绍:

  3. C++学习笔记7[指针]

    C++学习目录链接: C++学习笔记目录链接(持续更新中) 文章目录 一.变量和指针 1.指针的声明 2.指针的赋值 3.关于指针使用的说明 4.指针运算符和取地址运算符 5.指针运算 二.指针和数组 ...

  4. C++学习笔记——智能指针

    c++里不像java等语言设置了垃圾回收的功能,但是c++通过它的王牌指针实现了智能指针这一解决办法. 目录 异常 1.异常 2.异常的使用 3.异常的规则 4.异常安全 智能指针 概念 原理 aut ...

  5. c++学习笔记之指针

    1.声明指针 如果声明多个指针,每个都必须加*,如int *aPtr, *bPtr 变量名最好以Ptr结尾,表明是指针变量 把指针初始化NULL和0是等价的 2.地址运算符和间接运算符 地址运算符&a ...

  6. Boost学习笔记-智能指针

    1.  智能指针 scoped_ptr 只在作用域内生效,离开作用域既释放资源,不能复制和赋值.类似于标准库的auto_ptr,但它相对于auto_ptr的优势在于,他的要求更严格,使用起来更安全.a ...

  7. Rust 学习笔记——智能指针

    https://doc.rust-lang.org/book/ch15-00-smart-pointers.html 智能指针是一种想指针一样的行为且具有其他能力的数据结构(Smart pointer ...

  8. C语言学习笔记--数组指针和指针数组

    C 语言中的数组有自己特定的类型,数组的类型由元素类型和数组大小共同决定.(如 int array[5]类型为 int[5]) 1.定义数组类型 C 语言中通过 typedef 为数组类型重命名:ty ...

  9. go学习笔记-语言指针

    语言指针 定义及使用 变量是一种使用方便的占位符,用于引用计算机内存地址.取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址. 一个指针变量指向了一个值的内存地址.类似于变量和常量, ...

最新文章

  1. 基础矩阵,本质矩阵,单应性矩阵讲解
  2. keras中重要的函数用法及参数详解
  3. python unpack函数_Python numpy.unpackbits函数方法的使用
  4. 转 23种开发模式一点就通
  5. golang基础环境配置
  6. add(1)(2)(3) add(1,2)(3)
  7. Servlet 的三种创建方式
  8. 2DToolkit官方文档中文版打地鼠教程(一):初始设置
  9. SqlServer中char,varchar,nchar,nvarchar的区别
  10. 辨别虚假流量的十二种方法
  11. 在linux下如何显示隐藏文件
  12. Xcode8写代码闪退
  13. AD19-DRC检查
  14. 限流的抖音号怎么养?养号方法是什么?
  15. oracle create数据库,oracle手工创建数据库全纪录
  16. 51单片机c语言led灯闪烁实验报告,实验一LED灯闪烁.doc
  17. 2020 - 2021 年 Web 前端最新导航
  18. libmysqlclient_18 not defined in file libmysqlclient.so.18
  19. python 人脸识别:从入门到精通 (5.4)常用的神经网络层
  20. java sleep的意义_thread.sleep的作用是什么

热门文章

  1. 环境DNA高通量测序问题及解决SOP (Part 1: From sample to data)
  2. QIIME 2教程. 10数据导出ExportingData(2021.2)
  3. 蚂蚁森林合种计划(2020.10.23,7天有效,每周更新)
  4. NAR:UNITE真菌鉴定ITS数据库——处理未分类和并行分类(数据库文章阅读模板)
  5. 给不爱洗手找个理由——皮肤共生菌可以促进伤口愈合
  6. python使用matplotlib可视化、使用matplotlib可视化scipy.misc图像、自定义使用Accent色彩映射、将不同亮度映射到不同的色彩
  7. R语言构建文本分类模型并使用LIME进行模型解释实战:文本数据预处理、构建词袋模型、构建xgboost文本分类模型、基于文本训练数据以及模型构建LIME解释器解释多个测试语料的预测结果并可视化
  8. R语言ggplot2可视化:应用pivot_longer函数将数据从宽格式转换为长格式、为dataframe的每一列绘制密度图和直方图(堆叠)
  9. pandas重置dataframe的索引(reset_index)、如果索引不匹配dataframe操作时候的问题、重置索引(不设置drop=true)远索引生成新的数据列
  10. R语言关系操作符:>、<=、!=、>=、==、