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

嵌入式c学习七

c语言指针:程序需要载入内存中运行,在32bit系统中内存地址的范围是:0x0000 0000-0xFFFF FFFF,内存大小为4GB,内存地址指的是内存单元的编号是固定的,本身就是一个整数,对于32bit系统,内存地址对应的编号是4字节的正整数

地址:c语言规定用户有权对对内存地址进行命名,地址编号本身也可以当初数据存在变量中

指针:c语言规定,用户打算定义一个变量来存储地址,则在定义变量前需要指明,变量中存的是一个地址,存储地址的变量叫做指针变量,指针变量定义格式:数据类型  *变量名;如int *p ==>p是变量名,*修饰变量p表示p是一个指针即p里面存储的数据是一个地址 ==> int 表示p指向的地址的内存下面的数据是整型

空指针:对指针变量初始化需要吧指针变量里面对应的内存设置为0,需要吧0强制转换成地址

0x00000000  ==> (void *)0x00000000 == c语言提供了宏定义NULL

保留区:linux系统的内存中有一部分内存是保留区,地址范围为:0x0000 0000-0x0804 8000,此区域用户无法访问,一旦访问就会出现段错误

int *p = NULL;  //对指针变量进行初始化,目的是防止野指针出现,避免段错误

#include <stdio.h>

int main()
{
	int data = 20;
	int *p = NULL;  //对指针进行初始化,避免野指针出现
	
	p = &data;      //p ==> &p ==> *(&p) == p,使用变量是操作系统默认先找到变量的地址(&),在间接访问地址里面的数据(*) 
	
	//通过变量名访问 
	data = 10;
	printf("data: %d\n", data); //10
	
	*(&data) = 20;
	printf("data: %d\n", data); //20  data == *(&data)
	
	//通过指针访问
	*p = 40;
	printf("data: %d\n", data); //40  p = &data ==> *p == *(&data) 
	
	return 0;
}

保留区地址用户是无法访问的,但可以定义指针指向这块空间,指针变量只能存储这个地址,不能间接访问该地址下的值,否则会段错误(Segmentation fault)

数组指针:int b[5]; int *p = b; 

#include <stdio.h>

int main()
{
	
	int a[5] = {1,2,3,4,5};
		
	for(int i=0; i<5; i++){
		printf("a[%d]=%d	", i, a[i]);  
	}
	printf("\n");
	
	int *p = a;                  //此处a表示数组首元素地址,即a==&a[0] 
	
	//通过数组下标访问
	a[0] = 10;
	printf("a[0]=%d\n", a[0]);   //10
	
	//通过指针访问
	*(p+1) = 20; 
	printf("*(p+1)=%d\n", a[1]); //20 p == a ==> *(p+1) ==*(a+1) == a[1]
	
	return 0;
}

 地址的运算:一般只能对地址进行 +- 运算,表示地址的偏移,偏移的单位取决于该地址下存储的数据的类型

#include <stdio.h>

int main()
{
	
	int a[5] = {1,2,3,4,5};
	
	printf("a的地址为:   %p\n", a);     //a表示数组首元素地址 
	printf("a+1的地址为: %p\n", a+1);   //a+1表示地址向后偏移一个数组元素单位即4字节 
	printf("&a+1的地址为: %p\n", &a+1);  //&a表示 整个数组地址,&a+1表示地址向后偏移一个数组单位即4*5=20字节 
		
	int *ptr = (int*)(&a+1);           
	printf("*(a+1)=%d\n", *(a+1));     //2  *(a+1) = a[1] = 2
	printf("*(ptr-1)=%d\n", *(ptr-1)); //5 

	return 0;
}

二维数组与指针

#include <stdio.h>

int main()
{
	
	int aa[2][5] = {{1,2,3,4,5},{6,7,8,9,10}};
	
	//单独从地址的值来说,aa==aa[0]==&aa[0][0]==&aa 
	printf("aa地址      %p\naa[0]地址   %p\naa[0][0]地址%p\n&aa地址     %p\n", aa, aa[0], &aa[0][0], &aa); 
	
	//aa表示数组首元素地址,即aa == &aa[0]
	printf("&aa[0]的地址: %p\naa的地址:     %p\n", &aa[0], aa); 
	
	printf("aa+1的地址:   %p\n", aa+1);   //aa+1表示地址从aa[0]偏移到aa[1],偏移aa[2]数组中一个元素的字节:4*5=20字节 
	     
	printf("&aa的地址:    %p\n\n", &aa);   //&aa表示整个数组的地址
	
	printf("&aa+1的地址:  %p\n\n", &aa+1);  //&aa+1,表示地址向后偏移一个数组单位即2*4*5=40字节 
	
 	
	int *ptr1 = (int*)(&aa +1);            //此时ptr1指向数组aa的后一个地址 
	
	printf("*(ptr1-1)=%d\n", *(ptr1-1));   //10 向后偏移一个整型元素aa[1][4]的值 
	
	int *ptr2 = (int*)(*(aa+1));           //此时ptr2表示aa[1]的地址,int*表示指向aa[1][0] 
	printf("*(ptr2-1)=%d\n", *(ptr2-1));   // 5  aa[0][4] 
	
	return 0;
}

二维数组的访问

#include <stdio.h>

