c语言:摆脱对指针的恐惧【4】

news2024/12/25 0:34:53

  在上一期指针我们讲到了二级指针是的作用是存放一级指针的地址,还讲了指针数组是一个可以存放若干个指针变量的数组,这里我们再复习一下,下面指针数组是什么意思?

int* arr1[10]; //整形指针的数组
char *arr2[4]; //一级字符指针的数组
char **arr3[5];//二级字符指针的数组

上面三行代码都分别定义了一个数组,第一行代码的arr1数组存放了10个int类型的指针变量 ,第二行代码的arr2数组存放了4个字符类型的指针变量,第三行代码的arr3数组存放了三个二级字符类型的变量,复习完上一期学过的内容,我们马上开始这一期内容的学习吧。

数组指针

数组指针是指针还是数组呢,答案是,它是一个指针,一个指向数组的指针。

我们已经熟悉:  

整形指针: int * pint; 能够指向整形数据的指针。

浮点型指针: float * pf ; 能够指向浮点型数据的指针。
那数组指针应该是:能够指向数组的指针。
下面代码哪个是数组指针?
int *p1[10];
int (*p2)[10];
//p1, p2分别是什么?

解释:

int (*p)[10];
//解释:p先和*结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个指针,指
向一个数组,叫数组指针。
//这里要注意:[]的优先级要高于*号的,所以必须加上()来保证p先和*结合。

&数组名vs数组名 

假设我们定义一个数组:

int arr[10];

我们知道,arr表示这个数组的首元素地址,通常用于函数调用时的传址调用和把它赋给指针变量,以便指针可以访问该数组,那&arr是什么意思呢,也是首元素的地址吗?我们来看一段代码:

#include <stdio.h>
int main()
{
 int arr[10] = {0};
 printf("%p\n", arr);
 printf("%p\n", &arr);
 return 0;
}

运行结果如下:

 

从次代码的运行结果来看它们似乎是一样的,难道它们真的一样吗?再看一段代码:

 

在不进行任何运算时,它们的结果是一样的,然而在进行加一也就是向前走一步时,它们的结果却不一样,且整整相差了 40个字节,所以我们也能发现,虽然arr和&arr虽然值时一样的,但是它们表示的一样却是不同的。

实际上: &arr 表示的是 数组的地址 ,而不是数组首元素的地址。(细细体会一下)
本例中 &arr 的类型是: int(*)[10] ,是一种数组指针类型
数组的地址 +1 ,跳过整个数组的大小,所以 &arr+1 相对于 &arr 的差值是 40。

数组指针的使用

那么数组指针是怎么使用的呢?

既然数组指针指向的是数组,那数组指针中存放的应该是数组的地址。
看代码:
#include <stdio.h>
int main()
{
 int arr[10] = {1,2,3,4,5,6,7,8,9,0};
 int (*p)[10] = &arr;//把数组arr的地址赋值给数组指针变量p
 //但是我们一般很少这样写代码
 return 0;
}
一个数组指针的使用:
#include <stdio.h>
void print_arr1(int arr[3][5], int row, int col)
{
 int i = 0;
 int j = 0;
 for(i=0; i<row; i++)
 {
 for(j=0; j<col; j++)
 {
 printf("%d ", arr[i][j]);
 }
 printf("\n");
 }
}
void print_arr2(int (*arr)[5], int row, int col)
{
 int i = 0;
 int j = 0;
 for(i=0; i<row; i++)
 {
 for(j=0; j<col; j++)
 {
 printf("%d ", arr[i][j]);
 }
 printf("\n");
 }
}
int main()
{
 int arr[3][5] = {1,2,3,4,5,6,7,8,9,10};
 print_arr1(arr, 3, 5);
 //数组名arr,表示首元素的地址
 //但是二维数组的首元素是二维数组的第一行
 //所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
 //可以数组指针来接收
 print_arr2(arr, 3, 5);
 return 0;
}

