嵌入式学习之路 14(C语言基础学习——指针)

news2025/1/10 20:54:59

一、指针基础

指针的概念

        地址表示内存单元的编号,也被称为指针。指针既是地址,也是一种专门用于处理地址数据的数据类型。
例如,变量a的地址或者十六进制表示的0x1000都可以视作指针。
 

指针变量的定义

语法:基类型 * 指针变量名。
        基类型可以是之前学过的各种数据类型,如整型、浮点型、字符型、结构体类型、函数类型等,它表示指针所指向的内存空间能够存放的数据类型。例如:int *p; 中,p就是一个指向整型数据的指针变量。
        *在定义时表示定义的是指针类型的变量。
        指针变量名需符合标识符命名规则。


指针类型

例如:在int *p;中,int *整体被称为指针类型,表示指向整型数据的指针类型。


指针变量的引用

例如:int a = 10; int *p = &a; ,p指向 a 。
*是指针运算符,为单目运算,运算对象只能是指针(地址)。
*p表示访问 p 所指向的基类型的内存空间,这是一种间接访问。其过程包括:首先拿出 p 中的地址,在内存中定位;然后偏移出 sizeof(基类型) 大小的一块空间;最后将偏移出的这块空间当作一个基类型变量来看。
例如,*p 的运算效果相当于直接访问的变量 a 。
类似地,对于int a; ,a的数据类型是 int ,&a的数据类型是 int* ,对于 float b; ,&b的数据类型是 float* 。


指针变量的初始化

如果指针变量没有初始化,此时的值是随机值(野指针)。
初始化可以让指针变量有明确的指向,例如:int a; int *p = &a; 或者 int *p = NULL(NULL 表示空指针,即 0 号地址)。


赋值

例如:int *p; p = &a;


定义多个指针变量

例如:int *p, *q; 表示定义了两个指针变量。
注意:定义时候的 * 是修饰变量名的,表示定义的是一个指针类型的变量。


为什么需要指针指针

指针可以实现被调函数修改主调函数中的数据。

二、指针作为函数的参数

1、形参是指针类型的变量,用来接收实参(实参是要操作的内存空间的地址)。
2、实参:要修改谁,就把谁的地址传进去,但要保证空间有效。
3、注意:被调函数中一定要有*p的运算(间接访问的操作)。
4、值传递只是实参数据赋值给了形参,而地址(指针传递)传递的是地址,可以实现被调修改主调。

练习:

#include <stdio.h>

// 函数:实现两个数相加,并将结果存储在指针所指的变量中
void ADD(int *a, int b) 
{
    *a = *a + b;  // 将指针 a 所指变量的值与 b 相加,并将结果存储回指针所指的变量
}

// 函数:找出两个数中的最大值和最小值,并通过指针返回
void maxandmin(int a, int b, int *max, int *min) 
{
    *max = a > b? a : b;  // 如果 a 大于 b,将 a 赋值给指针 max 所指的变量,否则将 b 赋值给它
    *min = a < b? a : b;  // 如果 a 小于 b,将 a 赋值给指针 min 所指的变量,否则将 b 赋值给它
}

// 函数:交换两个指针所指变量的值
void swap(int *a, int *b) 
{
    int temp = *a;  // 临时变量 temp 存储指针 a 所指变量的值
    *a = *b;  // 将指针 b 所指变量的值赋给指针 a 所指的变量
    *b = temp;  // 将临时变量 temp 的值赋给指针 b 所指的变量
}

// 主函数
int main() 
{
    int a = 2;  // 定义并初始化变量 a 为 2
    int b = 3;  // 定义并初始化变量 b 为 3

    int max;  // 定义变量用于存储最大值
    int min;  // 定义变量用于存储最小值

    // ADD(&a,b);  // 调用 ADD 函数,将 b 的值加到 a 上
    // printf("sum = %d\n",a);  // 输出相加后的结果

    // maxandmin(a,b,&max,&min);  // 调用 maxandmin 函数找出 a 和 b 的最大值和最小值
    // printf("max = %d, min = %d\n",max,min);

    printf("a = %d b = %d\n",a,b);  // 输出原始的 a 和 b 的值
    swap(&a,&b);  // 调用 swap 函数交换 a 和 b 的值
    printf("a = %d b = %d\n",a,b);  // 输出交换后的 a 和 b 的值

    return 0;
}

