当前位置: 首页 > news >正文

C语言指针剖析(初阶) 最详细!

  1. 什么是指针?

  1. 指针和指针类型

  1. 野指针

  1. 指针运算

  1. 指针和数组

  1. 二级指针

  1. 指针数组

  1. 什么是指针?

  1. 指针是内存中一个最小单元的编号,也就是地址。

1.把内存划分为一个个的内存单元,一个内存单元的大小是一个字节。
2.每个字节都给定唯一的编号,这个编号称之为地址。地址在C语言中也叫指针
编号==地址==指针

2.我们说的指针,通常指的是指针变量,是用来存放内存地址的变量。

int main()
{int a = 10;int* pa = &a;//a的地址放在指针变量pa中,pa的类型是int *return 0;
}

指针变量:使用&(取地址操作符)取出变量的内存起始地址,把地址存放到一个变量中,这个变量就是指针变量。

int main()
{int a = 10;int* pa = &a;pa=10return 0;
}

💭注意:

  1. a是整型,占用4个字节的内存空间,每个字节都有对应的地址。

  1. &a 得到的是a的地址,其实得到的是a所占内存中4个字节中第一个字节地址

  1. pa=10 其实存放的是地址

4.一个指针变量在32位的平台上是4个字节,在64位的平台上是8个字节

2.指针和指针类型

所有指针类型在x86环境下全是4个字节,在x64环境下是8个字节。

指针类型的意义

1.指针类型决定了在解引用指针的时候能访问几个字节

对于整型指针,解引用时访问4个字节

对于字符型指针,解引用时访问1个字节

2.指针进行加减整数时,int型加4个字节,char型加1个字节

int main()
{int a = 10;int* pa = &a;char* pc = &a;printf("%p\n", pa);printf("%p\n", pa + 1);printf("%p\n", pc);printf("%p\n", pc + 1);return 0;
}
int main()
{int arr[10] = { 0 };int* p = &arr[0];int i = 0;for (i = 0; i < 10; i++){*p = i + 1;p++;}for (i = 0; i < 10; i++){printf("%d ", arr[i]);//1 2 3 4 5 6 7 8 9 10}return 0;
}

3. 指针解引用:指针的类型决定了,对指针进行解引用有多大的权限。char* 只能访问一个字节,int* 访问4个字节

3.野指针

野指针就是指针指向的位置是不可知的(随机的,不正确的,没有明确限制的)。

野指针成因

  1. 指针未初始化

  1. 指针越界访问

  1. 指针指向的空间释放

int* test()
{int a = 10;//a的空间被释放(局部变量)return &a;
}
int main()
{int* p = test();*p = 100;
}

如何规避野指针?

  1. 指针初始化

int main()
{int a = 10;int* p = &a;return 0;
}
  1. 小心指针越界

  1. 指针指向空间释放时,及时置NULL,一个指针不知道指向哪里时,暂时可以置为空指针(NULL)

  1. 避免返回局部变量的地址

int* test()
{int a = 10;//a的空间被释放(局部变量)return &a;
}
int main()
{int* p = test();*p = 100;
}
  1. 指针使用之前检查有效性(使用指针之前判断指针是否为空)

  1. 指针运算

  1. 指针+-整数

int my_strlen(char* str)
{int count = 0;while (*str != '\0'){count++;str++;//指针+整数}return count;
}
int main()
{char arr[10] = "abcdef";int len = my_strlen(arr);printf("%d\n", len);return 0;
}
char* str是字符型指针,所以str++是跳过一个字符
  1. 指针-指针(地址-地址)

💭注意:

1.两个指针指向同一块内存空间(指针的类型是一致的)
2.指针-指针得到的是指针和指针之间的元素个数
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int n = &arr[9] - &arr[0];//&arr[0]-&arr[9]=-9printf("%d", n);//9return 0;
}
int my_strlen(char* str)
{char* start = str;while (*str != '\0'){str++;}return str - start;
}
int main()
{char arr[10] = "abcdef";int len = my_strlen(arr);printf("%d\n", len);return 0;
}
  1. 指针的关系运算

标准规定
1.允许指向数组元素的指针与指向数组最后一个元素后面的那么内存位置的指针进行比较
2.不允许与指向第一个元素之前的那个内存位置的指针进行比较
//1.
for (vp = &values[N_VALUES]; vp > &values[0];)
{*--vp = 0;
}
//2.
for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
{*vp = 0;
}

5.指针和数组

指针就是指针,数组就是数组
指针的大小:4/8个字节,指针是存档地址的,地址的存放需要多大空间,指针变量的大小就是多少。
数组的大小:取决于数组的元素个数和每个元素的类型。
int main()
{int arr[10] = { 0 };int* p = arr;//&arr[0]int i = 0;//存放for (i = 0; i < 10; i++){*p = i + 1;p++;}//打印p = arr;for (i = 0; i < 10; i++){*(p + i) = i + 1;printf("%d ", *(p + i));}return 0;
}

6.二级指针

int main()
{int a = 10;//一级指针int* pa = &a;//pa是指针变量,用来存放地址,向内存申请空间4/8//二级指针int** ppa = &pa;//指向pa空间的指针变量ppareturn 0;
}
int main()
{int a = 10;//一级指针int* pa = &a;//pa是指针变量,用来存放地址,向内存申请空间4/8//二级指针int** ppa = &pa;//指向pa空间的指针变量ppaprintf("%d", **ppa);//10return 0;
}

7.指针数组

int main()
{int a = 10;int b = 20;int c = 30;//存放指针的数组int* arr[] = { &a,&b,&c };int i = 0;for (i = 0; i < 3; i++){printf("%d ", *(arr[i]));}return 0;
}
指针数组是一个数组,数组中每个元素都是指针类型

拓展

int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int i = 0;int* p = arr;//arr[i]-->*(arr+i)-->*(i+arr)-->i[arr]//*(arr+i)-->*(p+i)-->arr[i]for (i = 0; i < 10; i++){printf("%p=%p\n", &arr[i], p + i);}return 0;
}
这里arr[i]和i[arr]相等,[ ]就相当于一个操作符
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int i = 0;for (i = 0; i < 10; i++){printf("%d ", i[arr]);//i[arr]--*(i+arr)//arr[i]--*(arr+i)}return 0;
}
int main()
{int arr[3][5];//arr[i[[j]//(*(arr + i))[j]//*(*(arr + i) + j)return 0;
}

