C语言杂记(指针篇)

news2024/11/26 2:33:49

指针篇

指针就是地址,地址就是指针 指针变量就是存放地址的变量
*号只有定义的时候表示定义指针变量,其他表示从地址里面取内容

通过指针的方法使main函数中的data1和data2发生数据交换。

#include <stdio.h>
void chang_data(int *data1,int *data2)
{
	int tmp;
	tmp = *data1;
	*data1 = *data2;
	*data2 = tmp;
	
}


int main()
{
	int data1 = 10;
	int data2 = 20;
	chang_data(&data1,&data2);
	printf("data1:%d  data2:%d\n",data1,data2);
	return 0;
}

============================================================================

指针指向固定的区域
volatile :防止编译器进行编译优化,导致原来的值发生变化

#include <stdio.h>

int main()
{
	volatile unsigned int *p = (volatile unsigned int *)0x0000000001234567;
	printf("p:%p\n",p);
	return 0;
}

============================================================================

输入三个数,要求不管怎么输入,在输出的时候要由大到小输出,用函数封装的方法

#include <stdio.h>
int func(int *data1,int *data2,int *data3)
{
	int tmp;
	if(*data1 < *data2){
		tmp = *data1;
		*data1 = *data2;
		*data2 = tmp;
	}
	if(*data1 < *data3){
		tmp = *data1;
		*data1 = *data3;
		*data3 = tmp;
	}
	if(*data2 < *data3){
		tmp = *data2;
		*data2 = *data3;
		*data3 = tmp;
	}
	
}
int main()
{
	int data1;
	int data2;
	int data3;
	scanf("%d %d %d",&data1,&data2,&data3);
	func(&data1,&data2,&data3);
	printf("大到小:%d %d %d \n",data1,data2,data3);
	return 0;
}

============================================================================

1.定义一个指针变量指向数组
在C语言当中,数组名(不包括形参数组名)代表数组中首元素的地址,所以p = &a[0];//或者p =a;这两个等价的
2. 指针的偏移,偏移多少根据指针的类型,int偏移四个字节,char就偏移一个字节,使用的指针偏移遍历数组
3.指针的访问效率是远远大于数组下标的访问效率的

int main()
{
	int i = 0;
	int a[] = {1,2,3};
	int *p;
	p = &a[0];//或者p = a;
	for(i=0;i<sizeof(a)/sizeof(a[0]);i++){
		printf("a[%d] = %d \n",i,*p++);
	}
	p = a;//让指针重新指向数组的首元素地址
	return 0;
}

============================================================================

64位操作系统,一个指针占8个字节,所以八个字节表示一个地址

struct demo{
	int a;
	char c;
};
int main()
{
	struct demo *test;
	printf("sizeof int *:%d\n",sizeof(int *));
	printf("sizeof char *:%d\n",sizeof(char *));
	printf("sizeof double *:%d\n",sizeof(double *));
	printf("sizeof struct  *:%d\n",sizeof(test));
	return 0;
}

在这里插入图片描述

============================================================================

  1. 函数封装数组初始化和遍历
  2. 作为形参的指针,在调用函数时也会分配自己的一个地址,作为指针,指向传过来的地址(下面传过来的main函数arr的首地址),后续就是对传过来的地址进行操作
    ps:下面输出遍历的时候为什么不用把parr重新指向arr的首地址,因为这是两个函数,每个传过来的就是parr就是arr的首地址
#include <stdio.h>

void Init_arr(int *parr,int len)
{
	int i= 0;
	for(i=0;i<len;i++){
		*parr = i;
		parr++;	
	}
}

void Printf_arr(int *parr,int len)
{
	int *tmp2;
	for(int i = 0;i<len;i++){
	printf("arr:%d\n",*parr);
	parr++;
	}
	
	
}

int main()
{
	int arr[5];
	int len = sizeof(arr)/sizeof(arr[0]);
	
	Init_arr(arr,len);
	Printf_arr(arr,len);

	return 0;
}

============================================================================
练习:数组翻转

#include <stdio.h>

void Init_arr(int *parr,int len)
{
	int i= 0;
	for(i=0;i<len;i++){
		*parr = i;
		parr++;	
	}
}

void Overturn_arr(int *arr,int len)
{
	int i,j;
	int tmp;
	for(i=0;i<(len/2);i++){
		j = len-1-i;
		tmp = *(arr+i);
		*(arr+i) = *(arr+j);
		*(arr+j) = tmp;
}
}
void Printf_arr(int *parr,int len)
{

	for(int i = 0;i<len;i++){
	printf("arr:%d\n",*parr);
	parr++;
	}
	
	
}

