C语言之指针知识点总结

C语言之指针知识点总结

文章目录

  • C语言之指针知识点总结
    • 1. 初识指针
      • 1.1 取地址操作符 &
      • 1.2 指针变量
      • 1.3 解引用操作符 *
      • 1.4 指针变量
        • 1.4.1 大小
        • 1.4.2 指针类型的意义
      • 1.5 void*指针
      • 1.6 const关键字
        • 1.61 const修饰变量
        • 1.6.2 const修饰指针变量
      • 1.7 指针的运算
      • 1.7.1 指针+-整数
        • 1.7.2 指针 - 指针
        • 1.7.3 指针的关系运算
      • 1.8 野指针
        • 1.8.1 规避野指针
      • 1.9 指针的传值和传址
    • 2. 深入指针
      • 2.1 数组名的理解
      • 2.2 ⼀维数组传参的本质
      • 2.2 二级指针
      • 2.3 指针数组
      • 2.4 数组指针变量
      • 2.5 二维数组传参的本质
      • 2.6 函数指针变量
        • 2.6.1 函数指针变量的使用
        • 2.6.2 函数指针数组

1. 初识指针

1.1 取地址操作符 &

#include <stdio.h>int main()
{int a = 10;&a;return 0;
}

取地址操作符 & 用于取出变量的地址在这里插入代码片

1.2 指针变量

取出的地址要存放指针变量中

#include <stdio.h>int main()
{int a = 10;int* p = &a;return 0;
}

* 说明 p 是个指针变量,前面的int说明 指向的是一个int类型的对象

1.3 解引用操作符 *

解引用操作符是通过指针来找到指针指向的对象

#include <stdio.h>int main()
{int a = 10;int* p = &a;*p = 20;return 0;
}

*p 的意思就是通过pa中存放的地址,找到指向的空间,
p其实就是a变量了;所以p = 0,这个操作符是把a改成了20

1.4 指针变量

1.4.1 大小

指针变量的大小取决于系统,如果是32位平台下地址是32个bit位(即4个字节)
64位平台下地址是64个bit位(即8个字节)

1.4.2 指针类型的意义

一:指针的类型决定了,对指针解引⽤的时候有多⼤的权限(⼀次能操作⼏个字节)
二:指针的类型决定了指针向前或者向后⾛⼀步有多⼤(距离)

一:

#include <stdio.h>
int main()
{int m = 0x11223344;int n = 0x11223344;int* pi = &m;char* pc = &n;*pi = 0;*pc = 0;return 0;
}

上述代码中,pi会将m的4个字节全都改成0,而pc只会改n的1个字节改成0,由于指针类型不同,解引用时的权限不同

二:

#include <stdio.h>
int main()
{int n = 10;char *pc = (char*)&n;int *pi = &n;printf("%p\n", &n);printf("%p\n", pc);printf("%p\n", pc+1);printf("%p\n", pi);printf("%p\n", pi+1);return 0;
}

在这里插入图片描述
char* 的指针解引⽤就只能访问⼀个字节,⽽ int* 的指针的解引⽤就能访问四个字节

1.5 void*指针

void可以用来存放任意类型的地址,可以理解为无类型指针(或叫泛指型),但是void类型的指针不用解引用指针的±**

1.6 const关键字

1.61 const修饰变量
#include <stdio.h>int main()
{const n = 20;n = 10;//err 不可修改return 0;
}

当用const修饰变量时,被修饰的变量就无法更改它的值

1.6.2 const修饰指针变量
#include <stdio.h>int main()
{int a = 10;int b = 20;const int* x = &a; //const放在*左边 与下面一种写法一致int const* y = &a; //const放在*左边 int* const z = &a; //const放在*右边const int* const m = &a;//const放在*两边x = &b; *x = 10; /errz = &b;  /err*z = 20;m = &b;  /err*m = 20; /errreturn 0;
}

结论:
• const如果放在的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。但是指针变量本⾝的内容可变。
• const如果放在
的右边,修饰的是指针变量本⾝,保证了指针变量的内容不能修改,但是指针指向的内容,可以通过指针改变

