【重拾C语言】九、再论函数(指针、数组、结构体作参数;函数值返回指针、结构体;作用域)

news2024/10/5 5:30:53

目录

前言

九、再论函数

9.1 参数

9.1.1 参数的传递规则

9.1.2 指针作参数

9.1.3 数组作参数

9.1.4 结构体作参数

a. 直接用结构体变量作函数参数

b. 用指向结构体变量的指针作函数参数

9.2 函数值

9.2.1 返回指针值

9.2.2 返回结构体值

a. 返回结构体值

b. 返回结构体指针

9.3 作用域

9.3.1 局部量和全局量

9.3.2 作用域

a. 文件作用域(全局作用域)

b. 函数作用域

c. 块作用域

d. 函数原型作用域

e. 代码示例


前言

【重拾C语言】五、模块化程序设计——函数(定义、调用、参数传递、结果返回、函数原型;典例:打印字符图形、验证哥德巴赫猜想)_QomolangmaH的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_63834988/article/details/133580009?spm=1001.2014.3001.5501        前文介绍了函数的基础知识,包括如何定义函数、函数的调用形式和过程、函数结果的返回以及函数原型的使用等。本文将再论函数,主要介绍指针、数组、结构体等作参数;函数值返回指针、结构体,以及C语言作用域相关知识。

九、再论函数

9.1 参数

9.1.1 参数的传递规则

        C语言只有一种参数类别——值参。值参意味着:

  • 参数要求:赋值兼容
  • 形实结合:
    • 计算实参表达式的值;
    • 把实参值按赋值转换规则,转换成形参的类型;
    • 把转换后的实参值送入形参变量中。
  • 执行函数:
    • 值参表示形参本身,它是函数内的一个局部变量,已经与实参脱离关系(无关)了。在函数内对形参的赋值不影响实参。
  • 结束返回:  实参值无任何变化,还是调用函数之前的值。
#include <stdio.h>

void square(int num) {
    num = num * num;  // 修改形参的值
    printf("Inside the function: %d\n", num);
}

int main() {
    int number = 5;
    printf("Before the function call: %d\n", number);
    square(number);  // 调用函数并传递实参
    printf("After the function call: %d\n", number);
    
    return 0;
}

9.1.2 指针作参数

        一般意义上,如果函数的形参是指针类型,对应调用时,相应实参也应是指针类型表达式

#include <stdio.h>

void square(int *num) {
    *num = (*num) * (*num);  // 修改形参指针所指向的值
    printf("Inside the function: %d\n", *num);
}

int main() {
    int number = 5;
    printf("Before the function call: %d\n", number);
    square(&number);  // 调用函数并传递实参的地址
    printf("After the function call: %d\n", number);
    
    return 0;
}

输出:

        使用指针作为形参来传递实参的地址。在函数内部,通过解引用指针并修改指针所指向的值,实现了对实参的修改。

9.1.3 数组作参数

        在C语言中,数组名实际上是一个指针,表示数组首元素的地址。因此,当将数组名作为实参传递给函数时,实际上传递的是数组名的指针值。

        在函数调用时,数组名作为实参传递给函数的形参,只传递了数组名的值,也就是数组的首地址。函数内部并不会为形参开辟数组的存储空间,而只会为形参开辟一个指针变量的空间,用于存储传递进来的实参数组的地址。

#include <stdio.h>

void printArraySize(int arr[]) {
    printf("Size of the array inside the function: %lu\n", sizeof(arr));
    for (int i = 0; i < 5; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main() {
    int array[] = {1, 2, 3, 4, 5};
    printf("Size of the array in the main function: %lu\n", sizeof(array));
    printArraySize(array);

    return 0;
}

输出:

        将数组array作为实参传递给printArraySize函数,可以看到,在printArraySize函数内部,sizeof(arr)的结果是8(64位系统上),而不是数组的实际大小。这是因为在函数调用过程中,只传递了数组名的指针值,而不是整个数组的值。

        如上述代码所示,数组作为形参时,可以省略数组形式参数最外层的尺寸

错误示例:

void printMatrix(int matrix[][], int rows)
void printMatrix(int matrix[3][], int rows)
void printMatrix(int matrix[3][][3], int rows)

正确示例:

#include <stdio.h>

void printMatrix(int matrix[][3], int rows) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%d ", matrix[i][j]);
        }
        printf("\n");
    }
}