感谢阅读,欢迎大家批评指正!

http://www.lryc.cn/news/8037.html

相关文章:

  • AcWing语法基础课笔记 第三章 C++中的循环结构
  • A simple freeD tracking protocol implementation written in golang
  • 简约精美电商小程序【源码好优多】
  • 全网详解 .npmrc 配置文件:比如.npmrc的优先级、命令行,如何配置.npmrc以及npm常用命令等
  • 从0开始学python -31
  • Jenkins的使用教程
  • 1.Maven的坐标和依赖
  • Jenkins 笔记
  • Python和Java语言,哪个更适合做自动化测试?
  • 互联网的路由选择协议
  • 接口幂等性处理
  • 数字孪生智慧机场:透视数字化时代下的航空运营
  • SpringBoot 文件上传后查看404的问题和解决404后需要访问两次才能查看的问题
  • 定时任务使用总结
  • Jira和Confluence Server版终止支持倒计时365天,企业应对策略汇总
  • GEE学习笔记九十一:栅格影像叠置分析
  • linux系统编程入门
  • JS代码安全防护常见的方式
  • PHP(13)HTTP协议
  • 基于支持向量机 (SVM) 用php实现预测气温
  • MySQL(五)
  • Linux常用命令2
  • 『C/C++养成计划』Visual Studio Code编辑器配置(外观通用型扩展Minmal)
  • 设计模式(适配器模式)
  • 在基于全志D1s的芒果派麻雀上运行国产开源rt-smart系统
  • 【代码随想录训练营】【Day15】第六章|二叉树|层序遍历|226.翻转二叉树|101.对称二叉树
  • 基于圆展开自适应三边测量算法的室内定位
  • 使用中断子系统实现对LED灯的控制
  • 《爆肝整理》保姆级系列教程python接口自动化(十五)--参数关联接口(详解)
  • 【JDK8】MyBatis源码导入Idea