C 语言基础 -- 函数/指针/结构体

news2024/9/20 17:01:03

本文介绍指针、函数和结构体

粉丝福利, 免费领取C/C++ 开发学习资料包、技术视频/项目代码,1000道大厂面试题,内容包括(C++基础,网络编程,数据库,中间件,后端开发/音视频开发/Qt开发/游戏开发/Linuxn内核等进阶学习资料和最佳学习路线)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

1、函数

函数定义包含了四个部分:返回类型、函数名、参数列表、函数体。

创建一个函数时,必须指定函数头作为函数定义的第一行,跟着是这个函数放在大括号内的执行代码,称为函数体。函数头定义了函数的名称、形参和返回值类型。一般形式如下:

RetureType FunctionName(Parameters - separated by commas) {
  // statements;
}

将大括号及其内存用分号代替,如下所示

RetureType FunctionName(Parameters - separated by commas);

称为函数声明,也称为函数原型。定义了函数的名称、返回值类型和形参列表(参数个数以及顺序)。

参数个数可变的函数

标准库 <stdarg.h> 提供了编写这种函数的工具。在参数列表后添加省略号 ... 可以指定参数个数可变的函数(参数列表中至少需要一个固定的参数)。如下所示:

double average(double v1, double v2, ...) {
  // statements;
}

<stdarg.h> 头文件提供了解析可变参数相关的宏定义,分别是 va_start()、va_arg() 和 va_end()。第一个宏的形式如下:

void va_start(va_list parg, last_fixed_arg);

这个宏的名称来源于 variable argument start。这个函数接收两个参数:va_list 类型的指针 parg 和函数指定的最后一个固定参数的名称。va_list 类型也在 <stdarg.h> 头文件中定义,用于存储支持可变参数列表所需的信息。

在调用 va_start() 初始化 parg 后,然后可以调用 va_arg() 函数解析可变参数。va_arg() 的第一个参数是通过调用 va_start() 初始化的变量 parg,第二个参数是期望解析的参数类型。va_arg() 函数返回 parg 指定的当前参数值,同时更新 parg 指针,指向列表的下一个参数。当参数解析完成,va_arg() 函数返回 0。然后调用 va_end() 处理收尾工作,它将 parg 重置为 NULL。如果省掉这个调用,程序就不会正常工作。

例如,average 函数可以定义为:

double average(double v1, double v2, ...) {
 va_list parg;
 double sum = v1 + v2;
 double value = 0.0;
 int count = 2;

 va_start(parg, v2);
 while((value = va_arg(parg, double)) != 0.0) {
   sum += value;
   ++count;
}
 va_end(parg);
 return sum / count;
}

有时需要多次处理可变参数列表,va_copy() 可以复制 va_list 类型变量 parg。

va_list parg_copy;
va_copy(parg_copy, parg);

2、指针

基本概念

指针也是一种变量,其存储的是其所指变量的地址。如图所示,指针 pnumber 保存另一个变量 number 的地址(起始地址)。

但是只知道变量 pnumber 是一个指针是不够的,更重要的是,编译器必须知道它所指变量的类型。没有这个信息,根本不可能知道所指对象占用多少内存,或者如何处理它所指的内存的内容。每个指针都和某个变量类型相关联,也只能用于指向该类型的变量。

类型名 void 表示没有指定类型,所以 void* 类型的指针可以包含任意类型数据项的地址。类型 void* 常常用做参数类型或者函数返回类型。任意类型的指针都可以传送为 void* 类型的值,在使用它时,再将其转换为合适的类型。

const 与指针

声明指针时,可以使用 const 关键字限定。const 的位置不同,具有不同的含义。

1)const 在 * 号左边,表示指针指向一个常量。

long value = 9999L;
const long *pvalue = &value;

无法通过 pvalue 指针改变 value 的值,比如

*pvalue = 8888L;

会产生编译错误,但是可以改变 pvalue 的值(指向另外的变量)

long number = 8888L;
pvalue = &number;

另外,const 和 long 关键字的顺序没有关系,如下方式也可以声明指向常量的指针:

long const *pvalue = &value;

2)const 在 * 右边,表示指针为常量类型,限定指针的值不能被修改(不能指向其他的变量),如下所示:

int count = 43;
int *const pcount = &count;

数组与指针

数组名可以隐士转换为指针,表示数组的第一个元素的地址。但是数组不是指针,它们有一个重要的区别:可以改变指针包含的地址,但不能改变数组名引用的地址。

