C语言:指针进阶

news/2024/4/27 12:45:07/文章来源:https://blog.csdn.net/weixin_45930573/article/details/137017566

一、字符指针

	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.luyixian.cn/news_show_1026545.aspx

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

相关文章

mysql基础1sql分类

mysql基础 [rootvm ~]# docker run -itd -p 3306:3306 -e "MYSQL_ROOT_PASSWORD123456" mysql:5.7.26通用语法 1). SQL语句可以单行或多行书写&#xff0c;以分号结尾。 2). SQL语句可以使用空格/缩进来增强语句的可读性。 3). MySQL数据库的SQL语句不区分大小写…

【软考】UML中的图之状态图

目录 1. 说明2. 图示 1. 说明 1.状态图&#xff08;State Diagram&#xff09;展现了一个状态机。2.由状态、转换、事件和活动组成。3.关注系统的动态视图。4.对于接口、类和协作的行为建模尤为重要。5.强调对象行为的事件顺序。6.通常包括简单状态和组合状态、转换&#xff0…

Django之Celery篇(二)

一、Celery-任务的调用 1.1、异步任务调用 delay( )方法 from celery_task import *def delay():rs = send_email.delay(baizhan)print(rs.id)rs2 = send_msg.delay(SXT)print(rs2.id)1.2、定时任务调用 apply_async( )方法 from celery_task import * import datetimedef …

网络编程之流式套接字

流式套接字&#xff08;SOCK_STREAM&#xff09;是一种网络编程接口&#xff0c;它提供了一种面向连接的、可靠的、无差错和无重复的数据传输服务。这种服务保证了数据按照发送的顺序被接收&#xff0c;使得数据传输具有高度的稳定性和正确性。通常用于那些对数据的顺序和完整性…

Docker部署一个SpringBoot项目(超级详细)

注意&#xff1a;下面的教程主要是针对 Centos7 的&#xff0c;如果使用的其他发行版会有细微的差别&#xff0c;请查看官方文档。 Docker部署一个SpringBoot项目&#xff08;超级详细&#xff09; 一、安装Docker1.卸载旧版2.配置Docker的yum库3.安装Docker4.设置开机自启动5.…

Cornflakes: Zero-Copy Serialization for Microsecond-Scale Networking——论文泛读

SOSP 2023 Paper 论文阅读笔记整理 问题 数据序列化对于许多数据中心应用程序来说至关重要&#xff0c;序列化的主要开销在于数据移动&#xff0c;将应用程序数据移动到数据包中所需的内存拷贝成本高昂。最近的零拷贝API暴露了NIC分散收集功能&#xff0c;增加了将数据移动卸…

短视频矩阵系统--技术3年源头迭代

短视频矩阵系统核心技术算法主要包括以下几个方面&#xff1a; 1. 视频剪辑&#xff1a;通过剪辑工具或API从各大短视频平台抓取符合要求的视频。这些视频通常符合某些特定条件&#xff0c;如特定关键词、特定时间段发布的视频、视频点赞评论转发等数据表现良好的视频。 2. 视…

每日一题 --- 209. 长度最小的子数组[力扣][Go]

长度最小子数组 题目&#xff1a; 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的 连续 子数组 [numsl, numsl1, ..., numsr-1, numsr] &#xff0c;并返回其长度**。**如果不存在符合条件的子数组&#xff0c…

深度学习项目-基于深度学习的股票价格预测研究

概要 随着经济的发展&#xff0c;中国股票市场的规模持续扩大&#xff0c;早已成为金融投资的重要部分&#xff0c;掌握股票市场的变化规律无论是对监管者还是投资者都具有极其重要的意义。正因如此&#xff0c;人们不断探索着股票市场的变化规律&#xff0c;其中使用深度学习预…

知行之桥EDI系统功能介绍——FlatFile 端口介绍

FlatFile 端口能够实现平面文件与XML文件的互相转换。 每个 Flat File 端口配置一个特定的平面文件格式&#xff0c;从而实现与 XML 格式的互相转换。Flat File 端口有两个主要的模式&#xff1a; Position DelimitedCharacter Delimited 对于 Position Delimited 平面文件&a…