三、指针与一维整型数组

1、数组名代表数组首元素的地址,就是数组所在空间的首地址。例如:定义一个指向整型数组的指针变量可以写成 int *p = a; 或者 int *p = &a[0]; ,表示 p 指向了数组 a 。
2、数组名(数组首元素的地址)和 &a[0] 等价。
3、*p 等价于 a[0] 。
4、指针的运算:

&:取地址运算符。
*:解引用运算符。
p + 1:指针的算术运算,其偏移量取决于指针所指向的数据类型的大小。

指针的比较:

>  >=  <  <=  ==  !=

可以比较两个指针的大小或相等关系,但前提是这两个指针指向同一个数组或具有相同的基类型。

 

#include <stdio.h>

// 函数:打印数组元素
void printfArray(int *begin, int *end) 
{
    // 只要起始指针不超过结束指针,就持续执行循环
    while (begin <= end)  
    {
        // 打印起始指针所指向的元素,并将起始指针向后移动一位
        printf("%d ",*begin++);  
    }
    // 换行,使输出更清晰
    printf("\n");  
}

// 函数:找出数组中的最大值
int maxArray(int *a, int len) 
{
    int i;  // 定义循环变量
    // 初始化最大值为数组的第一个元素
    int max = *a;  

    // 遍历数组的每一个元素
    for (i = 0; i < len; i++)  
    {
        // 如果当前最大值小于数组中的某个元素
        if (max < *(a + i))  
        {
            // 更新最大值为该元素
            max = *(a + i);  
        }
    }

    // 返回最大值
    return max;  
}

// 函数:反转数组元素的顺序
void reversedOrder(int *begin, int *end) 
{
    int temp;  // 定义临时变量用于交换元素

    // 只要起始指针小于结束指针,就持续执行循环
    while(begin < end)  
    {
        // 交换起始指针和结束指针所指向的元素
        temp = *begin;  
        *begin = *end;  
        *end = temp;  
        // 起始指针向前移动一位
        begin++;  
        // 结束指针向后移动一位
        end--;  
    }
}

// 函数:选择排序
void choieSort(int *begin, int *end)  
{
    int *p = begin;  // 定义指向起始位置的指针
    int *q = NULL;  // 定义用于遍历的指针

    // 外层循环控制排序的轮数
    for (p = begin; p < end; p++)  
    {
        // 内层循环在每一轮中找出最小元素
        for (q = p + 1; q <= end; q++)  
        {
            // 如果当前元素大于后面的元素
            if (*p > *q)  
            {
                // 交换两个元素
                int t = *p;  
                *p = *q;  
                *q = t;  
            }
        }
    }
}

// 函数:冒泡排序
void bubbleSort(int *begin, int *end) 
{
    int *p = begin;  // 定义指向起始位置的指针
    int *q = NULL;  // 定义用于遍历的指针

    // 外层循环控制排序的轮数
    for (p = end; p > begin; p--)  
    {
        // 内层循环在每一轮中比较相邻元素
        for (q = begin; q < p; q++)  
        {
            // 如果当前元素大于下一个元素
            if (*q > *(q + 1))  
            {
                // 交换两个相邻元素
                int t = *q;  
                *q = *(q + 1);  
                *(q + 1) = t;  
            }
        }
    }
}

// 函数:插入排序
void insertSort(int *begin, int *end) 
{
    int *p = begin;  // 定义指向起始位置的指针
    int *q = NULL;  // 定义用于遍历的指针

    // 从第二个元素开始遍历
    for (p = begin + 1; p <= end; p++)  
    {
        int t = *p;  // 保存当前要插入的元素
        q = p;  // 记录当前位置

        // 寻找插入位置
        while (q > begin && *(q - 1) > t)  
        {
            // 将较大的元素向后移动
            *q = *(q - 1);  
            q--;  // 指针向前移动
        }
        // 插入元素
        *q = t;  
    }
}