我们想让程序输出arr中的所有元素,常见的方法是创建一个函数,用一个数组来接收,完成打印,而在我们学到数组指针优以后我们发现数组指针也可以完成二维数组的接收和打印,所以两个函数打印的是相同的内容,让我们运行程序试试:

结果完全相同,学了指针数组和数组指针我们来一起回顾并看看下面代码的意思:

int arr[5];
int *parr1[10];
int (*parr2)[10];
int (*parr3[10])[5];

数组指针、指针参数

在写代码的时候难免要把【数组】或者【指针】传给函数,那函数的参数该如何设计呢?

一维数组传参

#include <stdio.h>
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?
{}
int main()
{
 int arr[10] = {0};
 int *arr2[20] = {0};
 test(arr);
 test2(arr2);
}

上面的几种函数参数设计都可以吗,是的,我们可以用数组接收数组首元素地址,也可以用指针接收数组首元素地址,我们可以用指针数组来接收指针数组首元素的地址,也可以用二级指针来接收指针数组首元素的地址,因为指针数组的首元素是一个一级指针,而一级指针的地址就必须用二级指针来储存,所以以上test函数的参数设计都是可以的。

二位数组传参

void test(int arr[3][5])//ok?
{}
void test(int arr[][])//ok?
{}
void test(int arr[][5])//ok?
{}
//总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。
//因为对一个二维数组,可以不知道有多少行,但是必须知道一列多少元素。
//这样才方便运算。
void test(int *arr)//ok?
{}
void test(int* arr[5])//ok?
{}
void test(int (*arr)[5])//ok?
{}
void test(int **arr)//ok?
{}
int main()
{
 int arr[3][5] = {0};
 test(arr);
}

一级指针传参

#include <stdio.h>
void print(int *p, int sz)
{
 int i = 0;
 for(i=0; i<sz; i++)
 {
 printf("%d\n", *(p+i));
 }
}
int main()
{
 int arr[10] = {1,2,3,4,5,6,7,8,9};
 int *p = arr;
 int sz = sizeof(arr)/sizeof(arr[0]);
 //一级指针p,传给函数
 print(p, sz);
   return 0;
}

思考:当一个函数的参数部分为指针时,函数能接收什么样的参数?

比如:

void test1(int *p)
{}
//test1函数能接收什么参数?
void test2(char* p)
{}
//test2函数能接收什么参数?

答案是:test1可以接收一个int类型数组的首元素地址,也可以接收一个int类型变量的地址,同样,test2可以接收一个char类型数组的首元素地址,也可以接收一个char类型变量的地址。

二级指针传参

#include <stdio.h>
void test(int** ptr)
{
 printf("num = %d\n", **ptr); 
}
int main()
{
 int n = 10;
 int*p = &n;
 int **pp = &p;
 test(pp);
 test(&p);
  return 0;
}

思考:当函数的参数为二级指针的时候,可以接收什么参数?

void test(char **p)
{
 
}
int main()
{
 char c = 'b';
 char*pc = &c;
 char**ppc = &pc;
 char* arr[10];
 test(&pc);
 test(ppc);
 test(arr);//Ok?
  return 0;
}

答案是:当函数的参数为二级指针时,可以接收一个一级指针的地址,也可以接收一个指针数组的首元素地址。

函数指针

首先看一段代码:
#include <stdio.h>
void test()
{
 printf("hehe\n");
}
int main()
{
 printf("%p\n", test);
 printf("%p\n", &test);
 return 0;
}

输出的结果:

当我们把一个函数名test和&test分别打印时。

输出的是两个地址,这两个地址是 test 函数的地址。 那我们的函数的地址要想保存起来,怎么保存? 下面我们
看代码:
void test()
{
 printf("hehe\n");
}
//下面pfun1和pfun2哪个有能力存放test函数的地址?
void (*pfun1)();
void *pfun2();

首先,能存储地址,就要求pfun1或pfun2是指针,那哪个是指针呢?答案是:

pfun1 可以存放。 pfun1 先和 * 结合,说明 pfun1 是指针,指针指向的是一个函数,指向的函数无参数,返回值类型为void。
未完待续。。。。。。

 

 

 

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

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

相关文章

JavaSE——集合框架二(1/6)-前置知识-可变参数、Collections工具类

目录 可变参数 Collections工具类 Collections的常用静态方法 实例演示 可变参数 可变参数 就是一种特殊形参&#xff0c;定义在方法、构造器的形参列表里&#xff0c;格式是&#xff1a;数据类型...参数名称 可变参数的特点和好处 特点&#xff1a;可以不传数据给它&am…

常用API(正则表达式、爬取、捕获分组和非捕获分组 )

1、正则表达式 练习——先爽一下正则表达式 正则表达式可以校验字符串是否满足一定的规则&#xff0c;并用来校验数据格式的合法性。 需求&#xff1a;假如现在要求校验一个qq号码是否正确。 规则&#xff1a;6位及20位之内&#xff0c;0不能在开头&#xff0c;必须全部是数字…

超详细的前后端实战项目(Spring系列加上vue3)前端篇+后端篇(三)(一步步实现+源码)

好了&#xff0c;兄弟们&#xff0c;继昨天的项目之后&#xff0c;开始继续敲前端代码&#xff0c;完成前端部分&#xff08;今天应该能把前端大概完成开启后端部分了&#xff09; 昨天补充了一下登录界面加上了文章管理界面和用户个人中心界面 完善用户个人中心界面 修改一…

【被小学生教育的一天】

今日文章有感&#xff0c;记博主文章&#x1f4dd;&#xff0c;分享与感触。原文如下&#xff0c; 今天让小学生给我上了一课啊&#xff0c;今天去一所学校就实地考察感触特别深啊&#xff0c;就我从里面抽取一小块啊&#xff0c;给大家看一下&#xff0c;这个学校的教学规划&a…

STM32中断编程入门

文章目录 一、 理论部分1.中断系统2.中断执行流程3.NVIC的基本结构4.EXTI介绍5.AFIO复用IO口 二、实验目的&#xff1a;学习stm32中断原理和开发编程方法。使用标准完成以下任务&#xff1a;&#xff08;一&#xff09;实验一 开关控制LED的亮灭1.代码部分2.运行结果 &#xff…

SpringBoot+Vue开发记录(七)-- 跨域文件与Restful风格

本篇文章的主要内容是关于项目的跨域配置和给项目添加restful风格接口。 重点是文件粘贴 文章目录 一、 跨域二、Restful风格1. 什么是restful风格&#xff1f;2. 项目文件结构3. 新建文件4. 在Controller中进行修改 一、 跨域 跨域问题暂时也就那样&#xff0c;解决方法就是…

【搜索方法推荐】高效信息检索方法和实用网站推荐

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

AI视频教程下载:ChatGPT API、HTML、CSS 和 JS开发AI聊天机器人

在课程中,你将开启一段令人兴奋的聊天机器人开发之旅,并装备自己创建智能对话代理所需的技能和知识。 利用 ChatGPT API、HTML、CSS 和 JavaScript 的强大功能,你将学习如何设计和构建吸引用户并提供个性化体验的聊天机器人界面。深入探讨聊天机器人开发的基础知识,了解对话设…

【Docker学习】深入研究命令docker exec

使用docker的过程中&#xff0c;我们会有多重情况需要访问容器。比如希望直接进入MySql容器执行命令&#xff0c;或是希望查看容器环境&#xff0c;进行某些操作或访问。这时就会用到这个命令&#xff1a;docker exec。 命令&#xff1a; docker container exec 描述&#x…

AI网络爬虫-自动获取百度实时热搜榜

