C指针的简介与应用

news/2024/4/30 3:26:52/文章来源:https://blog.csdn.net/m0_53316604/article/details/130035312

C指针

感谢b站up主江科大自化协的讲解:https://www.bilibili.com/video/BV1Mb4y1X7dz/?spm_id_from=333.999.0.0
该学习笔记也是基于up课程做的笔记,我的个人能力及理解的局限,不足之处还望大佬指正~

9.1 指针简介

指针(Pointer)是C语言的一个重要知识点,其使用灵活、功能强大,是C语言的灵魂
指针与底层硬件联系紧密,使用指针可操作数据的地址,实现数据的间接访问

计算机存储机制

int a = 0x12345678;
short b = 0x5A6B;
char c[ ] = {0x33, 0x34, 0x35};

在这里插入图片描述

注意:

小端分配(Little Endian)是一种数据存储方式,它将多字节数据类型的最低有效字节存储在内存的最低地址处,而最高有效字节存储在最高地址处。这种存储方式的名称源于计算机处理信息的方式与书写语言的差异。在西方书写中,我们习惯从左到右进行书写,而在计算机内部处理数据时,数据通常是从右到左进行处理的。因此,在小端分配中,数据的低位部分在存储器中的地址是比高位部分的地址更小的。

例如,对于一个 32 位整数变量,其值为 0x12345678,该变量在小端分配存储方式下的存储方式如下:

地址0x40000x40010x40020x4003
数据内容0x780x560x340x12

可以看到,在小端分配中,该变量的最低有效字节 0x78 存储在内存地址 0x4000 处,而最高有效字节 0x12 则存储在地址 0x4003 处。

定义指针

指针即指针变量,用于存放其他数据单元(变量/数组/结构体/函数等)的首地址。若指针存放了某个数据单元的首地址,则这个指针指向了这个数据单元,若指针存放的值是0,则这个指针为空指针

定义一个指针变量:

在这里插入图片描述

解释:

这里的 x 表示指针类型的大小,通常用于指示指针所占用的内存空间大小。
在一个 16 位系统中,指针通常占用 2 个字节的内存空间,即 x = 2。
在一个 32 位系统中,指针通常占用 4 个字节的内存空间,即 x = 4。
在一个 64 位系统中,指针通常占用 8 个字节的内存空间,即 x = 8。
需要注意的是,这里的指针类型的大小与数据类型的大小不一定相同。例如,在一个 32 位系统中,int 类型通常占用 4 个字节的内存空间,但指针类型也是 4 个字节。这是因为不同的数据类型在内存中的存储方式和占用的内存空间大小不同,而指针类型所占用的内存空间大小通常是与系统位数相关的固定值。

例子:

#include <stdio.h>int main(void)
{int a;int *p;
//    char a;
//    char *p;printf("%d\n",sizeof(a));   //int 4, char 1printf("%d\n",sizeof(p));	//int 8, char 8return 0;
}

指针的操作

若已定义:int a;		//定义一个int型的数据int *p;		//定义一个指向int型数据的指针

则对指针p有如下操作方式:

操作方式举例解释
取地址p=&a;将数据a的首地址赋值给p
取内容*p;取出指针指向的数据单元
p++;使指针向下移动1个数据宽度
p=p+5;使指针向下移动5个数据宽度
p–;使指针向上移动1个数据宽度
p=p-5;使指针向上移动5个数据宽度

例子:(取地址和取内容)

#include <stdio.h>int main(void)
{char a = 0x66;char *p;p = &a;
//    char *p = &a;printf("%x\n",a);   //66printf("%x\n",p);	//62fe47printf("%x\n",*p);	//66return 0;
}

例子:(使指针向下移动1个数据宽度)

#include <stdio.h>int main(void)
{int a = 0x66;int *p;p = &a;printf("%x\n",a);   //66printf("%x\n",p);	//62fe44printf("%x\n",*p);	//66p++;printf("%x\n",p);	//62fe48(加了一个数据宽度,int4字节)return 0;
}

注意:

通常用于数组,单独变量没有意义。

2.数组与指针