// 函数:折半查找
int * binaryFind(int *begin, int *end, int n) 
{
    int *mid = NULL;  // 定义指向中间位置的指针
    int *ret = NULL;  // 定义用于存储查找结果的指针

    // 只要查找范围存在(起始指针小于等于结束指针)
    while (begin <= end)  
    {
        // 计算中间位置
        mid = begin + (end - begin) / 2;  

        // 如果要查找的值小于中间值
        if (n < *mid)  
        {
            // 在左半部分继续查找
            end = mid - 1;  
        }
        // 如果中间值小于要查找的值
        else if (*mid < n)  
        {
            // 在右半部分继续查找
            begin = mid + 1;  
        }
        // 如果找到匹配的值
        else  
        {
            // 记录找到的位置
            ret = mid;  
            break;  // 退出循环
        }
    }

    // 返回查找结果,如果未找到则为 NULL
    return ret;  
}

// 函数:折半查找(递归)
int *binaryFindR(int *begin, int *end, int n) 
{
    int *mid = begin + (end - begin) / 2;  // 计算中间位置
    int *ret = NULL;  // 定义用于存储查找结果的指针

    // 如果起始指针大于结束指针,说明未找到
    if (begin > end)  
    {
        return NULL;  
    }

    // 如果要查找的值小于中间值
    if (n < *mid)  
    {
        // 在左半部分递归查找
        end = mid - 1;  
        ret = binaryFindR(begin, end, n);  
    }
    // 如果中间值小于要查找的值
    else if (*mid < n)  
    {
        // 在右半部分递归查找
        begin = mid + 1;  
        ret = binaryFindR(begin, end, n);  
    }
    // 如果找到匹配的值
    else if (*mid == n)  
    {
        // 记录找到的位置
        ret = mid;  
    }

    // 返回查找结果,如果未找到则为 NULL
    return ret;  
}

// 函数:交换两个指针所指向的值
void swap(int *a, int *b) 
{
    int t = *a;  // 临时存储指针 a 所指向的值
    *a = *b;  // 将指针 b 所指向的值赋给指针 a 所指向的位置
    *b = t;  // 将临时存储的值赋给指针 b 所指向的位置
}

// 函数:快速排序
void quickSort(int *begin, int *end) 
{
    // 记录起始位置和结束位置
    int *p = begin;  
    int *q = end;  

    // 选择起始位置的元素作为基准值
    int *k = begin;  

    // 只要起始指针小于结束指针,就持续执行循环
    while (begin < end)  
    {
        // 从右向左找小于基准值的元素
        while(begin < end && *end >= *k)  
        {
            end--;  
        }

        // 从左向右找大于基准值的元素
        while (begin < end && *begin <= *k)  
        {
            begin++;  
        }

        // 交换找到的两个元素
        swap(begin, end);  
    }

    // 如果起始指针和结束指针相遇
    if (begin == end)  
    {
        // 将基准值与相遇位置的元素交换
        swap(k, begin);  
    }

    // 如果起始位置到结束位置减 1 的范围内还有元素,继续排序
    if (p < end - 1)  
    {
        quickSort(p, end - 1);  
    }

    // 如果起始位置加 1 到结束位置的范围内还有元素,继续排序
    if (begin + 1 < q)  
    {
        quickSort(begin + 1, q);  
    }
}

// 主函数
int main() 
{
    int a[] = {10,2,8,5,4,6,7,3,9,1};  // 定义并初始化整数数组
    int len = sizeof(a)/sizeof(a[0]);  // 计算数组的长度

    /*printf("max = %d\n",maxArray(a,len));

    printfArray(a,a+len-1);		//可以改变打印的起始位置和结束位置

    reversedOrder(a,a+len-1);
    printfArray(a,a+len-1);*/

    //choieSort(a,a+len-1);
    //bubbleSort(a,a+len-1);
    printfArray(a,a+len-1);
    //insertSort(a,a+len-1);
    //printfArray(a,a+len-1);

    /*int n;
    scanf("%d",&n);
    //int *ret = binaryFind(a,a+len-1,n);
    int *ret = binaryFindR(a,a+len-1,n);

    if (ret==NULL)
        printf("no found\n");
    else
        printf("found\n");
    */

    quickSort(a,a+len-1);  // 对数组进行快速排序
    printfArray(a,a+len-1);  // 打印排序后的数组

    return 0;
}