另外,数组名代表的并不是数组的地址,尽管两者都指向同一地址,但是指针运算完全不同。比如:

char chs[10];
printf("%x %x\n", chs, &chs);
printf("%x %x\n", chs + 1, &chs + 1);

输出为

0x60fee6 0x60fee6
0x60fee7 0x60fef0

可以看到,chs + 1 指向下一个字节的地址,而 &chs + 1 指向了下 10 个字节的地址。因为 chs 是长度为 10 的字符数组,&chs 类型不再是 char*。可以使用 typedef 简化数组的定义

typedef char TenCharArray[10];
TenCharArray chs;

chs 可以隐式地转换为 char* 指针类型,但是 &chs 为 TenCharArray* 指针类型。

多维数组中,名称和指针之间的差异更为明显,例如定义如下二维数组

char board[3][3] = {
                     {'1', '2', '3'},
                     {'4', '5', '6'},
                     {'7', '8', '9'},
                   };

多维数组和它元素(子数组)的关系如下所示

board 引用第一个元素的地址,该元素仍然是一个数组,而 board[0]、board[1] 和 board[3] 引用对应子数组第一个元素的地址。则用多维数组名称访问元素的方式如下所示

指针数组

数组的元素也可以是指针类型,在声明需要注意方法

char *ptr[10] = {NULL};

上述方法声明了一个容量是 10 个 char* 类型的指针数组。[] 操作符的优先级比 * 高,所以 ptr 首先和 [] 操作符结合,表明 ptr 是数组,然后确定元素类型是 char*。

函数指针

函数也可以看作一种变量,也有其对应的指针类型,使用指针也可以操作函数。函数的内存弟子存储了函数开始执行的位置(起始地址),存储在函数指针中的内容就是这个地址。不过,只有地址还不够,还必须指定形参列表以及返回值类型。

函数指针的定义方法如下:

RetureType (*FunctionPtr)(Parameters - separated by commas);

该声明只定义了一个名为 FunctionPtr 的指针变量,不指向任何内容。*FunctionPtr 必须放在括号中,因为 () 操作符具有最高优先级,FunctionPtr 和右边 () 结合,FunctionPtr 就表示函数。

通过函数指针调用函数和函数调用类型,只需要将函数调用时函数名换成函数指针

int sum(int a, int b);
int (*pfun)(int, int) = sum;
int result = pfun(1, 2);

3、结构体

关键字 struct 能定义各种类型的变量集合,成为结构体,并把它们视为一个单元。下面是一个简单声明一个结构体 Horse 的例子:

struct Horse {
  int age;
  int height;
} silver = {
  27, 12
};

Horse 不是一个变量名,而是一个新的数据类型,定义了一个 Horse 类型的变量 silver 并进行初始化。上面的初始化方式需要将初始值以正确的顺序放在大括号中,也可以在初始化列表中指定成名名(可以只指定部分成员的值),如下:

struct Horse trigger = {
  .age = 22, .height = 30
};

结构体内的变量成为成员或字段,通过成员访问运算符 . 访问,例如

silver.age = 12;

不一定要给结构体指定标记符名字,如下例子也是合法的,只不过不能再定义其他变量。

struct {
  int age;
  int height;
} silver;

同样可以定义指向结构体变量的指针,此时用 -> 运算符访问成员。例如

struct Horse* ptr = &sivler;
ptr->age = 20;

结构体也可以在结构体内部声明,以限制作用域,例如

struct Horse {
  struct Date {
    int day;
    int month;
    int year;
  } dob;
  int age;
  int height;
};

位字段机制允许几个成员分别使用某种数据类型的几位,通常是 unsigned int 类型。例如

struct {
  unsigned int flag1 : 1;
  unsigned int flag2 : 1;
  unsigned int flag3 : 2;
  unsigned int flag4 : 3;
} indicators;

4、联合体

联合体和结构体类似,但是各个成员以共享的方式占用同一块内存,而不是像结构体一样各个成员独立占用一块内存。关键字 union 用于定义联合体。例如

union U_example {
  float decval;
  int* pnum;
  double my_value;
} ul;

联合体成员的访问方式和结构体成员完全相同,联合体对象所占的字节数是其最大的成员所占的空间。

5、枚举类型

在编程时,常常希望变量存储一组可能值中的一个,枚举就用于这种情形。利用枚举,可以定义一个新的整数类型,该类型变量的值域是指定的几个可能值。下面语句定义了一个枚举类型 Weekday