数组是一些相同数据类型的变量组成的集合,其数组名即为指向该数据类型的指针。数组的定义等效于申请内存、定义指针和初始化。
例如: 	char c[ ] = {0x33, 0x34, 0x35};
等效于:	申请内存定义 char *c = 0x4000;初始化数组数据利用下标引用数组数据也等效于指针取内容。
例如:	c[0];	等效于:	*c;c[1];	等效于:	*(c+1);c[2];	等效于:	*(c+2);

例子:

#include <stdio.h>
#include <stdlib.h>int main(void)
{
//    char a[] = {0x33, 0x34, 0x35};int *a;a = malloc(3*4);*a = 0x33;*(a+1) = 0x34;*(a+2) = 0x35;//   char *p;
//    p = a;printf("a[0]=%x\n",a[0]);   //33printf("a[1]=%x\n",a[1]);	//34printf("a[2]=%x\n",a[2]);	//35printf("*a=%x\n",*a);  		    //33printf("*(a+1)=%x\n",*(a+1));	//34printf("*(a+2)=%x\n",*(a+2));	//35return 0;
}

3.注意事项

在对指针取内容之前,一定要确保指针指在了合法的位置,否则将会导致程序出现不可预知的错误
同级指针之间才能相互赋值,跨级赋值将会导致编译器报错或警告

在这里插入图片描述

二级指针是指一个指向指针的指针,也可以说是一个指针的指针。它可以用于实现多级数据结构,例如二维数组、链表等。在 C 语言中,二级指针的定义形式如下:

int **pp; // 定义一个指向 int 类型指针的指针

其中,int * 表示指向 int 类型的指针,int ** 表示指向指针的指针,即二级指针。

函数指针是指向函数的指针,它可以用于回调函数、动态绑定等场景。在 C 语言中,函数指针的定义形式如下:

int (*p)(int, int); // 定义一个指向返回类型为 int,参数为两个 int 类型的函数指针

其中,int (*) 表示函数指针类型,p 是函数指针变量名,(int, int) 表示函数指针所指向函数的参数类型。在使用函数指针时,需要注意使用函数指针绑定函数时要保证函数的返回类型、参数类型和个数与函数指针类型一致。

例如,下面的代码定义了一个函数指针变量 p,并将其绑定到了名为 add 的函数上:

int add(int x, int y) {return x + y;
}int main() {int (*p)(int, int) = add;printf("%d\n", p(1, 2)); // 输出 3return 0;
}

在这段代码中,p 是一个函数指针变量,它被初始化为指向 add 函数。在调用函数指针时,可以直接使用 p 变量,并传递参数。

9.2 指针的应用

传递参数1)使用指针传递大容量的参数,主函数和子函数使用的是同一套数据,避免了参数传递过程中的数据复制,提高了运行		效率,减少了内存占用2)使用指针传递输出参数,利用主函数和子函数使用同一套数据的特性,实现数据的返回,可实现多返回值函数的设计
传递返回值1)将模块内的公有部分返回,让主函数持有模块的“句柄”,便于程序对指定对象的操作

值传递:(虽然安全,但是耗内存)

#include <stdio.h>void fun(int param)
{printf("%x\n",param);
}int main(void)
{int a = 0x66;fun(a);return 0;
}

指针传递:(指针传递大容量的参数)

#include <stdio.h>int FindMax(const int *array,int Count)  //用const,只读
{int i;int max = array[0];for(i=1;i<Count;i++){if(array[i]>max){max = array[i];}}return max;
}int main(void)
{int a[] = {1,2,3,5,4,3};int Max;Max = FindMax(a,6);printf("Max=%d\n",Max);return 0;
}

指针传递:(指针传递输出参数,可实现多返回值函数的设计)

#include <stdio.h>void FindMaxAndCount(int *max,int *count,const int *array,int length)  //用const,只读
{int i;*max = array[0];*count = 1;for(i=1;i<length;i++){if(array[i]>*max){*max = array[i];*count = 1;}else if(array[i] == *max){(*count)++;}}}int main(void)
{int a[] = {1,2,5,5,4,3};int Max;int Count;FindMaxAndCount(&Max,&Count,a,6);printf("Max=%d\n",Max);		//5printf("Count=%d\n",Count);	//2return 0;
}

传递返回值:(将模块内的公有部分返回,让主函数持有模块的“句柄”,便于程序对指定对象的操作)