快速排序的思路 

5330fa9e787e422297929ba356da599e.png

 

 

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

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

相关文章

Python面试宝典第28题:合并区间

题目 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为intervals[i] [starti, endi]&#xff0c;且endi大于starti。请合并所有重叠的区间&#xff0c;并返回一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间。 示例 1&#xff1a; 输入&…

Linux 利用 iostat 和 iotop 进行 IO 分析

目录 一、概述二、iostat1、下载2、常用选项3、/proc/diskstats 文件3、一般使用 三、iostop1、下载2、常用选项3、一般使用 一、概述 在Linux 系统上&#xff0c;iostat 和 iotop 这两个 IO 数据工具非常常用。它们都是性能分析领域中不可缺少的工具性软件。 如果 Linux 系统…

关于Redis的集群面试题

问题一&#xff1a;Redis的多数据库机制&#xff0c;了解多少&#xff1f; Redis支持多个数据库&#xff0c;并且每个数据库是隔离的不能共享&#xff0c;单机下的redis可以支持16个数据库&#xff08;db0~db15&#xff09;;若在Redis Cluster集群架构下&#xff0c;则只有一个…

基于STM32F103的FreeRTOS系列(七)·任务创建·列表的使用超详细解析

目录 1. 列表和列表项 1.1 列表和列表项简介 1.1.1 列表 1.1.2 列表项 1.1.3 迷你列表项 1.1.4 列表与列表项关系图 1.2 列表初始化 1.3 列表项的初始化 1.4 列表项的插入函数 1.5 列表项的末尾插入 1.6 列表项的删除 1.7 列表的遍历 1. 列表和列表项…

Open3D 三维重建-Marching Cubes (行进立方体)

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1步骤 2.1.2函数代码 2.2完整代码 三、实现效果 3.1原始点云 3.2重建后点云 Open3D点云算法汇总及实战案例汇总的目录地址&#xff1a; Open3D点云算法与点云深度学习案例汇总&#…

基于Flask框架的豆瓣电影实时数据分析可视化系统【自动爬虫、数据库、Pyecharts】

文章目录 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主项目介绍数据抓取数据存储可视化前后端交互登陆界面注册界面数据更新后展示每文一语 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主 项目介绍 本项目基于Py…

JavaEE: 线程安全问题的解决方案(synchronized)

发生原因 要想解决线程安全问题,那么我们首先得知道线程安全问题为什么会发生. 发生原因: 线程在操作系统中是"随机调度,抢占式执行的"[根本原因].多个线程,同时修改同一个变量修改操作不是"原子"的内存可见性问题指令重排序 解决方案 原因1和2,我们很…

基于YOLOv8的茶叶病变检测系统

基于YOLOv8的茶叶病变检测系统 (价格85) 包含 [Algal Leaf Spot, Brown Blight, Gray Blight, Healthy, Helopeltis, Red Leaf Spot] 6个类 翻译&#xff1a; [藻类叶斑病&#xff0c;褐疫病&#xff0c;灰疫病&#xff0c;健康&#xff0c;茶角盲蝽&#xff0c; 红叶斑…

08.SQL注入-下(超详细!!!)

1、Access注入 1.1 判断是否存在注入漏洞 ?id10 and 11 //不报错 ?id10 and 12 //报错1.2 判断字段数 ?id10 order by 1 ... ?id10 order by 7 //不报错 ?id10 order by 8 //报错 说明有7个字段1.3 猜表名 ?id10 and exists(select * from administrator) …

IP协议解析

我最近开了几个专栏&#xff0c;诚信互三&#xff01; > |||《算法专栏》&#xff1a;&#xff1a;刷题教程来自网站《代码随想录》。||| > |||《C专栏》&#xff1a;&#xff1a;记录我学习C的经历&#xff0c;看完你一定会有收获。||| > |||《Linux专栏》&#xff1…

C语言宏定义的使用