int main()
{
	int arr[5];
	int len = sizeof(arr)/sizeof(arr[0]);
	
	Init_arr(arr,len);
	Overturn_arr(arr,len);
	Printf_arr(arr,len);

	return 0;
}

============================================================================

二维数组的认知 现在有一个二维数组,我们可以把二维数组理解为父子数组,还有数组名就是地址
int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
那么父数组的名字就是a,而字数组的名字就是a[0],a[1],a[2],那么我们可以看出a的地址和a[0]的地址是一样的,但是要注意他们的偏移量是不一样的,a+1偏移的是一整个子数组的大小,a[0]+1是偏移一个数组元素的大小。
a[0] 等价于 &a[0][0] a[1]等价于 = &a[1][0] a[2]等价于 = &a[2][0]
那么a表示父数组的地址,a[0]表示的字数组的首地址
(a)等价与a[0]的首地址(因为a不可能取到整个子数组的值),*(a)+1就是(a[0])+1

#include <stdio.h>
int main()
{
	int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
	
	printf("a父数组地址 IP:%p   %d\n",a,*(a));
	printf("a[0]子数组地址 IP:%p  %d\n",a[0],*(a[0]));
	
	printf("a+1父数组地址偏移 IP:%p  %d\n",(a+1),*(a+1));
	printf("a[0]+1字数组地址偏移 IP:%p  %d\n",(a[0]+1),*(a[0]+1));
	//*(a)等价与a[0]的首地址,*(a)+1就是(a[0])+1
	printf("*(a)字数组地址偏移 IP:%p   *(a)+1的地址: %p\n",*(a),*(a)+1);
	return 0;
}

在这里插入图片描述
总结:
在这里插入图片描述

============================================================================

数组指针:就是数组的指针,其实就是一个指向数组的指针。 数组指针才是等同于二维数组名

#include <stdio.h>
int main()
{
	int arr[2][3] = {{1,2,3},{4,5,6}};
	int (*p)[3];//指向有3个元素数组的指针
	p = arr;
	int i,j;
	printf("p=%p\n",p);
	printf("++p:%p\n",++p);//这里看出地址偏移是12字节,就是一个子数组的大小
	p = arr;//这里让p重新指向二维数组名,再使用p遍历数组
	for(i=0;i<2;i++){
		for(j=0;j<3;j++){
			//printf("arr:%d\n",arr[i][j]);
			printf("arr:%d\n",*(*(p+i)+j));
		}
	}
	return 0;
}

在这里插入图片描述

============================================================================
数组指针的和二维数组的配合使用

题目:用数组指针方法,输出二维数组任意行列的数

#include <stdio.h>


void InputNum(int *hang,int *lie)
{
	printf("输入行列号:\n");
	scanf("%d %d",hang,lie);
}

int SearchNum(int (*p)[4],int hang,int lie)
{
	return (*(*(p+hang)+lie));
}

int main()
{
	int a[3][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}};
	
	int hang,lie;
	int data;
	//提示输出
	InputNum(&hang,&lie);
	//找到对于的数字
	data = SearchNum(a,hang,lie);
	//打印出来
	printf("第%d行第%d列的数字为:%d\n",hang,lie,data);
	return 0;
}

============================================================================
函数指针,就是一个指向函数入口地址的指针。

1.函数指针:如果程序中定义了一个函数,在编译的时候,编译系统会为函数代码分配一段存储空间,这段存储空间的起始地址(又成为入口地址)称为这个函数的指针。
2.函数名就是地址
3.如何定义一个函数指针变量:int (*p)(int a,int b)
4.定义函数指针的时候要和指向的函数的类型保持一致

#include <stdio.h>

void printfWeclme()
{
	printf("hello world\n");
	
}

int DataAdd(int data)
{
	return ++data;
	
}

int main()
{
	void (*p)(); //函数指针的定义
	int (*p2)(int data);
	
	p = printfWeclme;//指向printfWeclme这个函数
	p2 = DataAdd;
	
	(*p)();//利用函数指针调用这个函数
	
	printf("++data:%d\n",(*p2)(10));
	return 0;
}

练习:用函数指针实现两个整数ab,输入1 2 或者3,1:输出ab中的大者,2:输出ab中的小者,3:输出ab之和