#include <stdio.h>/****************/
int Time[]={23,59,55};
int *GetTime(void)
{return Time;
}
/****************/int main(void)
{int *pt;pt = GetTime();  //通过指针间接访问printf("pt[0]=%d\n",pt[0]);printf("pt[1]=%d\n",pt[1]);    printf("pt[2]=%d\n",pt[2]);return 0;
}

传递参数和传递返回值

#include <stdio.h>int main(void)
{//用指针传递参数和体现模块的“句柄”
//    FILE *f = fopen("F:\\test.txt","w");
//    fputc('A',f);	//在f写个字符A
//    fputs('HelloWorld!',f);	//在f写个HelloWorld!char a;char s[10];FILE *f = fopen("F:\\test.txt","r");a = fgetc(f);  //普通的值传递fgets(s,15,f); //返回的输出参数fclose(f);printf("%c",a);peintf(s);return 0;
}

9.3 指针在单片机的运用

直接访问物理地址下的数据1)访问硬件指定内存下的数据,如设备ID号等2)将复杂格式的数据转换为字节,方便通信与存储

1)访问硬件指定内存下的数据,如设备ID号等

main.c文件

#include <REGX52.H>
#include "LCD1602.h"void main()
{
//	unsigned char *p;  //定义一个指针变量unsigned char code *p;  //定义一个指针变量(加code,访问程序存储空间)LCD_Init();LCD_ShowString(1,1,"Hello");//直接读取ID号存放的RAM区
//    p = (unsighne char *)0xF1;  //强制转换
//    LCD_ShowHexNum(2,1,*p,2);
//    LCD_ShowHexNum(2,3,*(p+1),2);
//    LCD_ShowHexNum(2,5,*(p+2),2);
//    LCD_ShowHexNum(2,7,*(p+3),2);
//    LCD_ShowHexNum(2,9,*(p+4),2);
//    LCD_ShowHexNum(2,11,*(p+5),2);
//    LCD_ShowHexNum(2,13,*(p+6),2);//ID号存放在程序的地址读取p = (unsighne char code *)0x1FF9;  //强制转换LCD_ShowHexNum(2,1,*p,2);LCD_ShowHexNum(2,3,*(p+1),2);LCD_ShowHexNum(2,5,*(p+2),2);LCD_ShowHexNum(2,7,*(p+3),2);LCD_ShowHexNum(2,9,*(p+4),2);LCD_ShowHexNum(2,11,*(p+5),2);LCD_ShowHexNum(2,13,*(p+6),2);while(1){}
}

2)将复杂格式的数据转换为字节,方便通信与存储

#include <stdio.h>/****************************/
unsigned char AirData[20];
void SendData(const unsigned char *data, unsigned char count)
{unsigned char i;for(i=0;i<count;i++){AirData[i]=data[i];}
}void ReceiveData(unsigned char *data,unsigned char count)
{unsigned char i;for(i=0;i<count;i++){data[i]=AirData[i];} 
}
/****************************/int main(void)
{unsigned char i;unsigned char DataSend[]={0x12,0x34,0x56,0x78};float num = 12.345;unsigned char *p;p = (unsigned char *)&num;SendData(p,4);/*****************************/SendData(DataSend,4);printf("\nAirData=");for(i=0;i<20;i++){printf("%x ",AirData[i]);}  /*****************************/unsigned char DataReceive[4];float *fp;ReceiveData(DataReceive,4);fp = (float *)DataReceive;printf("\nnum=%f",*fp);/*****************************/return 0;
}

补充:结构体指针

结构体指针是指一个指向结构体的指针,它可以用于访问和修改结构体中的成员变量。在 C 语言中,结构体指针的定义和初始化形式如下:

struct person {char* name;int age;
};struct person p; // 定义结构体变量
struct person *pp; // 定义结构体指针变量pp = &p; // 将结构体指针变量设置为结构体变量的地址
pp->name = "Tom"; // 使用 -> 运算符访问结构体指针成员变量
pp->age = 20;

其中,&p 表示取结构体变量 p 的地址,pp 表示指向结构体 person 的指针,pp->name 表示访问结构体指针成员变量 namepp->age 表示访问结构体指针成员变量 age