int main()
{
	
	int aa[2][5] = {{1,2,3,4,5},{6,7,8,9,10}};
	
	for(int i=0; i<2; i++){
		for(int j=0; j<5; j++){
			printf("aa[%d][%d]=%d  ", i, j, aa[i][j]);
		}
		printf("\n");
	}
	
	//p变量名,*p表示p是指针,[5]表示p指向有5个元素的匿名数组,int表示指针指向的内存中数据为整型 
	int (*p)[5] = aa;  //将数组aa的首地址即&aa[0]存到指针变量p中
	
	//数组下标访问
	aa[0][0] = 10;    // aa[0][0] == *(aa[0]+0) == *aa[0] == *(&aa[0][0])
	printf("a[0][0]=%d\n", aa[0][0]); 
	
	//指针变量访问aa[1][2]
	//aa[1][2] == *(aa[1]+2) == *(*(aa+1)+2) ==>aa==&aa[0]==p ==>*(*(p+1)+2) 
	*(*(p+1)+2) = 80;
	printf("a[1][2]=%d\n", aa[1][2]); 
	 
	return 0;
}

指针数组:数组中每个元素都是指针,定义格式:数据类型   *数组名[元素个数];如:int *p[5];

二级指针:指针变量中存储的值,是另一个指针变量的地址

指针与数组的定义:int * (*p)[3][4]

p:表示变量p 

*p:表示变量p是一个指针,用于存放地址

[3]:表示指针p存储的地址下的数据类型是一个匿名数组,可以存放三个元素

[4]:表示匿名数组[3]中每个元素都是一个有4个元素的匿名数组

*:   表示匿名数组[4]中每个元素的类型是一个指针

int:表示[4]中存储的指针所指向的地址是int

	int *(*p)[2][3];   //运算符优先级()>[]>* 
	
	// *p     		  :表示p是一个指针存放的数据是地址
	// (*p)[2]        :表示p指针里面存放的地址,地址下面的数据类型为匿名数组[2]里面有两个元素
	// (*p)[2][3]     :表示匿名数组[2]里面的数据,类型是匿名数组[3]->里面有三个元素
	// *(*p)[2][3]    :表示匿名数组[3]里面的数据,类型是指针
	// int *(*p)[2][3]:表示匿名数组[3]里面存的地址,地址所下面存的数据类型为int 

二级指针定义格式:int data;  int *p1= &data;  int **p2 = &p1;==>*p2是一个指针存储的值为地址,*表示p1里面存的地址下面的值,还是指针

#include <stdio.h>

int main()
{
	int data = 10;		//定义整型变量 
	int *p1 = &data;	//定义指针变量存储data的地址 
	int **p2 = &p1;		//定义二级指针,存储指针p1的地址 
	
	//用变量名访问数据
	data = 20;
	printf("data=%d\n", data); 
	
	//用指针p1访问数据
	*p1 = 30;          //p1==&data ==>*p1 == *(&data) == data 
	printf("*p1=%d\n", data); 
	
	//用指针p2访问 
	**p2 = 40;		   //p2 == &p1 ==> *p2 == *(&p1) == p1 ==> **p2 ==*p1 == data
	printf("**p2=%d\n", data); 
	
	//一维数组形式访问
	p1[0] = 50;       //p1[0] == *(p1+0) == *p1 == data 
	printf("p1[0]=%d\n", data); 
	
	//二维数组形式访问
	p2[0][0] = 60;    // p2[0][0] == *(p2[0]+0) == *p2[0] == *(*(p2+0)) == **p2 == data 
	printf("p2[0][0]=%d\n", data); 	
	
	return 0;
}

练习:

#include <stdio.h>

int main()
{
	int buf[5] = {1,2,3,4,5};
	int *p = buf;
	
	printf("%d\n", *p++);  		//1:++后置,*p =buf[0]=1,结束后P指向a[1]的地址 
	printf("%d\n", (*p)++);		//2:++后置,*p=buf[1]=2,结束后p指向a[2]的地址 
	
	return 0;
}

相关文章:

  • 企业架构与IT方法论:现代企业的基石
  • SQLark 实战 | 如何通过对象名和 DDL 快速搜索数据库对象
  • Unity TextMeshPro中显示建筑特殊符号
  • 【NGINX代理附件上传服务配置优化】
  • java项目之基于ssm的旅游论坛(源码+文档)
  • k8s搭建kube-prometheus
  • 在 Ubuntu 中用 Docker 安装 RAGFlow
  • 相同Vlan间的通信
  • HBase启动问题排查指南:解决HMaster和HRegionServer未运行的常见错误
  • 【C语言】使用结构体实现位段
  • Redis之单线程与多线程
  • ASP.NET Core 使用 MongoDB
  • Git Flow 分支管理策略
  • LeetCode算法题(Go语言实现)_01
  • GR00T N1——英伟达开源的通用人形VLA:类似Helix的快与慢双系统,且可类似ViLLA利用海量的无标注视频做训练
  • Docker和Dify学习笔记
  • c++简单实现redis
  • 使用LLaMA Factory微调导出模型,并用ollama运行,用open webui使用该模型
  • 基于javaweb的SpringBoot成绩管理系统设计与实现(源码+文档+部署讲解)
  • 优化广告投放算法
  • 上海小学生暑(寒)托班会增设开办期数、延长办班时间吗?团市委回应
  • 中国驻美大使:远离故土的子弹库帛书正随民族复兴踏上归途
  • 湖南4个县市区被确定为野生蘑菇中毒高风险区:中毒尚无特效解毒药
  • 广西百色“致富果”:高品质芒果直供香港,带动近五千户增收
  • 科普|认识谵妄:它有哪些表现?患者怎样走出“迷雾”?
  • 中国社联成立95周年,《中国社联期刊汇编》等研究丛书出版