文章目录 &#x1f34a;自我介绍&#x1f34a;宏定义&#x1f34a;宏函数&#x1f34a;嵌入式开发常用do...while(0)&#x1f34a;字符串化运算符 ‘ # ’&#x1f34a;不定参数宏 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以&#xff1a;点赞关注评论收藏&#xf…

SQL报错注入之floor

目录 1.简述 2.关键函数说明 1.rand函数 2.floor&#xff08;rand&#xff08;0&#xff09;*2&#xff09;函数 3.group by 函数 4.count&#xff08;*&#xff09;函数 3.报错分析 4.报错流程 4.1寻找注入点 4.2爆数据库名 4.3爆表名 4.4爆字段名 4.5查询数据 1.…

32、Python之面向对象:对象的表示,再论Python是dict包括语法糖

引言 在前面介绍Python容器的时候&#xff0c;我们曾经用过这种夸张的表述&#xff0c;“Python就是包裹在一堆语法糖中的字典”。虽然夸张&#xff0c;其实更多的是为了突出Python中dict的强大之处。今天这篇文章&#xff0c;打算看下Python中类对象、实例对象的表示及内存管理…

甄选范文“论负载均衡技术在Web系统中的应用”软考高级论文系统架构设计师论文

论文真题 负载均衡技术是提升Web系统性能的重要方法。利用负载均衡技术, 可将负载(工作任务) 进行平衡、分摊到多个操作单元上执行, 从而协同完成工作任务, 达到提升Web系统性能的目的。 请围绕“负载均衡技术在Web系统中的应用”论题, 依次从以下三个方面进行论述。 1.…

自动化测试 — selenium + Java

什么是自动化测试 将人为驱动的测试行为转化为机器执行的过程。 自动化测试包括UI 自动化&#xff0c;接口自动化&#xff0c;单元测试自动化。按照这个金字塔模型来进行自动化测试规划&#xff0c;可以产生最佳的自贡话测试产出投入比&#xff08;ROI &#xff09;&#xff0c…

智能氮气柜如何为存储应用提供稳定和安全的环境?

智能氮气柜在保持内部环境的严格控制下&#xff0c;如何为各类高要求的存储应用提供一个稳定和安全的环境&#xff1f; 智能氮气柜内部安装高精度温湿度传感器&#xff0c;持续监测内部环境状况。通过外部连接的氮气供应源&#xff0c;向柜内注入高纯度氮气&#xff0c;当检测到…

k8s—ingress应用

一、ingress和ingress-controller ingress对象&#xff1a; 指的是k8s中的⼀个api对象/资源对象&#xff0c;⼀般⽤yaml配置。作⽤是定义请求如何转发到service的规则&#xff0c;可以理解为配置模板。 ingress-controller&#xff1a; 具体实现反向代理及负载均衡的程序&…

IO-Link通信笔记(十七)——可任意MCU平台移植的面向对象程序设计的IO-Link从站协议栈与接口代码生成和监控上位机与便携式通信主站

一、可任意MCU平台移植的面向对象程序设计的IO-Link从站协议栈 图形化界面与驱动代码库生成功能&#xff0c;是现如今几大半导体芯片供应商选择向广大开发人员推荐的主流开发方式&#xff0c;例如意法的cube-mx。开发人员可以通过这些软件针对所使用芯片的相关外设资源&#xf…

缺失值处理方法:代数/统计/机器学习算法补全数据(附Python-sklearn代码精美可视化绘图)

注&#xff1a;本期的删除或插补方法主要针对连续数据&#xff0c;时间序列数据的插补在后续关于时间序列的博客中讲明。参考鸢尾花丛书&#xff0c;链接如下&#xff1a; 参考书籍及源代码链接https://github.com/Visualize-ML 博客是选出自己感觉用的到的精炼部分加自己的理…

春秋云境 | 文件上传 | CVE-2022-30887

目录 靶标介绍 开启靶场 上传一句话木马 蚁剑连接 找到 flag 靶标介绍 多语言药房管理系统 (MPMS) 是用 PHP 和 MySQL 开发的, 该软件的主要目的是在药房和客户之间提供一套接口&#xff0c;客户是该软件的主要用户。该软件有助于为药房业务创建一个综合数据库&#xff0…