另外,在定义结构体指针时,也可以在指针类型前加上关键字 typedef,以便更方便地使用结构体指针:

typedef struct {char* name;int age;
} person;person p; // 定义结构体变量
person *pp = &p; // 定义结构体指针变量并初始化为结构体变量的地址
pp->name = "Tom"; // 访问结构体指针成员变量
pp->age = 20;

在这段代码中,person 是一个结构体类型别名,它等价于上面定义的 struct person。定义结构体变量时可以直接使用别名 person,定义结构体指针时也可以直接使用 person *

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

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

相关文章

【NX2023/1847】UG软件安装详细指南教程

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录安装包一、安装包内容检查二、安装步骤1.安装JAVA_WIN64.exe2.运行Launch.exe3.安装许可3.直接重启电脑&#xff08;小白直接重启稳妥&#xff09;4.重启后继续运行L…

【案例实践】R语言多元数据统计分析在生态环境中的实践应用

查看原文>>>R语言生物群落分析绘图、多元统计分析、CMIP6、遥感碳储量、GEE林业、InVEST等 生态环境领域研究中常常面对众多的不同类型的数据或变量&#xff0c;当要同时分析多个因变量&#xff08;y&#xff09;时需要用到多元统计分析&#xff08;multivariate sta…

《计算机网络-自顶向下》05. 网络层-控制平面

文章目录路由控制方式每路由控制逻辑集中式控制路由选择算法LS —— 链路状态路由选择算法DV —— 距离向量路由选择算法LS 和 DV 算法的比较自治系统内部路由协议RIPOSPF自治系统外部路由协议&#xff1a;BGP通告 BGP 路由信息选择最好的路由相关术语热土豆选择路由选择算法&a…

使用向量机(SVM)算法的推荐系统

系统整体结构 运行环境 包括Python环境、TensorFlow环境、安装模块、MySQL数据库。 Python环境 需要Python 3.6及以上配置&#xff0c;在Windows环境下推荐下载Anaconda完成Python所需的配置&#xff0c;下载地址为https://www.anaconda.com/&#xff0c;也可下载虚拟机在Li…

【ES】搜索结果处理RestClient查询文档

【ES】搜索结果处理&RestClient查询文档2.搜索结果处理2.1.排序2.1.1.普通字段排序2.1.2.地理坐标排序2.2.分页2.2.1.基本的分页2.2.2.深度分页问题2.2.3.小结2.3.高亮2.3.1.高亮原理2.3.2.实现高亮2.4.总结3.RestClient查询文档3.1.快速入门3.1.1.发起查询请求3.1.2.解析响…

Java面试题总结 | Java基础部分(持续更新)

Java基础 文章目录Java基础一个Java文件里可以有多个类吗&#xff08;不含内部类&#xff09;&#xff1f;创建对象的方法面向对象和面向过程简述自动装箱拆箱Java代码块执行顺序java中的基本数据类型对应的字节数包装类型和基本数据类型的场景java中的关键字分类final关键字st…

数据结构入门(C语言版)线性表中链表介绍及无头单向非循环链表接口实现

线性表之链表导航1、链表的概念和结构2、链表的分类3、链表的实现3.1 结构体定义3.2 接口函数定义3.3 接口函数的实现4、结语导航 1、链表的概念和结构 概念&#xff1a; 线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素 。因此&#xff0c;为了表示每…

推荐NLP基础 RNN循环神经网络

NLP概述 Natural Language Processing(NLP, 自然语言处理) 目的&#xff1a;让计算机处理或“理解”自然语言&#xff0c;以执行语言翻译和问题回答等任务&#xff1b;最终 来讲就是构建机器语言和人类语言之间的沟通桥梁&#xff0c;实现人机交流为最终目的。 常见应用&…

Python 虚拟环境迁移到其他电脑

一、背景介绍 在 Python 项目开发过程中&#xff0c;根据不同的项目场景&#xff0c;需要切换不同的 Python 版本。 因此&#xff0c;我们经常会对不同的项目&#xff0c;创建特定的 Python 虚拟环境&#xff0c;实现项目环境间的“物理隔离”。 本地创建 Python 虚拟环境&…

三、位置判断与代码搬移