1.7 指针的运算

1.7.1 指针±整数

由于一维数组在内存中是连续存放的,那么就可以通过指针±整数,也就是指针偏移来遍历数组

代码一:

#include <stdio.h>
//指针+- 整数
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int* p = &arr[0];int i = 0;int sz = sizeof(arr) / sizeof(arr[0]); //计算数组中的元素个数for (i = 0; i < sz; i++){printf("%d ", *(p + i));//p+i 这⾥就是指针+整数}return 0;
}

代码二:

#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);for (i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}

代码一中的*(p + i) 就是 *(arr + i )
arr[ i ] 编译器会处理成 *(arr + i )
所以通过这两种方式都可以实现数组元素的打印

1.7.2 指针 - 指针
//指针-指针
#include <stdio.h>
int my_strlen(char* s)
{char* p = s;while (*p != '\0')p++;return p - s;
}
int main()
{printf("%d\n", my_strlen("abc"));return 0;
}

通过指针 - 指针的方式来模拟实现strlen
当*p中的值不为’\0‘时,如果指针加整数的方式,来找到’\0’的位置,然后通过高地址 - 低地址得出字符串的长度

指针 - 指针的绝对值是计算两个地址之间的元素个数

1.7.3 指针的关系运算
//指针的关系运算
#include <stdio.h>
int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9,10};int *p = &arr[0];int i = 0;int sz = sizeof(arr)/sizeof(arr[0]); //计算数组中的元素个数while(p<arr+sz) //指针的⼤⼩⽐较{printf("%d ", *p);p++;}return 0;
}

p中存放的是数组中的首元素地址,
arr+sz 首元素地址加上数组元素个数,得到数组结尾的地址
当p的地址小于数组结尾的地址,打印*p
然后++找到下一个元素
就可以实现数组元素的打印

1.8 野指针

概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

野指针的成因:

  1. 指针未初始化
  2. 指针越界访问
  3. 指针指向的空间释放

代码一:

#include <stdio.h>
int main()
{ int *p;//局部变量指针未初始化,默认为随机值*p = 20;return 0;
}

指针未初始化,不知道指向哪个空间,p是野指针

代码二:

#include <stdio.h>
int main()
{int arr[10] = {0};int *p = &arr[0];int i = 0;for(i=0; i<=11; i++){//当指针指向的范围超出数组arr的范围时,p就是野指针*(p++) = i;}return 0;
}

数组中只有10个元素,却循环了12次,指针访问越界了,p是野指针

代码三:

#include <stdio.h>
int* test()
{int n = 100;return &n;
}
int main()
{int*p = test();printf("%d\n", *p);return 0;
}

当进入test函数时,系统在内存中创建了一个空间用来存放n的值,当出test函数时,n的空间就被销毁了,所以p就指向了一个已经销毁的空间,p是野指针

1.8.1 规避野指针

1.初始化指针的时候,就给指针一个初始值,如果不知道指针要指向哪个空间,将指针置为NULL

#include <stdio.h>
int main()
{int num = 10;int*p1 = &num;int*p2 = NULL;return 0;
}

2.小心指针越界
内存有多大的空间,就让指针访问多大的空间,不能超出范围

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

1.9 指针的传值和传址

代码一:

#include <stdio.h>
void Swap(int x, int y)
{int tmp = x;x = y;y = tmp;
}
int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);printf("交换前:a=%d b=%d\n", a, b);Swap1(a, b);printf("交换后:a=%d b=%d\n", a, b);return 0;
}

代码二:

#include <stdio.h>
void Swap(int* x, int* y)
{int tmp = *x;*x = *y;*y = tmp;
}
int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);printf("交换前:a=%d b=%d\n", a, b);Swap1(&a, &b);printf("交换后:a=%d b=%d\n", a, b);return 0;
}