#include <stdio.h>
#include <stdlib.h>
int GetMax(int a,int b)
{
	int Max;
	if(a>b){
		Max = a;
	}else{
		Max = b;
	}
	return Max;
}

int GetMin(int a,int b)
{
	int Min;
	if(a<b){
		Min = a;
	}else{
		Min = b;
	}
	return Min;
}

float GetAvg(int a,int b)
{
	return ((float)a+(float)b)/2;
}

int dataHandler(int a,int b,int (*func1)(int,int))
{
	int ret;
	ret = (*func1)(a,b);
	return ret;
	
}

float dataHandler2(int a,int b,float (*func2)(int,int))
{
	float ret;
	ret = (*func2)(a,b);
	return ret;
	
}
int main()
{
	int a = 10;
	int b = 20;
	int mark;
	int ret;
	float ret2;
	int (*func1)(int,int);
	float (*func2)(int,int);
	printf("Input:");
	scanf("%d",&mark);
	switch(mark){
		case 1:
			func1 = GetMax;
		break;
		case 2:
			func1 = GetMin;
		break;
		
		case 3:
			func2 = GetAvg;
		break;
		
		default:
		printf("Input error\n");
		exit(-1);
		
	}
	if(mark != 3){
	ret = dataHandler(a,b,func1);
	printf("ret:%d\n",ret);
	}else{
	ret2 = dataHandler2(a,b,func2);
	printf("ret2:%0.2f\n",ret2);
	}
	
	
	return 0;
}

============================================================================
数组指针:
在这里插入图片描述

理解::指针数组就是存放指针的数组,数组的每一项都是指针变量

int main()
{
	int a = 1;
	int b = 2;
	int c = 3;
	int* arr[3] = {&a,&b,&c};
	
	for(int i=0;i<3;i++){
		printf("%d ",*(arr[i]));
	}	
	return 0;
}

定义一个函数指针数组,然后进行函数调用:

#include <stdio.h>
#include <stdlib.h>

int GetMax(int a,int b)
{
	int Max;
	if(a>b){
		Max = a;
	}else{
		Max = b;
	}
	printf("Max:%d\n",Max);
	return Max;
}

int GetMin(int a,int b)
{
	int Min;
	if(a>b){
		Min = b;
	}else{
		Min = a;
	}
	printf("Min:%d\n",Min);
	return Min;
}

int main()
{
	int a = 10;
	int b = 20;
	int (*pfun[2])(int,int) = {GetMax,GetMin};//定义了一个指向函数入口的函数指针数组,每一项都指向一个函数入口地址
	for(int i=0;i<2;i++){
		(*pfun[i])(a,b);//进行调用
	}

	return 0;
}

============================================================================
指针函数:返回指针值的函数
在这里插入图片描述

有3个学生,每个学生对于四门成绩,要求用用户输入学生序号后,输出该学生的全部成绩。用函数指针实现

#include <stdio.h>


int *getPosPenson(int pos,int (*pstu)[4])//函数指针
{
	int *p;
	p = (int *)(pstu+pos);
	return p;
	
}

int main()
{
	int arr[3][4] = {
		{1,2,3,4},
		{5,6,7,8},
		{45,52,63,54}		
	};
	
	int *ppos;
	int pos;//学生0 1 2
	
	do{
		printf("输入学生012:");
		scanf("%d",&pos);
	}while(pos!=0 && pos!=1 && pos!=2 );

	
	ppos = getPosPenson(pos,arr);
	for(int i=0;i<4;i++){
		printf("%d ",*(ppos++));
	}
	
	return 0;
}

在这里插入图片描述

============================================================================
二级指针:保存指针地址的指针

#include <stdio.h>

int main()
{
	int data = 10;
	int *p;
	p = &data;
	int **p2;
	
	printf("data的地址:%p\n",&data);
	printf("p存放的地址(data的地址):%p\n",p);
	
	printf("p本身的地址:%p\n",&p);
	
	p2 = &p;
	printf("p2保存的地址(p本身的地址):%p\n",p2);
	printf("*p2是:%p\n",*p2);//这里取到的应该是data的地址
	printf("**p2是:%d\n",**p2);//这里就取到data的值了
	
	return 0;
}

在这里插入图片描述

============================================================================
下面对于ppos的理解

#include <stdio.h>