int main() {
    int matrix[][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
    int rows = sizeof(matrix) / sizeof(matrix[0]);
    
    printf("Matrix elements in the main function:\n");
    printMatrix(matrix, rows);
    
    return 0;
}

9.1.4 结构体作参数

a. 直接用结构体变量作函数参数
#include <stdio.h>

struct Point {
    int x;
    int y;
};

void printPoint(struct Point p) {
    printf("Point coordinates: (%d, %d)\n", p.x, p.y);
}

int main() {
    struct Point point = {3, 5};

    printf("Point coordinates in the main function:\n");
    printPoint(point);

    return 0;
}
  • Point结构体,包含两个整型成员变量xy
  • printPoint函数,接收一个Point类型的结构体作为参数,并在函数内部打印结构体的坐标值。
  • main函数中,创建一个名为pointPoint结构体变量,并初始化其xy成员变量的值。然后,调用printPoint函数,将point作为参数传递给它。
  • 输出:

b. 用指向结构体变量的指针作函数参数
#include <stdio.h>

struct Point {
    int x;
    int y;
};

void printPoint(struct Point* p) {
    printf("Point coordinates: (%d, %d)\n", p->x, p->y);
}

int main() {
    struct Point point = {3, 5};

    printf("Point coordinates in the main function:\n");
    printPoint(&point);

    return 0;
}
  • printPoint函数,接收一个指向Point类型结构体的指针作为参数
  • main函数中,调用printPoint函数,将&pointpoint的地址)作为参数传递给它
  • 输出结果与方法a相同:

9.2 函数值

9.2.1 返回指针值

        函数可以返回指针作为其返回值,这样可以在函数外部访问函数内部创建的变量或数据。

        函数返回类型不允许是数组类型和函数类型、共用体类型,除此之外允许一切类型, 当然允许指针类型,带回指针值的函数的函数定义说明符形式是:

类型名 *函数名( 形参列表 )
#include <stdio.h>

int* getArray() {
    static int arr[] = {1, 2, 3, 4, 5};
    return arr;
}

int main() {
    int* ptr = getArray();
    
    for (int i = 0; i < 5; i++) {
        printf("%d ", *(ptr + i));
    }
    
    return 0;
}

输出:

9.2.2 返回结构体值

        函数的计算结果可能是一个结构体值。在C语言中,有两种途径能够把该结构体值通过函数名字带回到主调函数。

a. 返回结构体值
  • 函数的结果类型是结构体类型
  • 直接把一个结构体值带回调用函数的主程序
#include <stdio.h>

struct Point {
    int x;
    int y;
};

struct Point createPoint(int x, int y) {
    struct Point point;
    point.x = x;
    point.y = y;
    return point;
}

int main() {
    struct Point p = createPoint(3, 4);
    
    printf("Point coordinates: (%d, %d)\n", p.x, p.y);
    
    return 0;
}

b. 返回结构体指针
  • 函数的结果类型是指向结构体类型变量的指针类型
#include <stdio.h>
#include <stdlib.h>

struct Point {
    int x;
    int y;
};

struct Point* createPoint(int x, int y) {
    struct Point* point = malloc(sizeof(struct Point));
    point->x = x;
    point->y = y;
    return point;
}

int main() {
    struct Point* p = createPoint(3, 4);
    
    printf("Point coordinates: (%d, %d)\n", p->x, p->y);
    
    free(p);
    
    return 0;
}
  • 函数createPoint()接受两个参数,并动态分配内存来创建一个Point类型的结构体变量。然后,它将给定的坐标值分配给结构体的成员,并返回指向该结构体的指针。
  • main()函数中,调用createPoint()函数来创建一个Point结构体,并使用指针访问结构体的成员来打印坐标值。最后,使用free()函数释放了动态分配的内存,以避免内存泄漏。

9.3 作用域

9.3.1 局部量和全局量

  • 局部变量(Local Variables)是在函数内定义的变量,包括形参。它们的作用范围限定在所属的函数内部。另外,定义在复合语句内部的变量的作用范围则限定在该复合语句内部。
  • 全局变量(Global Variables)则是在函数以外定义的变量,它们不从属于任何特定的函数。全局变量的作用范围从定义处开始,一直延伸到整个源文件的结束,包括各个函数。
#include <stdio.h>

// 全局变量
int globalVariable = 10;

void myFunction()
{
    // 局部变量
    int localVar = 20;
    
    printf("局部变量:%d\n", localVar);
    printf("全局变量:%d\n", globalVariable);
}

int main()
{
    myFunction();
    
    // 尝试访问局部变量和全局变量
    // 这里不能访问局部变量localVar,会导致编译错误
    printf("全局变量:%d\n", globalVariable);
    
    return 0;
}

