C语言:指针进阶

一、字符指针

	char arr[] = "hello";char* p = "hello";  //p中存的是"hello"字符串首元素的地址printf("%c\n",*arr); //hprintf("%c\n", *p);  //hprintf("%s\n", arr); //"hello",以字符串格式打印,从首元素开始,遇到'\0'结束printf("%s\n", p);  //"hello"*arr = 'x';  //存放在数组中,可以修改//*p = 'y';  //err,char* p = "hello";为常量,不可修改printf("%c\n", *arr); //x//printf("%c\n", *p); 

1.1练习题 

	char str1[] = "hello bit.";char str2[] = "hello bit.";char* str3 = "hello bit.";char* str4 = "hello bit.";if (str1 == str2)printf("str1 and str2 are same\n");elseprintf("str1 and str2 are not same\n");if (str3 == str4)printf("str3 and str4 are same\n");elseprintf("str3 and str4 are not same\n");
//str1 and str2 are not same  
//str3 and str4 are same

str1为自己数组中首元素的地址, str2为自己数组中首元素的地址, str1≠str2;即内存中保存有两份"hello bit.",但存放的地址不同;

str3和str4中对应的字符串均为常量(不可修改),内容一样,又不可修改,在内存中只保留一份,即str3和str4均指向同一个字符串"hello bit."的首字母地址。


二、指针数组

//指针数组
//是数组-数组中存放的是指针(地址)
//int* arr[3];存放整形指针的数组

int a[5] = {1,2,3,4,5};
int b[5] = {2,3,4,5,6};
int c[5] = {3,4,5,6,7};
int* arr[3] = {a,b,c};
for (int i = 0; i < 3; i++)
{for (int j = 0; j < 5; j++)printf("%d ", *(arr[i] + j));//arr[i]+j<=>arr[i][j]printf("\n");
}

三、数组指针

3.1 书写方式

//数组指针 - 是指向数组的指针

	int a = 1;int* pa = &a;char b = 'w';char* pb = &b;int arr[10] = {1,2,3,4,5};//arr,数组名,是首元素arr[0]的地址//&arr,取出的是数组的地址int (*parr)[10] = &arr;//parr数组指针,指向一个数组,存放的是数组的地址//(*parr)确保parr是指针,[10]确保是是数组指针,int:指针指向的数组元素类型为整形double* d[5];double* (*pd)[5] = &d;//(*pd)确保pd是指针,[5]确保是数组指针,double*:指针指向的数组元素类型为浮点型指针

3.2 arr和&arr区别

	int arr[10] = {0};int* p1 = arr;int(*p2)[10] = &arr;printf("%p\n",arr); //0053F9E4printf("%p\n", &arr); //0053F9E4printf("%p\n", p1);  //0053F9E4printf("%p\n", p2);  //0053F9E4printf("%p\n", p1+1); //0053F9E8,比0053F9E4多4printf("%p\n", p2+1); //0053FA0C,比0053F9E4多40

3.3 注意

数组名是数组首元素地址

但有2个例外:

1.sizeof(数组名):计算整个数组的大小,单位是字节

2.&数组名:取出的是整个数组的地址

 3.4 &arr进阶

3.4.1 一维数组

	int arr[5] = {1,2,3,4,5};int(*p)[5] = &arr; //p是指向数组arr的指针for (int i = 0; i < 5; i++)printf("%d ", *((*p) + i)); //*p是数组首元素地址(*p=*(&arr)=arr)//*((*p) + i)<=>*(arr + i)<=>arr[i]

p是指向数组的数组指针,存放的是整个数组的地址;*p解引用表示整个数组首元素的地址;

	int arr1[5] = { 1,2,3,4,5 };int a = 0;int* pa = &a;int* arr2[2] = {pa}; //数组中有2个元素,都是整形指针类型int(*p1)[5] = &arr1;int(*p2)[2] = &arr2;printf("%d\n",**p1);   //1,*p1=arr1,**p1=*arr1=数组首元素printf("%d\n", **(arr2)); //0,*arr2=pa=&a数组首元素,**arr2=*paprintf("%d\n", ***p2); //err(不懂),*p2 = arr2printf("%d\n", *(int*)(**p2)); //0

3.4.2 一维数组传参