判断当前位置 判断当前位置是否在SDRAM # < cpu\arm920t\start.S > relocate1: /* relocate U-Boot to RAM */ adr r0, _start /* r0 <- current position of code */ ldr r1, _TEXT_BASE /* test if we run from flash or RAM */ cmp r0, r1 /* dont reloc…

基于支持向量机SVM的脑部肿瘤识别,脑电波样本熵提取

目录 支持向量机SVM的详细原理 SVM的定义 SVM理论 Libsvm工具箱详解 简介 参数说明 易错及常见问题 SVM应用实例,基于SVM的的脑部肿瘤识别分类预测 代码 结果分析 展望 支持向量机SVM的详细原理 SVM的定义 支持向量机(support vector machines, SVM)是一种二分类模型,它…

电视王者沦落到再度卖楼求生,家电巨头跌落神坛,凸显行业之囧

电视无疑是中国家电行业中做得最成功的行业之一&#xff0c;在国内市场将外资品牌挤压出市场&#xff0c;还走向了海外市场&#xff0c;不过有一家国内的电视企业如今却无奈再度卖楼求生&#xff0c;这家企业就是长虹。一、长虹的变幻长虹称雄国内电视市场出自上一任领导人倪润…

pytorch 线性回归总结

测试1(y3∗x1−4∗x2y3*x_{1}-4*x_{2}y3∗x1​−4∗x2​),lr1e-2 %matplotlib inline import torch import numpy as np torch.manual_seed(1) from torch.nn import Linear from torch.autograd import Variable import torch.nn as nn import random np.random.seed(1) rand…

Robocup 仿真2D 学习笔记(四)阵型编辑

一、阵型文件介绍 阵型文件里设置的是球员在比赛中的跑位点 基于helios base的阵型文件&#xff0c;在目录/src/formations-dt中 阵型的调用在/src/strategy.cpp 文件&#xff1a; before-kick-off.conf 是球员上场之后的阵型 &#xff08;或进球等待开球&#xff09; no…

049:cesium加载czml文件,显示图形

第049个 点击查看专栏目录 本示例的目的是介绍如何在vue+cesium中加载czml文件, 显示图形。这是官网的一个示例,这里转换了处理方式。 直接复制下面的 vue+cesium源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共78行)相关API参考:专栏目标示…

暴击一棵树——二叉树入门一(入门基础概念)

目录 1.树的概念 2.二叉树的概念 二叉树&#xff08;Binary Tree&#xff09; 满二叉树&#xff08;Full Binary Tree&#xff09; 完全二叉树&#xff08;Complete Binary Tree&#xff09; 3.堆和二叉树 4、二叉树的结构 1.二叉树的逻辑结构 2.二叉树的物理结构 1.树…

《钢琴调律师 五级》 笔记

声音产生的三个条件&#xff1a;物体振动、媒质传播、人耳接收 复合音&#xff1a;由一些频率不同的简谐成分合成的声音。大多数乐器都是复合音&#xff0c;因此才各有不同的音色特征 纯音&#xff1a;物体做简谐振动所产生的声音 乐音&#xff1a;指有较为明确音调感的声音。噪…

spark第七章:SparkStreaming实例

系列文章目录 系列文章目录 spark第一章&#xff1a;环境安装 spark第二章&#xff1a;sparkcore实例 spark第三章&#xff1a;工程化代码 spark第四章&#xff1a;SparkSQL基本操作 spark第五章&#xff1a;SparkSQL实例 spark第六章&#xff1a;SparkStreaming基本操作 spa…

javaEE+jsp820高校校园设备报修系统dzkfa9程序mysql

1&#xff0e;系统登录&#xff1a;系统登录是用户访问系统的路口&#xff0c;设计了系统登录界面&#xff0c;包括用户名、密码和验证码&#xff0c;然后对登录进来的用户判断身份信息&#xff0c;判断是管理员用户还是普通用户。 2&#xff0e;系统用户管理&#xff1a;不管是…

从C出发 13 --- 多维数组

数组的本质是数据集合&#xff0c;我们在程序里面操作数组&#xff0c;就是在操作数据 数组中的元素能不能是其他程序元素? 这个说法只是表示数组里面的元素是int 类型 而这个数组的类型是 int [5] 由元素类型和数组大小共同决定 int a[10] {0}; // a的类型 : int[10]…