9.3.2 作用域

        作用域是指在程序中标识符有效的区域。在C语言中,每个源程序编译单位(例如源文件),每个函数定义、函数原型以及复合语句都构成一个作用域区域。在一个标识符的作用域内,可以使用该标识符,并且使用的是相应声明的标识符。这意味着在不同的作用域中可以使用相同名称的标识符,因为它们处于不同的作用域,互相之间不会产生冲突。

a. 文件作用域(全局作用域)

        在函数之外定义的标识符具有文件作用域,它们在整个源文件中可见,在文件中的任何位置都可以使用这些标识符。

b. 函数作用域

        在函数内部定义的标识符具有函数作用域,它们只在函数内部可见,在函数外部无法使用这些标识符。

c. 块作用域

        在复合语句(代码块)内部定义的标识符具有块作用域,它们只在该代码块内可见。当代码块执行完毕后,其中定义的标识符就不再可见。

d. 函数原型作用域

        函数原型中声明的标识符具有函数原型作用域,它们只在函数原型所在的作用域中可见。函数原型作用域主要用于函数声明中的参数。

e. 代码示例
#include <stdio.h>

// 文件作用域(全局作用域)
int globalVariable = 10;

void function1()
{
    // 函数作用域
    int localVariable = 20;
    printf("Local variable: %d\n", localVariable);
    printf("Global variable: %d\n", globalVariable);
}

void function2()
{
    // 函数作用域
    int localVariable = 30;
    printf("Local variable: %d\n", localVariable);
    printf("Global variable: %d\n", globalVariable);
}

int main()
{
    // 块作用域
    {
        int blockVariable = 40;
        printf("Block variable: %d\n", blockVariable);
    }

    function1();
    function2();

    return 0;
}

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

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

相关文章

高效防汛决策:山海鲸可视化系统助力城市防洪

随着全球气候的变化&#xff0c;自然灾害如洪水、台风等频发&#xff0c;防范洪水成为城市管理者和居民们亟待解决的重要问题。 洪水的威胁 洪水是自然界的杀手之一&#xff0c;不仅会造成大量的财产损失&#xff0c;还可能危害人们的生命安全。因此&#xff0c;预测、监测和有…

自我监督学习日志

学习日志 10.12 一天学不了一分钟&#xff0c;不知道为什么也就是了 今天一定要学一个小时&#xff01; 机器学习就是机器帮我们找一个函数 语音辨识&#xff0c;语音&#xff0c;声音讯号 转化为文字 帮我们找一个人类写不出来的复杂函数 类神经网络 输入 一张图片用一个矩…

2023-10-12 LeetCode每日一题(找出数组的串联值)

2023-10-12每日一题 一、题目编号 2562. 找出数组的串联值二、题目链接 点击跳转到题目位置 三、题目描述 给你一个下标从 0 开始的整数数组 nums 。 现定义两个数字的 串联 是由这两个数值串联起来形成的新数字。 例如&#xff0c;15 和 49 的串联是 1549 。 nums 的 串…

不容易解的题10.10

5.最长回文子串 5. 最长回文子串 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/longest-palindromic-substring/?envTypelist&envIdZCa7r67M给一个字符串&#xff0c;让我们找最长回文子串 这题不用说&#xff0c;回文子串那一定是连续的&#…

【Node.js】路由

基础使用 写法一&#xff1a; // server.js const http require(http); const fs require(fs); const route require(./route) http.createServer(function (req, res) {const myURL new URL(req.url, http://127.0.0.1)route(res, myURL.pathname)res.end() }).listen…

Java从resources文件下载文档,文档没有后缀名

业务场景&#xff1a;因为公司会对excel文档加密&#xff0c;通过svn或者git上传代码也会对文档进行加密&#xff0c;所以这里将文档后缀去了&#xff0c;这样避免文档加密。 实现思路&#xff1a;将文档去掉后缀&#xff0c;放入resources下&#xff0c;获取输入流&#xff0…

12V手电钻保护板如何接线演示

爱做手工的小伙伴们肯定会用到手电钻&#xff0c;那么电池消耗完了&#xff0c;或要换的&#xff0c;或要自己动手做几个备用电源&#xff0c;关键点就是电路保护板的接线。废话不多说&#xff0c;直接上板子看实操。 文章目录 一、线路板图1、输入接线2、输出接线 二、接线方法…

java学习笔记001

java基础 java语言特点 面向对象&#xff0c;强类型&#xff0c;跨平台&#xff0c;解释型 基本概念&#xff08;JVM、JRE、JDK&#xff09; JVM java虚拟机 作用&#xff1a;加载.class文件 JRE Java运行环境 JREJVMJava系统类库 JDK Java开发工具包 JDKJRE编译&a…

英语——方法篇——单词——谐音法+拼音法——50个单词记忆