void test(int arr[])//ok
{}
void test(int arr[10])//ok
{}
void test(int *arr)//ok
{}
void test2(int *arr[20])//ok
{}
void test2(int **arr)//ok,arr2是数组首元素(地址)的地址,即是地址的地址
{}
int main()
{int arr[10] = {0};int *arr2[20] = {0};test(arr);test2(arr2);
}

3.4.3 二维数组

//arr[3][5]

//1.arr表示二维数组首元素地址,但此首元素为第一行的一维数组,是一个数组指针

//即,arr是一个指向第一行一维数组的数组指针

//2.&arr表示指向整个二维数组的指针

//3.*arr表示指向第一行一维数组首元素的地址《=》arr[0]

//4.**arr表示指向第一行一维数组首元素 <=>*arr[0]<>=arr[0][0]

	int arr[3][5] = {{1,2,3,4,5}, {22,33,44,55,66}, {333,444,555,666,777}};printf("%p\n",*arr);  //第一行一维数组首元素地址,即1的地址printf("%p\n", arr[0]); //第一行一维数组首元素地址,即1的地址printf("%p\n", arr + 1);//第二行一维数组地址printf("%p\n", *(arr + 1)); //第二行一维数组地址首元素地址printf("%p\n", arr[1]); //第二行一维数组地址首元素地址printf("%d\n", **arr); //取出数字1printf("%d\n",*arr[0]);//1printf("%d\n", *(*arr + 1)); //2printf("%d\n", *(arr[0] + 1));  //2, =>arr[0][1]printf("%d\n", *arr[1]);  //22,=>arr[1][0]printf("%d\n", **(arr + 1));//22

 3.4.4二维数组传参

void test(int arr[3][5])//ok
{}
void test(int arr[][])//err
{}
void test(int arr[][5])//ok
{}
void test(int *arr)//err,整形指针
{}
void test(int* arr[5])//err,指针数组
{}
void test(int (*arr)[5])//ok
{}
void test(int **arr)//err,二级指针
{}
int main()
{int arr[3][5] = {0};test(arr); //arr是数组指针
}

四、函数指针

4.1 书写方式

//1.指向函数的指针

//2.存放函数地址的指针

//数组名 !=& 数组名

//函数名 == &函数名(意义相同,写法不同)

int add(int x,int y)
{return x+y;
}
int main()
{printf("%p\n",add); //001613CAprintf("%p\n",&add); //001613CA//pf就是一个函数指针变量int (*pf)(int,int) = &add;//或者 int (*pf)(int,int) = add; pf<==>addint ret = add(3,5); int ret1 = (*pf)(3,5); //*只是一个摆设int ret2 = pf(3,5); printf("%d ",ret1);  //8printf("%d ",ret2);  //8return 0;
}

4.2 练习题

//题一

int main()

{

( * ( void ( * ) ( ) ) 0 ) ( );

//调用0地址处的函数,该函数无参,返回类型是void

//1.void (*) () - 函数指针类型;//void (*p) () - 函数指针变量

//2.( void (*) () ) 0 - 对0进行强制类型转换,被解释为一个函数地址

//3. *( void (*) () ) 0 - 对0地址进行解引用操作

//4.( * ( void ( * ) ( ) ) 0 ) ( ); - 调用0地址处的函数

return 0;

}

//题二

void (* signal(int, void (*) (int) ) ) (int); 

//简化理解:void (*) (int) signal(int, void (*) (int));

//1.signal先和()结合,说明signal是函数名

//2.signal函数的第一个参数类型是int,第二个参数类型是函数指针

//该函数指针,指向一个参数为int,返回类型是void的函数

//3.signal函数的返回类型也是一个函数指针

//该函数指针,指向一个参数为int,返回类型是void的函数


五、函数指针数组 

//函数指针数组

//存放函数指针的数组

int add(int x,int y)
{return x+y;
}
int sub(int x, int y)
{return x - y;
}
int main()
{int (*pf1)(int, int) = add;int (*pf2)(int, int) = sub;int (*pfArr[2])(int, int) = {add,sub}; //pfArr是函数指针数组return 0;
}

int arr[5];

int (*p1)[5] = &arr; //p1是指针,指向整形数组的指针

int* arr[5];

int* (*p2)[5] = &arr; //p2是指针,指向【整型指针数组】的指针