V R社交平台的用处|虚拟现实体验馆加盟|V R设备在线价格

VR&#xff08;虚拟现实&#xff09;社交平台的用处可以体现在以下几个方面&#xff1a; VR社交平台不仅可以丰富用户的社交体验&#xff0c;还可以在教育、艺术、商务等领域发挥重要作用&#xff0c;为用户提供更加多样化、互动性强的社交平台体验。 VR游乐设备|VR娱乐设备|VR…

CleanMyMac X 4.15.1 for Mac 最新中文破解版 系统优化垃圾清理工具

CleanMyMac X for Mac 是一款功能更加强大的系统优化清理工具&#xff0c;相比于 CleanMyMac 4.15.1来说&#xff0c;功能增加了不少&#xff0c;此版本为4.15.1官方最新中英文正式破解版本&#xff0c;永久使用&#xff0c;解决了打开软件崩溃问题&#xff0c;最新版4.15.1版本…

微信开发者工具创建一个小程序

创建项目 对于上面这个AppID可以自行选择是注册还是测试号&#xff0c;我是使用的测试号&#xff0c;之后再下面选择模板&#xff0c;我这里选择了JS-基础模板。 进入项目后在模拟器中可看到如下页面&#xff1a; 添加提交按钮进行页面跳转 添加需要跳转的文件夹&#xff0c;…

Leetcode 3.25

LeetCode Hot 100 栈1.有效的括号2.最小栈3.字符串解码 栈 1.有效的括号 有效的括号 这道题肯定是利用了栈先入后出的特性。有以下几种情况 如果当前元素是左括号则push进栈不弹出&#xff1b; 如果当前元素是右括号则弹出栈中前一个元素&#xff0c;并判断是否与当前元素匹配…

http模块—http请求练习

题目要求&#xff1a;搭建如下http服务&#xff1a; 1.当浏览器向我们的服务器发送请求时&#xff0c;当请求类型是get请求&#xff0c;请求的url路径地址是/login。响应体结果是登录页面 2.当浏览器向我们的服务器发送请求时&#xff0c;当请求类型是get请求&#xff0c;请求…

ubuntu 首次登录mysql8 未设置密码或忘记密码解决方法 亲测可用

-1.首先输入以下指令&#xff1a; sudo cat /etc/mysql/debian.cnf2. 再输入以下指令&#xff1a; mysql -u debian-sys-maint -p //注意! //这条指令的密码输入是输入第一条指令获得的信息中的 password ZCt7QB7d8O3rFKQZ 得来。 //请根据自己的实际情况填写&#xff01;运…

QT文件读写操作和内容提取

访问IO设备&#xff0c;需要先调用open()来设置正确的OpenMode(例如ReadOnly或ReadWrite) 打开设备后后&#xff0c;使用write() 或putChar() 写入数据到文件和设备&#xff0c;并通过调用read()&#xff0c;readLine() 或readAll() 进行读取&#xff1b;使用完设备后&#xf…

离线数仓(八)【DWD 层开发】

前言 1、DWD 层开发 DWD层设计要点&#xff1a; &#xff08;1&#xff09;DWD层的设计依据是维度建模理论&#xff08;主体是事务型事实表&#xff08;选择业务过程 -> 声明粒度 -> 确定维度 -> 确定事实&#xff09;&#xff0c;另外两种周期型快照事实表和累积型…

【自我提升】一、Hyperledger Fabric 概念梳理

写在前面&#xff1a;最近因为业务需要&#xff0c;开始学习Hyperledger Fabric了&#xff0c;做java全栈工程师可真难搞。现在算是啥类型的都在涉及了&#xff0c;现在这个技术啥都不懂&#xff0c;就先开个学习专栏&#xff0c;记录记录。顺带也给各位道友参考参考。 目录 …

【Bug】记录2024年遇到的Bug以及修复方案

--------------------------------------------------------分割线 2024.3.22------------------------------------------------------- 1、load_sample_image raise AttributeError(“Cannot find sample image: %s” % image_name) AttributeError: Cannot find sample imag…