enum Weekday {Monday, Tuesday, Wednessday, Thursday, Friday, Saturday, Sunday};

可以给任意或者所有枚举器指定特定的整数值。尽管枚举器使用的名称必须唯一,但枚举器的值不要求是惟一的。未设定指定值的枚举器,其值为前一个的值 +1

粉丝福利, 免费领取C/C++ 开发学习资料包、技术视频/项目代码,1000道大厂面试题,内容包括(C++基础,网络编程,数据库,中间件,后端开发/音视频开发/Qt开发/游戏开发/Linuxn内核等进阶学习资料和最佳学习路线)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

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

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

相关文章

html+css+js网页设计 翘珠宝微商城移动端20个页面

htmlcssjs网页设计 翘珠宝微商城移动端20个页面 网页作品代码简单&#xff0c;可使用任意HTML编辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xff09;。 获取源码 …

ET6框架(十二)ET-EUI基本使用

文章目录 一、下载插件&#xff1a;二、使用插件例子三、使用规则四、公共UI组件五、脚本生成缝隙 ET-EUI是基于ET6.0版本拓展出来的一个套UI框架 一、下载插件&#xff1a; 首先我们需要下载&#xff0c;地址&#xff1a; GitHub - zzjfengqing/ET-EUI: 基于ET框架的UI模块 …

ESRI ArcGIS Pro 3.1.5新功能及安装教程和下载

ESRI ArcGIS Pro 3.1.5 主要新功能包括&#xff1a; 改进的数据编辑和管理&#xff1a;支持更多数据格式和更精细的属性表操作。增强的空间分析工具&#xff1a;新增和优化空间分析工具&#xff0c;提高数据分析效率。更好的3D可视化&#xff1a;改进3D渲染性能&#xff0c;支…

中国艺术孙溟㠭凿篆《无用之用》

孙溟㠭凿篆作品《无用之用》 这方作品是孙溟㠭先生用凿木的方式凿刻出来的&#xff0c;呈现出了凿痕的效果&#xff0c;与众不同。 孙溟㠭凿篆《无用之用》 孙溟㠭凿篆《无用之用》 万般皆有所用&#xff0c;取其长补余短&#xff0c;无用之用是为大用&#xff0…

SAPUI5基础知识25 - 聚合绑定(Aggregation Binding)

1. 背景 Aggregation Binding 是 SAPUI5 中的一种数据绑定方式&#xff0c;用于将数据模型中的集合&#xff08;如数组&#xff09;绑定到 UI 控件的聚合&#xff08;如列表项、表格行等&#xff09;。 常见的场景包括将一个数组绑定到 sap.m.List 的 items 聚合&#xff0c;…

校园转转二手交易市场JAVA系统-幽络源整理免费分享

校园转转二手交易市场JAVA系统&#xff0c;由幽络源精心收集整理&#xff0c;附带详细的功能介绍和部署教程。此系统已经过站长实际测试&#xff0c;功能完备、运行稳定&#xff0c;适合用于校园二手交易平台的搭建。 后台功能介绍 系统设置&#xff1a;全面的系统配置管理功能…

跨部门协作:搭建共享型客服知识库

引言 在当今这个快速变化且高度互联的商业环境中&#xff0c;企业面临的挑战日益复杂多变。为了更有效地服务客户、提升客户满意度&#xff0c;客服团队不仅需要掌握丰富的专业知识&#xff0c;还需要能够快速响应并解决跨领域的问题。然而&#xff0c;单一部门的知识库往往难…

小乌龟运动控制-4两只小乌龟

ROS小乌龟系列文章目录 第一章 小乌龟划圆圈 第二章 小乌龟走方形 第三章 五角星 第四章 两只小乌龟 文章目录 ROS小乌龟系列文章目录前言1、生成第2个乌龟2、实现两只小乌龟一个画圆圈一个画方块运行 前言 ROS 中实现两只小乌龟一个画圆圈一个画方块的代码实现 1、生成第2个…

安装office过程中遇到的一系列问题及解放方案(Windows)

本博文列出安装office过程中遇到的一系列问题及解放方案&#xff08;Windows&#xff09;参考的相关博客&#xff0c;仅供参考。 office下载与安装&#xff1a; 免费装Office2021工具Office Tool Plus使用教程 JH过程中遇到0xC004F074错误&#xff1a; win10 JH 错误代码&a…