int (*p)(int,int) //p是指针,函数指针

int (*p2[5])(int,int) //p2与[5]先结合,是数组,函数指针数组

int (*(*p3)[5])(int,nit) = &p2; //取出的是函数指针数组的地址

//p3是一个指向【函数指针数组】的指针


六、回调函数 

6.1 定义

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
void menu()
{printf("1.add  2.sub\n");printf("0.exit\n");
}
int add(int a, int b)
{return a + b;
}
int sub(int a, int b)
{return a - b;
}
//回调函数
int calc(int(*pf)(int,int))
{printf("请输入两个数字");int x = 0;int y = 0;scanf_s("%d %d",&x,&y);return pf(x,y);
}
int main()
{int input = 0;do {menu();int ret = 0;printf("请选择:");scanf_s("%d",&input);switch (input){case 1:ret = calc(add);printf("ret=%d\n", ret);break;case 2:ret = calc(sub);printf("ret=%d\n", ret);break;case 0:break;default:printf("输入错误,请重新选择\n");}} while (input);return 0;
}

 七、指针练习

C指针练习题-CSDN博客

C指针sizeof()、strlen()练习题详解-CSDN博客

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

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

相关文章

Windows安装SSH详细教程

目录 第一章:SSH简介与概念 1.1 什么是SSH? 1.2 SSH的作用 1.3 SSH的特点 1.4 SSH的应用场景 第二章:安装OpenSSH客户端 2.1 下载OpenSSH客户端 2.2 安装OpenSSH客户端 2.3 验证安装结果 第三章:配置SSH客户端 3.1 设置SSH配置文件 3.2 生成SSH密钥对 3.3 配置…

PCL点云处理之M估计样本一致性(MSAC)平面拟合(二百三十六)

PCL点云处理之M估计样本一致性(MSAC)平面拟合(二百三十五六) 一、算法介绍二、使用步骤1.代码2.效果一、算法介绍 写论文当然用RANSAC的优化变种算法MSAC啊,RANSAC太土太LOW了哈哈 MSAC算法(M-estimator Sample Consensus)是RANSAC(Random Sample Consensus)的一种…

Python入门级题目及答案

前言&#xff1a; 学习Python作为一门编程语言是非常有必要的&#xff0c;因为Python简单易学&#xff0c;功能强大&#xff0c;应用广泛。在本篇博客中&#xff0c;我们将提供八道Python入门级的题目&#xff0c;每道题目都伴有详细的描述和对应的答案代码。通过完成这八道题目…

Linux系统使用Docker部署Portainer结合内网穿透实现远程管理容器和镜像

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Tickeys for Mac:让每一次敲击都充满乐趣,提升打字体验新高度!

Tickeys for Mac 是一款为 macOS 设计的虚拟键盘音效生成器。它通过模拟机械键盘的声音&#xff0c;为打字和输入操作增添了音效反馈&#xff0c;让用户在使用电脑时感受到更加真实的键盘反馈体验。用户可以根据个人喜好选择不同类型的键盘声音和音效设置&#xff0c;让键盘操作…

带你充分理解并掌握 vue3 的 setup 用法

在 Vue 3 中,setup 函数是 Composition API 的入口点,它提供了一种新的方式来组织和复用逻辑。setup 函数是在组件的生命周期钩子 created 之前执行的,它允许开发者在组件创建时定义响应式状态、计算属性、方法和生命周期逻辑。 基本用法 setup 函数返回一个对象,该对象的…

因子处理:/n*2-1:一个简单的标准化方法

在计算因子时候经常会使用到 rank排序&#xff0c;既将序列转换为顺序&#xff1a; s1 pd.Series([0.1,5,0.6,0.8,0.2,9]) s2 s1.rank() print(s1) print(s2)output&#xff1a; 0 0.1 1 5.0 2 0.6 3 0.8 4 0.2 5 9.0 dtype: float64 0 1.0 1 5.0 2…

【Python基础篇】那些年错过的Python

随着OpenAI的发展&#xff0c;Python的重要性不言而喻。不知你是否和我一样&#xff0c;不知道曾经说过多少次我要学Python&#xff0c;都没有执行起来… 近期我在知识库中更新了一波Python教程&#xff0c;选取了这一篇分享给大家。 前言 很多时候我们需要让程序变成交互性的…