代码一:
无法交换两个变量的值,在传值调用中,改变形参的值无法改变形参的值
代码二:
传入的是两个变量的地址,在函数中改变形参就是改变实参,所以实现了两个变量的交换

2. 深入指针

2.1 数组名的理解

数组名就是数组首元素的地址
有两个情况例外:

sizeof(数组名) 计算的是整个数组的大小
&数组名 取出的是数组的地址,而非首元素的地址

2.2 ⼀维数组传参的本质

#include <stdio.h>
void test(int arr[])
{int sz2 = sizeof(arr)/sizeof(arr[0]);printf("sz2 = %d\n", sz2);
}
int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9,10};int sz1 = sizeof(arr)/sizeof(arr[0]);printf("sz1 = %d\n", sz1);test(arr);return 0;
}

代码运行结果
sz1 = 10
sz2 = 1
一维数组传参传的是首元素的地址,所以无法通过函数来计算一维数组中的元素个数

#include <stdio.h>
void test(int* arr)
{int sz2 = sizeof(arr)/sizeof(arr[0]);printf("sz2 = %d\n", sz2);
}
int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9,10};int sz1 = sizeof(arr)/sizeof(arr[0]);printf("sz1 = %d\n", sz1);test(arr);return 0;
}

结论:⼀维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式。

2.2 二级指针

指针变量也是变量,是变量就有地址,所以可以使用二级指针来存放指针变量的大小,同时也有三级指针,四级指针(三级指针之后就不常见了)

int main()
{int num = 10;int* p = &num;int** pp = &p;return 0;
}

在这里插入图片描述

2.3 指针数组

指针数组是存放指针的数组

int* p[4];

p是个指针数组,指向4个int*类型的元素

2.4 数组指针变量

数组指针变量是用来存放数组的地址

int (*p)[5] = { 0 };

p先和*结合,说明p是⼀个指针变量变量,然后指着指向的是⼀个⼤⼩为10个整型的数组。所以p是⼀个指针,指向⼀个数组,叫 数组指针

[ ]的优先级要⾼于号的,所以必须加上()来保证p先和结合

2.5 二维数组传参的本质

#include <stdio.h>void test(int a[3][5], int r, int c)
{
int i = 0;
int j = 0;for (i = 0; i < r; i++){for (j = 0; j < c; j++){printf("%d ", a[i][j]);}printf("\n");}
}
int main()
{
int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7} };
test(arr, 3, 5);
return 0;
}

与一维数组不同的是,⼆维数组传参本质上也是传递了地址,传递的是第⼀
⾏这个⼀维数组的地址
与一维数组相同,这⾥实参是⼆维数组,形参也写成⼆维数组的形式,也可以写成指针的形式

总结:
一维数组的传参,传的是首元素的地址
二维数组的传参,传的是首元素的地址,不过二维数组的首元素是数组中第一行的元素
一维数组和二维数组的形参部分可以写成数组形式,也可以写成指针的形式

2.6 函数指针变量

函数也是有地址的,可以使用函数指针变量来存放函数的地址
与数组相同的是,函数名是函数的地址

int (*p)(int x,int y);
int (*p)(int, int);//x 和 y可以省略

其中int是函数的返回类型,p是函数指针变量名称,int int是p指向的函数的形参部分
去掉函数指针变量的名字,就是函数指针变量的类型
int (*)(int, int)

2.6.1 函数指针变量的使用
#include <stdio.h>
int Add(int x, int y)
{return x + y;
}
int main()
{int(*pf3)(int, int) = Add;printf("%d\n", (*pf3)(2, 3));printf("%d\n", pf3(3, 5));return 0;
}

通过函数指针变量来调用函数

2.6.2 函数指针数组

函数指针数组和指针数组一样,但是函数指针数组是用来存放函数指针变量的

int (*p[5])(int x, int y);
int (*p[5])(int, int);

p指针变量先与[ ] 结合,是数组,数组中 存放的是int (*)(int int)类型的函数指针

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/171168.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pyhon数据分析A股股票策略实际买卖总结(每月末更新数据)