工作任务和目标&#xff1a;自动获取百度实时热搜榜的标题和热搜指数 标题&#xff1a;<div class"c-single-text-ellipsis"> 东部战区台岛战巡演练模拟动画 <!--48--></div> <div class"hot-index_1Bl1a"> 4946724 </div> …

OpenAI撤回有争议的决定:终止永久性非贬损协议

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

HTML静态网页成品作业(HTML+CSS+JS)——心理健康教育介绍网页(4个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;使用Javacsript代码使用下拉菜单的实现以及首页图片的轮播&#xff0c…

ESP32烧录AT固件并进行MQTT通讯

首先下载AT固件 发布的固件 - ESP32 - — ESP-AT 用户指南 latest 文档 下载烧录工具 下载指导 - ESP32 - — ESP-AT 用户指南 latest 文档 烧录后注意usb的串口是不能发AT指令的 需要用16和17脚 用AT指令确认OK后连WIFI ATCWMODE1 //设置客户端模式 ATCWLAP …

CV大作业28期-使用TensorFlow快速实现图像风格迁移系统

使用TensorFlow快速实现图像风格迁移系统 资源地址&#xff1a;待更新 视频地址&#xff1a;待更新 随着GPT的横空出世&#xff0c;生成式网络也越来越活&#xff0c;现在的大语言模型除了能回答文字上面的内容&#xff0c;并且在图像和视频创作中也表现除了巨大的潜力&#xf…

Websocket助手

功能介绍 WS助手是WebSocket调试的开发工具&#xff0c;该客户端工具可以帮助开发人员快速连接到测试/生产环境&#xff0c;它可以帮助您监视和分析 Websocket 消息&#xff0c;并在开发过程中解决问题&#xff1b;可以模拟客户端实现与服务器的数据交互&#xff0c;并完成批量…

【DZ模板】克米设计APP手机版本地化+完美使用

模版介绍 【DZ模板】价值288克米设计APP手机版DZ模板 数据本地化完美使用 腾讯官方出品discuz论坛DIY的后台设置&#xff0c;功能齐全&#xff0c;论坛功能不亚于葫芦侠&#xff0c;自定义马甲&#xff0c;自定义认证&#xff0c;自定义广告&#xff0c;完全可以打造出自己想…

面试大杂烩之kafka

面试这个领域最近环境不行&#xff0c;所以卷起来流量挺大 关于K8s 其实看我之前的博客&#xff0c;k8s刚有点苗头的时候我就研究过&#xff0c;然后工作的时候间接接触 也自己玩过 但是用的不多就忘记了&#xff0c;正苦于不知道写什么&#xff0c;水一篇 用来面试应该是够了…

【设计模式】JAVA Design Patterns——Static Content Hosting(静态内容托管模式)

&#x1f50d;目的 将静态内容部署到基于云的存储服务&#xff0c;该服务可以将它们直接交付给客户端。 这可以减少对昂贵计算实例的需求。 &#x1f50d;解释 真实世界例子 全球性的营销网站&#xff08;静态内容&#xff09;需要快速的部署以开始吸引潜在的客户。为了将托管…

Weblogic XML反序列化漏洞 [CVE-2017-10271]

漏洞环境搭建请参考 http://t.csdnimg.cn/i11e2 漏洞原理 Weblogic的wls security组件对外提供webservice服务&#xff0c;wls security组件使用了xmldecoder来解析用户传入的xml数据&#xff0c;如果用户进行xml恶意数据的构造&#xff0c;即可触发反序列化漏洞 漏洞版本 O…

LLMs之PEFT之Llama-2:《LoRA Learns Less and Forgets LessLoRA学得更少但遗忘得也更少》翻译与解读

LLMs之PEFT之Llama-2&#xff1a;《LoRA Learns Less and Forgets LessLoRA学得更少但遗忘得也更少》翻译与解读 导读&#xff1a;该论文比较了LoRA与完全微调在代码与数学两个领域的表现。 背景问题&#xff1a;微调大规模语言模型需要非常大的GPU内存。LoRA这一参数高效微调方…