实现DevOps需要什么?

实现DevOps需要什么&#xff1f; 硬性要求&#xff1a;工具上的准备 上文提到了工具链的打通&#xff0c;那么工具自然就需要做好准备。现将工具类型及对应的不完全列举整理如下&#xff1a; 代码管理&#xff08;SCM&#xff09;&#xff1a;GitHub、GitLab、BitBucket、SubV…

Notepad++:格式化json字符串(带转义)

目录 一、效果呈现 二、去除json字符串转义 三、格式化json字符串 一、效果呈现 格式化前 带字符串转义&#xff0c;带unicode编码字符 格式化后 二、去除json字符串转义 方法&#xff1a;采用Notepad的普通替换 第一&#xff1a;\"替换为" 第二&#xff1a;\\…

函数模板详解

大家好&#xff1a; 衷心希望各位点赞。 您的问题请留在评论区&#xff0c;我会及时回答。 一、函数模板 C另一种编程思想为&#xff1a;泛型编程&#xff0c;主要利用的技术就是模板。 C提供两种模板机制&#xff1a;函数模板、类模板 函数模板语法 函数模板作用&#xff…

有意义还是有意思?

人生苦短&#xff0c;有意思可能比有意义更重要。有意思多好玩啊&#xff0c;追逐那些有意思的事&#xff0c;才能真正顺从内心的选择。有意思的事通常都很小&#xff0c;也许找到有意思的事&#xff0c;本身就是一种幸福。 日常生活中&#xff0c;如果总在探究什么样的事情有意…

Python6:Socket编程初步学习笔记

Socket协议概要 创建socket的时候&#xff0c;需要一些选项来说明本次使用协议具体是什么&#xff0c;常用的两个&#xff1a; 由此产生的不同组合&#xff1a; 但目前TCP(IPV4)是主流&#xff0c;SOCK_STREAMAF_INET 创建和使用Socket socket模块中有socket类&#xff1a…

QMT量化策略实盘(一)下单函数passorder

第一篇量化实盘的分享&#xff0c;从一定绕不开的综合下单函数passorder说起。 用于股票、期货、期权等下单和新股、新债申购、融资融券等交易操作。&#xff08;对比ptrade就不支持期货交易&#xff09; 这个函数功能很全&#xff0c;同时参数也比较多&#xff0c;在初次使用…

方格分割(蓝桥杯)

文章目录 方格分割题目描述答案&#xff1a;509思路dfs 方格分割 题目描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 6x6的方格&#xff0c;沿着格子的边线剪开成两部分。 要求这两部分的形状完全相同。 如下就是三…

用html画一个烟花特效

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>烟花特效</title><link rel"stylesheet" href"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/fontawesom…

vue3从其他页面跳转页面头部组件菜单el-menu菜单高亮

主要代码 import { ref, onMounted, watch } from vue; const activeIndex ref("/"); const route useRoute();onMounted(() > {updateActiveMenu(); });watch(() > route.path, updateActiveMenu);function updateActiveMenu() {// 根据路由更新activeMenu…

【vue3学习笔记(一)】vue3简介;使用vue-cli创建工程;使用vite创建工程;分析工程结构;安装开发者工具

尚硅谷Vue2.0Vue3.0全套教程丨vuejs从入门到精通 对应课程136-140节 课程 P136节 《vue3简介》笔记 课程 P137节 《使用vue-cli创建工程》笔记 官方文档&#xff1a; https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create官方文档地址 查看vue-cli版本&#x…

git配置密钥

要配置 Git 密钥&#xff0c;可以按照以下步骤进行操作&#xff1a; 1.生成密钥&#xff1a;首先&#xff0c;在终端或命令提示符中运行以下命令生成密钥对&#xff1a; ssh-keygen -t rsa -b 4096 -C "dengweng-pulse.net"这将生成一个 RSA 密钥对&#xff0c;其中…

课堂行为动作识别数据集

一共8884张图片 xml .txt格式都有 Yolo可直接训练 已跑通 动作类别一共8类。 全部为教室监控真实照片&#xff0c;没有网络爬虫滥竽充数的图片&#xff0c;可直接用来训练。以上图片均一一手工标注&#xff0c;标签格式为VOC格式。适用于YOLO算法、SSD算法等各种目标检测算法…