简介 本篇文章主要记录python数据分析a股股票选股后实际买卖的记录。 选股策略 低位寻股&#xff0c;筛选出低位股价股票已经做过调整的股票&#xff0c;做短线交易&#xff08;不超过7天&#xff09;&#xff0c;不贪&#xff0c;小赚即走。分三个时段&#xff0c;开盘三十…

SAS9.2软件“OLE:对象的类没有在注册数据库中注册“问题的解决. 2023-11-25

操作系统测试平台: Win7 sp1 32bit (6.1.7601.26321 (Win7 RTM)) ; Win 11 64bit(具体版本不详) 其它win平台理论上也可以,可自行测试 1.安装依赖库(必要步骤) 下载地址: Microsoft Visual C 2005 Redistributable 下载 Microsoft Visual C 2008 Redistributable 官方vc库总…

buuctf web [极客大挑战 2019]PHP

提示有备份,dirsearch扫描网站备份 GitHub - maurosoria/dirsearch: Web path scanner下载.zip格式文件 解压到python目录下 在上图位置cmd打开窗口 输入python setup.py install安装dirsearch 安装好后输入命令使用dirsearch python dirsearch.py -u http://44296191-973d-…

第一百八十回 介绍两种阴影效果

文章目录 1. 概念介绍2. 实现方法3. 代码与效果3.1 示例代码3.2 运行效果 4. 内容总结 我们在上一章回中介绍了"自定义SlideImageSwitch组件"相关的内容&#xff0c;本章回中将介绍两种阴影效果.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在…

【深入剖析K8s】容器技术基础(一):从进程开始说起

容器其实是一种特殊的进程而已。 可执行镜像 为了能够让这些代码正常运行’我们往往还要给它提供数据’比如我们这个加法程序所需要的输人文件这些数据加上代码本身的二进制文件放在磁盘上’就是我们平常所说的一个程序,也叫代码的可执行镜像&#xff08;executablejmage&…

用xlwings新建一个excel并同时生成多个sheet

新建一个excel并同时生成多个sheet&#xff0c;要实现如下效果&#xff1a; 一般要使用数据透视表来快速实现。 今天记录用xlwings新建一个excel并同时生成多个sheet。 import xlwings as xw # 打开excel,参数visible表示处理过程是否可视,add_book表示是否打开新的Excel程序…

CSDN助手:一键下载CSDN博客:高效保存,随时阅读

文章目录 &#x1f4d6; 介绍 &#x1f4d6;&#x1f3e1; 环境 &#x1f3e1;&#x1f4d2; 使用方法 &#x1f4d2;⚓️ 相关链接 ⚓️ &#x1f4d6; 介绍 &#x1f4d6; 这是我自己无聊的时候写的一个应用&#xff0c;以前UI有点丑&#xff0c;这次重写了一下UI 功能如下 …

vue+elementui如何实现在表格中点击按钮预览图片?

效果图如上&#xff1a; 使用el-image-viewer 重点 &#xff1a; 引入 import ElImageViewer from "element-ui/packages/image/src/image-viewer"; <template><div class"preview-table"><el-table border :data"tableData" …

使用VC++设计程序:实现常见的三种图像插值算法:最近邻插值,双线性插值,立方卷积插值

图像放大的三种插值算法 获取源工程可访问gitee可在此工程的基础上进行学习。 该工程的其他文章&#xff1a; 01- 一元熵值、二维熵值 02- 图像平移变换&#xff0c;图像缩放、图像裁剪、图像对角线镜像以及图像的旋转 03-邻域平均平滑算法、中值滤波算法、K近邻均值滤波器 04-…