theatre&#xff0c;剧场&#xff0c;太后th吃eat热re食物&#xff0c;就去剧场了 loud dolphin&#xff0c;做do脸皮厚plh在。。。里 humid&#xff0c;hu湖mi米d的 blender&#xff0c;b爸lend借给er儿。 tragedy&#xff0c;tr土人

笔训【day4】

目录 选择题 1、进制 格式 2、 数组名在&和sizeof后&#xff0c;表数组本身 3、求二维数组某元素地址 ​编辑 ​编辑 4、x x & (x-1) 二进制位1的个数 ​编辑 5、斐波那契递归次数 编程题 1、计算糖果 2、进制转换 选择题 1、进制 格式 十进制转二进制就除…

ARM-day9作业

main.c: #include "uart.h"#include "key_it.h"int main(){char c;char *s;uart4_init(); //串口初始化//中断初始化key_it_config();key3_it_config();//完成GPIO相关初始化all_led_init();//风扇初始化fs_init();//蜂鸣器初始化fmq_init();while(1){…

只有线上出了bug,老板们才知道测试的价值?

有同学说&#xff0c;测试没价值&#xff0c;我们测试团队刚被拆散了。 也有同学说&#xff0c;公司不重视测试&#xff0c;我觉得我们就是测试得太好了。哪天线上出个bug&#xff0c;老板们就知道测试的价值了。 还有人给测试同学规划职业发展路径&#xff0c;就是不做测试&…

C语言 —— 操作符

1. 操作符的分类 算术操作符: - * / % 移位操作符: << >> 位操作符: & | ^ 赋值操作符: - 单目操作符 关系操作符 逻辑操作符 条件操作符 逗号表达式 下标引用、函数调用和结构成员 2. 算术操作符 - * / % 注意 /操作符: 对于整型的除法运算结果依然是整数…

十六、代码校验(2)

本章概要 前置条件 断言&#xff08;Assertions&#xff09;Java 断言语法Guava 断言使用断言进行契约式设计检查指令前置条件后置条件不变性放松 DbC 检查或非常严格的 DbCDbC 单元测试 前置条件 前置条件的概念来自于契约式设计(Design By Contract, DbC), 利用断言机制…

JavaWeb---Servlet

1.Srvlet概述 Servlet是运行在java服务器端的程序&#xff0c;用于接收和响应来着客户端基于HTTP协议的请求 如果想实现Servlet的功能&#xff0c;可以通过实现javax。servlet。Servlet接口或者继承它的实现类 核心方法&#xff1a;service&#xff08;&#xff09;&#xf…

vue七牛云视频直传

完成后样式&#xff1a; 下面的代码是我自己项目里面用到的&#xff0c;一些判断看自己情况去掉&#xff0c;用的是element-ui组件 安装 uuid 库。你可以使用 npm 或 yarn 来完成安装。在终端中执行以下命令&#xff1a; npm install uuidhtml部分 <el-upload class&quo…

海外接单被没收百万收入并处以罚款,承德的这位程序员到底做了什么?

相信在接单圈混的程序员最近都听说了吧&#xff0c;承德的一位程序员因为翻墙接单被没收了105.8万的收入&#xff0c;还被处了10万的罚款&#xff0c;事件一出瞬间登上了热搜并在接单圈广为传播&#xff0c;如果你还没有听说过&#xff0c;也不用担心&#xff0c;现在我就先来给…

webmin远程命令执行漏洞

文章目录 漏洞编号&#xff1a;漏洞描述&#xff1a;影响版本&#xff1a;利用方法&#xff08;利用案例&#xff09;&#xff1a;安装环境漏洞复现 附带文件&#xff1a;加固建议&#xff1a;参考信息&#xff1a;漏洞分类&#xff1a; Webmin 远程命令执行漏洞&#xff08;CV…

python:使用卷积神经网络(CNN)进行回归预测

作者:CSDN @ _养乐多_ 本文详细记录了从Excel或者csv中读取用于训练卷积神经网络(CNN)模型的数据,包括多个自变量和1个因变量数据,以供卷积神经网络模型的训练。随后,我们将测试数据集应用于该CNN模型,进行回归预测和分析。 该代码进一步修改可用于遥感影像回归模型. …

CentOS7 NTP客户端的时间同步详解

需求&#xff1a;在CentOS7下配置NTP客户端时间同步服务 简介&#xff1a; NTP服务是为了时钟同步使用&#xff0c;特别在一些实时性数据库场景中非常重要。 Centos7下默认使用chronyd服务代替过渡ntpd服务&#xff0c;因此经常遇到大部分人还是记住ntpd服务而不去配置chronyd服…