pycharm中配置已有的conda环境

背景 之前已通过conda命令创建环境&#xff0c;并安装依赖正常运行程序&#xff0c;现希望在pycharm中进行调试 配置流程 打开pycharm&#xff0c;并打开项目&#xff0c;路径&#xff1a;setting->Project: your_project -> Python Interpreter&#xff0c;点击 Add …

TCP/IP五层模型

目录 一. 概述 1.TCP基础入门 2.TCP数据报结构 3. TCP/IP五层协议模型讲解&#xff1a; 4. 网络设备所在分层​编辑 5. TCP的三次握手 一. 概述 作为一名程序员&#xff0c;对于TCP/IP五层协议&#xff0c;重点掌握应用层和传输层&#xff0c;特别是以下两层对应的协议&a…

国内服务器部署NextChat程序教程

问题描述 NextChat在ChatGPT私人搭建方面广受欢迎&#xff0c;详细的Vercel部署教程建议参考之前的文章《通过NextChat(ChatGPT-Next-Web)低成本给自己或客户部署GPT程序》&#xff0c;在Vercel上部署的方法比较灵活&#xff0c;因为可以自由更改程序内容&#xff0c;所以推荐…

RK3568平台(内存篇)Linux内存管理

一.什么是内存 最直观的,我们买手机,电脑,内存条,都会标明内存是多大,例如途中的8G,16G,128G都指的内存大小。 我们应该都听说过 RAM 存储器,它是一种半导体存储器件。RAM 是英文单词 Random 的缩写,即“随机”的意思。所以 RAM 存储器也称为“随机存储器”。 那么…

Docker续7:docker部署nmt续1:使用haproxy代理nginx

[rootlocalhost ~]# docker stop 30 //停止nginx容器 30 [rootlocalhost ~]# docker ps --all CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS …

【管理】职业规划三叶草

持续更新。。。。。。。。。。。。。。。 【管理】职业规划三叶草 三叶草模型是什么第一片叶子&#xff1a;兴趣&#xff08;Interest&#xff09;第二片叶子&#xff1a;能力&#xff08;Ability&#xff09;第三片叶子&#xff1a;价值&#xff08;Value&#xff09;将三叶草…

【活动预约】镭速邀您莅临2024年行业案例分享专场线下沙龙活动!

​为了加强行业内外渠道集成商及相关生态合作伙伴的交流合作&#xff0c;共同应对数据安全挑战&#xff0c;提升内外网安全交换系统的应用范围及应用效果&#xff0c;镭速即将举办一场不容错过的2024年行业案例分享专场线下沙龙活动&#xff01; 活动亮点 ➣行业前沿&#x…

Spring扩展点系列-InstantiationAwareBeanPostProcessor

文章目录 简介测试一1、配置文件Bean注册2、单元测试方法3、测试类4、输出结果结论 测试二1、测试类2、输出结果结论 源码解析postProcessPropertiesCommonAnnotationBeanPostProcessorAnnotationInjectedBeanPostProcessor 总结 简介 spring容器中Bean的生命周期内所有可扩展…

Apache DolphinScheduler大规模任务调度系统对大数据实时Flink任务支持

转载自神龙大侠 我是用olphinScheduler 3.2.1版本做源代码编译部署&#xff08;部署方式参考我的另外一篇文档《源代码编译&#xff0c;Apache DolphinScheduler前后端分离部署解决方案》&#xff09; 二进制文件部署本文也适用&#xff0c;只需要修改相对应的配置即可。 资…

科普小课堂:中等硬度的床垫,合适的睡姿,通过日常力量练习提升自身能力以支撑脊柱形态。

文章目录 引言I 选择合适床垫的指标3:1 原则睡得舒服与否II 日常力量练习翻书-胸椎活动度练习猫式-脊柱整体活动度练习III 知识扩展人体脊柱“S”型生理曲线软床垫对腰椎的影响硬床垫对腰椎的影响合适的睡姿引言 女性瘦型体型人群脊柱曲线相对较明显,尤其是腰部曲线,需选择承…

优化LabVIEW中TCP通信速度的方法

在LabVIEW中&#xff0c;TCP通信速度较慢可能由多种因素导致&#xff0c;如数据包处理延迟、阻塞式读取或数据解析效率低等。通过调整读取模式、优化数据处理逻辑、以及使用并行处理结构&#xff0c;可以显著提升TCP通信的速度&#xff0c;使其接近第三方调试工具的表现。LabVI…