电子学会C/C++编程等级考试2022年09月(二级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:统计误差范围内的数 统计一个整数序列中与指定数字m误差范围小于等于X的数的个数。 时间限制:5000 内存限制:65536输入 输入包含三行: 第一行为N,表示整数序列的长度(N <= 100); 第二行为N个整数,整数之间以一个空格分…

Deepin使用记录-deepin系统开启SSH服务

1、检查安装的deepin系统是否已经开启SSH功能。 $ ps -e | grep ssh $ ps -e | grep ssh 查看是否启动ssh 2、安装openssh-server服务 sudo apt-get install openssh-server 如果出现以上提示&#xff0c;就表示你已经安装了ssh服务&#xff0c;只是还没有启动。 3、安装完…

快速幂算法详解(C++实现)

文章目录 1. 什么是快速幂2. 暴力求解代码实现缺陷分析 3. 优化一&#xff1a;取模运算的性质4. 优化二&#xff1a;快速幂算法的核心思想5. 终极优化&#xff1a;位运算优化6. 源码 这篇文章我们来一起学习一个算法——快速幂算法。 1. 什么是快速幂 顾名思义&#xff0c;快速…

leetCode 1080.根到叶路径上的不足节点 + 递归

给你二叉树的根节点 root 和一个整数 limit &#xff0c;请你同时删除树中所有 不足节点 &#xff0c;并返回最终二叉树的根节点。假如通过节点 node 的每种可能的 “根-叶” 路径上值的总和全都小于给定的 limit&#xff0c;则该节点被称之为 不足节点 &#xff0c;需要被删除…

C语言-内存函数详解

文章目录 1. memcpy使用和模拟实现2. memmove使用和模拟实现3. memset函数的使用4. memcmp函数的使用 1. memcpy使用和模拟实现 返回类型和参数&#xff1a; void * memcpy ( void * destination, const void * source, size_t num );1.函数memcpy从source的位置开始向后复制…

R语言实现Lasso回归

一、Lasso回归 Lasso 回归&#xff08;Least Absolute Shrinkage and Selection Operator Regression&#xff09;是一种用于线性回归和特征选择的统计方法。它在回归问题中加入了L1正则化项&#xff0c;有助于解决多重共线性&#xff08;多个特征高度相关&#xff09;和特征选…

设备树是什么?

设备树&#xff1a; 设备树DTS(Device Tree Source) 描述设备信息的独立的文件。 为什么要引入设备树&#xff1f; 随着芯片的发展&#xff0c;Linux内核中就包含着越来越多这些描述设备的代码&#xff0c;导致Linux内核代码会很臃肿。因此引入了设备树文件&#xff0c;从…

基于 GPS 定位信息的 Pure-Pursuit 轨迹跟踪实车测试(1)

基于 GPS 定位信息的 Pure-Pursuit 轨迹跟踪实车测试&#xff08;1&#xff09; 进行了多组实验&#xff0c;包括顺逆时针转向&#xff0c;直线圆弧轨迹行驶&#xff0c;以及Pure-Pursuit 轨迹跟踪测试 代码修改 需要修改的代码并不多&#xff0c;主要对 gps_sensor 功能包和…

Java中的泛型是什么?如何使用泛型类和泛型方法?

Java 中的泛型是一种编程机制&#xff0c;允许你编写可以与多种数据类型一起工作的代码&#xff0c;同时提供编译时类型检查以确保类型的安全性。泛型的主要目的是提高代码的可重用性、类型安全性和程序的整体性能。 泛型类&#xff08;Generic Class&#xff09;: 在泛型类中…

【教3妹学编程-算法题】统计子串中的唯一字符

3妹&#xff1a;“太阳当空照&#xff0c;花儿对我笑&#xff0c;小鸟说早早早&#xff0c;你为什么背上炸药包” 2哥 :3妹&#xff0c;什么事呀这么开发。 3妹&#xff1a;2哥你看今天的天气多好啊&#xff0c;阳光明媚、万里无云、秋高气爽&#xff0c;适合秋游。 2哥&#x…

关于python中的nonlocal关键字

如果在函数的子函数中需要调用外部变量&#xff0c;一般会看见一个nonlocal声明&#xff0c;类似下面这种&#xff1a; def outer_function():x 10def inner_function():nonlocal xx 1print(x)inner_function()outer_function()在这个例子中&#xff0c;inner_function 引用…