void  getPosPenson(int pos,int (*pstu)[4],int **ppos)//函数指针
{
	
	*ppos = (int *)(pstu+pos);//*ppos取到的就是main函数一级指针ppos的地址,这个指针指向了pstu这个指针的偏移地址,所以main函数中的ppos就再*(取一次内容)就访问到里面的值了

}

int main()
{
	int arr[3][4] = {
		{1,2,3,4},
		{5,6,7,8},
		{45,52,63,54}		
	};
	
	int *ppos;
	int pos;//学生0 1 2
	
	do{
		printf("输入学生012:");
		scanf("%d",&pos);
	}while(pos!=0 && pos!=1 && pos!=2 );

	
	getPosPenson(pos,arr,&ppos);//这里传过去的时ppos的地址(指针的地址需要二级指针来承接)
		for(int i=0;i<4;i++){
		printf("%d ",*(ppos++));
	}
	

	
	return 0;
}

============================================================================
二级指针不能简单粗暴指向二维数组

============================================================================
搞懂下面这张图
在这里插入图片描述

================================================================================================================================================================

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

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

相关文章

Flutter知识点(二)处理Json

flutter不支持反射&#xff0c;所以本来很简单的事情&#xff0c;一下子变复杂了。当然官方也提供了一些工具来方便开发者。 由于Dart的map和array的数据结构和json一样&#xff0c;所以在flutter中&#xff0c;变成了json string与Map&#xff0c;array之间的砖换。 &#x…

MYSQL数据库学习

数据库的基本概念 什么是数据库&#xff1f; 数据库&#xff08;database&#xff09;是用来组织 存储和管理数据的仓库。 当今世界是一个充满着数据的互联网世界&#xff0c;充斥着大量的数据。数据的来源有很多&#xff0c;比如出行记录 消费记录 浏览的网页 发送的信息等等…

《C++ Primer》 第十一章 关联容器

《C Primer》 第十一章 关联容器 11.1 使用关联容器 使用map: //统计每个单词在输入中出现的次数 map<string, size_t> word_count;//string到size_t的空map string word; while(cin>>word)word_count[word];//提取word的计数器并将其加1 for(const auto &w:…

Linux系统之部署Gitblit服务器

Linux系统之部署Gitblit服务器一、Gitblit介绍1.Gitblit简介2..Gitblit官网二、检查本地系统环境1.检查系统版本2.检查系统内核版本3.检查JDK版本三、下载Gitblit1.创建下载目录2.下载Gitblit软件包2.解压Gitblit软件包四、Gitblit的配置工作1.修改配置文件2.修改service-cento…

【小程序】如何实现一个可折叠的列表

作者刚接触小程序开发不久&#xff0c;打算用 CSDN 把学习过程中遇到的一些问题记录下来&#xff0c;都是一些浅显易懂的内容&#xff0c;希望对你也有所帮助。 如文章标题所示&#xff0c;作者要实现一个可折叠的列表&#xff0c;先来看一下页面效果&#xff1a; 这种展示方式…

ChatGPT API 低价上线,开发者可以人手一个了?

千呼万唤&#xff0c;ChatGPT API来了&#xff01; 不仅首发&#xff0c;价格居然还有惊喜&#xff0c;0.002美元/每1000 token&#xff0c;并将价格降低90%&#xff0c;直接打了1折。OpenAI官方还表示&#xff0c;gpt-3.5-turbo目前的版本代号是gpt-3.5-turbo-0301&#xff0…

【面试系列】equals和==的区别

问题&#xff1a;两个对象值相同(x.equals(y) true)&#xff0c;但是可能存在hashCode不同吗? 的定义 比较的是两个对象的内存地址&#xff0c;相等则意味着内存地址一样。 对象的equals方法 Object#equals public boolean equals(Object obj) {return (this obj);}Stri…

数据结构——基本概念

数据数据&#xff1a;是描述客观事物的符号&#xff0c;是计算机中可以操作的对象&#xff0c;是能被计算机识别&#xff0c;并输入给计算机处理的符号的集合。数据元素&#xff1a;是组成数据的&#xff0c;有一定意义的基本单位&#xff0c;在计算机中通常作为整体处理&#…

基于上下文分析的 Python 实时 API 推荐

原文来自微信公众号“编程语言Lab”&#xff1a;基于上下文分析的 Python 实时 API 推荐 搜索关注 “编程语言Lab”公众号&#xff08;HW-PLLab&#xff09;获取更多技术内容&#xff01; 欢迎加入 编程语言社区 SIG-程序分析 参与交流讨论&#xff08;加入方式&#xff1a;添加…

ICLR 2023 | LightGCL: 简单且高效的图对比学习推荐系统

论文题目&#xff1a;LightGCL: Simple Yet Effective Graph Contrastive Learning for Recommendation收录会议&#xff1a;ICLR 2023论文链接&#xff1a;https://arxiv.org/abs/2302.08191代码链接&#xff1a;https://github.com/HKUDS/LightGCL港大数据智能实验室 &#x…

billu_box靶场通关

billu靶场通关 靶机ip&#xff1a;192.168.112.134 信息收集 端口开放 80 目录扫描 images目录存在目录遍历 test.php(任意文件下载) add.php(文件上传) index.php(主页) head.php show.php c.php这个工具的字典不全&#xff0c;换py脚本重新扫多出了以下目录 phpmy in …

目标检测YOLOv5数据集怎么找?

完整的配置-标注-训练-识别在我这篇博客小白YOLOv5全流程-训练实现数字识别_yolov5数字识别_牛大了2022的博客-CSDN博客 模型部分剖析可以看我每周深度学习笔记部分。关于训练的数据集怎么搞很多人问过我&#xff0c;我在这篇文章给大家一点我的经验和建议。 数据集是什么 简…

Leetcode每日一题 1487. 保证文件名唯一

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法......感兴趣就关注我吧&#xff01;你定不会失望。 &#x1f308;个人主页&#xff1a;主页链接 &#x1f308;算法专栏&#xff1a;专栏链接 我会一直往里填充内容哒&#xff01; &…

网上心理咨询系统的设计与实现

技术&#xff1a;Java、JSP等摘要&#xff1a;高等院校担负着培养高素质人才的使命&#xff0c;高素质人才不仅要有良好的思想道德素质、科学文化素质和身体素质&#xff0c;更要有良好的心理素质。然而随着近年来我国高校的连续扩招以及高额的学费居高不下&#xff0c;当代的大…

工程项目管理软件有哪些?这六款很好用!

工程项目管理软件哪个好用&#xff1f;这六款很不错&#xff01; 在现代社会中&#xff0c;软件已经成为了企业信息化、项目管理等方面必不可少的工具。尤其是对于工程项目管理而言&#xff0c;借助软件进行协同、计划、控制等方面的工作&#xff0c;已经成为了必要的手段。但…

钡铼技术BL302 ARM工控机QT图形化界面开发的实践

QT是一种跨平台的应用程序框架&#xff0c;用于开发图形用户界面(GUI)、网络应用程序和嵌入式应用程序。QT提供了丰富的GUI组件和工具&#xff0c;使开发人员能够轻松地创建专业级别的应用程序。QT使用C编写&#xff0c;支持多种操作系统&#xff0c;包括Windows、Linux、macOS…

tuts4you上lena‘s40个crackme(1)

本来是不打算写文章了&#xff0c;因为懒&#xff0c;想以后通过录屏的形式保存一下自己学的路程。但奈何开学后一直没找到机会&#xff0c;在宿舍也不愿意大吼大叫的讲东西&#xff0c;只好再写写文章了 最近学了一些汇编语言和逆向工程&#xff0c;所以就想通过这40给题目来看…

hashCode 和 equals 的处理

文章目录hashCode 和 equals 的处理1. 阿里巴巴编程规范要求2. equals和hashcode的分析2.1 Object方法2.2 只覆写&#xff08;Override&#xff09;equals带来的问题问题演示问题分析问题处理hashCode 和 equals 的处理 1. 阿里巴巴编程规范要求 2. equals和hashcode的分析 2…

python实战应用讲解-【numpy专题篇】函数(附python示例代码)

NumPy 数学函数 NumPy 包含大量的数学运算的函数,包括三角函数,算术运算的函数,复数处理函数等。 三角函数 NumPy 提供了标准的三角函数:sin()、cos()、tan()等 import numpy as npa = np.array([0, 30, 45, 60, 90]) print(不同角度的正弦值:) # 通过乘 pi/180 转化…

园区智慧能源管理系统

实现对园区的用能情况实时、全方位监测&#xff0c;重点设备进行数据自动采集并智能统计、分析&#xff0c;根据需要绘制各种趋势曲线、能源流向图和分析报表。将物联网、大数据与全过程能源管理相融合&#xff0c;提供全生命周期的数字化用能服务&#xff0c;实现用能的精细化…