C语言函数

目录

一、函数的概念

二、头文件

三、库函数

四、自定义函数

五、return语句

1. return语句的基本用法

2. return语句在函数中的作用

3. return语句的使用场景

4. return语句的注意事项

5. 示例代码

 六、C语言中数组作为函数参数

1. 数组作为函数参数的基本概念

2. 传递一维数组

3. 传递多维数组

4. 注意事项

5. 结论

七、C语言中的嵌套调用和链式访问

1. 嵌套调用

2. 链式访问

3. 结论

八、函数的声明与定义

 函数声明

        函数定义

单个文件中的函数

多个文件中的函数

static和extern关键字

          static关键字

          extern关键字

总结


一、函数的概念

        在C语言中,函数是一段用于执行特定任务的代码,它可以被重复调用,有助于代码的模块化和重用。

        C语言中的函数分为两类:

  1. 库函数:这些函数是编译器提供的,比如printf()scanf()getchar()putchar()等。它们提供了输入/输出、字符串操作、数学计算等基本服务。

  2. 用户定义函数:这些函数是由程序员根据需要自己定义的。

二、头文件

        在C语言中,头文件是包含函数声明、宏定义、类型定义和变量声明等内容的文件,它们以.h为文件扩展名。头文件允许你在多个源文件中共享公共的代码片段,这样可以提高代码的可重用性和可维护性。

头文件的主要作用是:

  1. 函数声明:头文件中包含了库函数的声明,这样你可以在源文件中使用这些函数而不必重新定义它们。

  2. 宏定义:宏是一些预处理器指令,它们在编译前由预处理器进行处理。头文件中可以定义宏,以便在多个源文件中共享。

  3. 类型定义:头文件中可以定义新的类型,这些类型可以在多个源文件中使用。

  4. 变量声明:虽然不推荐在头文件中声明全局变量,但有时你可能需要在多个源文件中共享一些全局变量,这时可以在头文件中声明它们。

头文件的使用通常分为两类:

  1. 标准头文件:这些是C语言标准库提供的头文件,例如stdio.hstdlib.hstring.h等。这些头文件通常位于编译器的标准库目录中,你可以使用#include <头文件名>来包含它们。

  2. 用户定义的头文件:这些是程序员自己创建的头文件,用于组织项目中的公共代码。

三、库函数

        C语⾔标准中规定了C语⾔的各种语法规则,C语⾔并不提供库函数;C语⾔的国际标准ANSI C规定了⼀ 些常⽤的函数的标准,被称为标准库,那不同的编译器⼚商根据ANSI提供的C语⾔标准就给出了⼀系列 函数的实现。这些函数就被称为库函数。

        简单来说,库函数是预先编写好的、可重用的代码块,它们通常被组织成库,可以在程序中直接调用。在C语言中,库函数是扩展语言功能的重要组成部分。使用库函数可以减少程序员的工作量,提高开发效率,并确保代码的稳定性和可靠性。

        C语言标准库提供了一系列的函数,这些函数被分为多个头文件,每个头文件包含了相关功能的函数声明。要使用这些库函数,你需要在C程序中包含对应的头文件。

以下是一些常用的C语言标准库头文件及其提供的功能:

  1. stdio.h:提供标准输入输出功能,如printf()scanf()getchar()putchar()fopen()fclose()等。

  2. stdlib.h:提供通用工具函数,如内存分配(malloc()calloc()realloc()free())、程序控制(exit()system())、随机数生成(rand()srand())等。

  3. string.h:提供字符串处理函数,如strcpy()strcat()strlen()strcmp()memset()memcpy()等。

  4. math.h:提供数学计算函数,如三角函数(sin()cos()tan())、指数和对数函数(exp()log()pow())、平方根(sqrt())等。

  5. ctype.h:提供字符处理函数,如判断字符类型(isalpha()isdigit()isspace())、字符转换(tolower()toupper())等。

  6. time.h:提供时间和日期处理函数,如time()asctime()clock()difftime()等。

  7. assert.h:提供断言宏assert(),用于在调试过程中检查条件是否为真。

  8. errno.h:提供错误码定义,用于处理系统调用和库函数的错误。

  9. float.h:提供浮点数的限制和特性信息。

  10. limits.h:提供整型的限制信息。

  11. stdarg.h:提供变量参数处理功能,用于编写可变参数的函数。

        要使用这些库函数,你需要在C程序中包含对应的头文件,并链接相应的库。大多数C编译器都会自动链接标准库,但如果你使用了其他库,可能需要显式地指定链接命令。

举个例子,如果我想要使用printf函数,这时候我们就会包含对应的头文件

#include <stdio.h>

int main() {
    printf("Hello, World!\n");
    return 0;
}

         #include <stdio.h>命令告诉预处理器包含标准输入输出库的头文件,这样我们就可以在程序中使用printf()函数了。

C 标准库头文件 - cppreference.com

        库函数是在标准库中对应的头⽂件中声明的,所以库函数的使⽤,务必包含对应的头⽂件,不包含是可能会出现⼀些问题的。库函数类型功能多样,使用之前需要对函数规定和使用进行了解,并留意其中的头文件。

四、自定义函数

        库函数的丰富,让我们在编写的时候能够方便我们调用和维护,但是最开始这些函数没有被定义的时候,又是怎么使用这些函数的呢?

        这时候我们的英雄就闪亮登场了----自定义函数。

        自定义函数的出现,大大解锁了函数出场的姿态,用户可以自定义自己的函数来执行特定的任务,从而提高代码的可重用性、模块性和可维护性。

        在下面的代码中,我们定义了一个函数,即接受两个整型参数,并返回它们的和

#include <stdio.h>

// 函数声明
int add(int a, int b);

int main() {
    int sum = add(3, 4); // 函数调用
    printf("The sum is: %d\n", sum);
    return 0;
}

// 函数定义
int add(int a, int b) {
    int result = a + b;
    return result;
}

在这个例子中:

  • add函数的声明告诉编译器这个函数接受两个int类型的参数,并返回一个int类型的值。
  • add函数的定义提供了函数的具体实现。在这个例子中,它只是简单地将两个参数相加并返回结果。
  • main函数中,我们调用了add函数,并将结果存储在sum变量中,然后打印出来。

        需要注意的是,函数声明和函数定义中的参数名称可以不同,但参数类型必须相同。

        我们不妨再来看一起例子,怎么用C语言计算两个数的公约数,在了解这个之前,我们要先了解什么是公约数的算法,或者说怎么定义这个公约数。

欧几里得算法的步骤如下:

  1. 假设有两个正整数a和b(假设a > b),我们想要找到它们的最大公约数。

  2. 用较大的数a除以较小的数b,得到余数r(0 ≤ r < b)。

  3. 将较小的数b和得到的余数r作为新的一对数。

  4. 重复步骤2和3,直到余数为0。当余数为0时,较小的数就是原始两个数的最大公约数。

#include <stdio.h>

// 函数声明
int gcd(int a, int b);

int main() {
    int num1, num2, result;

    printf("Enter two integers: ");
    scanf("%d %d", &num1, &num2);

    result = gcd(num1, num2); // 函数调用

    printf("The GCD of %d and %d is %d\n", num1, num2, result);

    return 0;
}

// 函数定义
int gcd(int a, int b) {
    // 欧几里得算法
    while (b != 0) {
        int temp = b;
        b = a % b;
        a = temp;
    }
    return a;
}

 在编写这个函数的时候,我们对gcd采用非递归的方法,我们在这里提供一种递归实现

int gcd(int a, int b) {
    if (b == 0) {
        return a;
    } else {
        return gcd(b, a % b);
    }
}

        在这两个例子中,我们对函数定义的形式可以做一个总结,首先我们声明函数返回值的类型,也就是我们最开始的哪一个整型int,之后对函数进行命名,而括号中放入的是形式参数,被花括号括起来的就是函数体

        我们可以把函数想象成⼩型的⼀个加⼯⼚,⼯⼚得输⼊原材料,经过⼯⼚加⼯才能⽣产出产品,那函数也是⼀样的,函数⼀般会输⼊⼀些值(可以是0个,也可以是多个),经过函数内的计算,得出结果。

        • 最开始的整型int是⽤来表⽰函数计算结果的类型,有时候返回类型可以是 void ,表⽰什么都不返回。

         • 函数的参数就相当于,⼯⼚中送进去的原材料,函数的参数也可以是 void ,明确表⽰函数没有参 数。如果有参数,要交代清楚参数的类型和名字,以及参数个数。

        • {}括起来的部分被称为函数体,函数体就是完成计算的过程。

再定义一个函数的时候,我们会发现一个有趣的现象

int hanshu(int a, int b) 
{
    return 0;
}

        这里的a和b作为形式参数,也就是只有形式没有含义,如果我们在后面对函数进行赋值操作,这时候的形式参数将会转变为实际参数,这个转变的过程称为形参的实例化。但是需要注意,是形参和实参各⾃是独⽴的内存空间。

        什么意思呢?我们来看一起例子

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int Add(int x, int y)
{
	int z = 0;
	z = x + y;
	return z;
}
int main()
{
	int a = 0;
	int b = 0;
	//输⼊
	scanf("%d %d", &a, &b);
	//调⽤加法函数,完成a和b的相加
	//求和的结果放在r中
	int r = Add(a, b);
	//输出
	printf("%d\n", r);
	return 0;
}

        将a=5,b=6

        那么调试结果为 

五、return语句

        在C语言编程中,return语句是一个非常重要的组成部分,它在函数执行过程中扮演着至关重要的角色。return语句主要用于从函数中返回一个值,并在执行过程中终止函数的执行。

1. return语句的基本用法
return expression;
  • 无返回值:在不需要返回值的情况下(例如在void类型的函数中),return语句可以单独使用,不跟任何表达式。

2. return语句在函数中的作用
  • 返回结果:在带有返回类型的函数中(如intfloatchar等),return语句用于将计算结果或状态信息返回给调用者。

  • 终止函数:一旦return语句被执行,当前函数的执行立即终止。这意味着return之后的任何代码都不会被执行。

3. return语句的使用场景
  • 结束函数:在达到某个条件或完成某个任务后,使用return语句结束函数的执行。

  • 错误处理:在检测到错误或异常情况时,可以使用return语句返回一个错误码或特殊值。

  • 提前返回:在某些情况下,如果函数的某些条件不满足,可以提前使用return语句退出函数。

4. return语句的注意事项
  • 返回类型匹配:返回的值类型必须与函数声明的返回类型相匹配。如果函数声明为返回int类型,则return语句不能返回其他类型的值。

  • 单一返回点:虽然C语言允许函数中有多个return语句,但有些编程风格推荐尽量保持函数只有一个出口点,以提高代码的可读性和可维护性。

  • 空返回值:在void类型的函数中,return语句可以单独使用,表示函数执行完毕,但没有返回值。

5. 示例代码

        下面是一个简单的例子,演示了return语句的使用:

​
#include <stdio.h>

int add(int a, int b) {
    return a + b; // 返回两个整数的和
}

int main() {
    int result = add(3, 4); // 调用add函数并接收返回值
    printf("The sum is: %d\n", result);
    return 0; // main函数返回0,表示程序正常结束
}

​

        在这个例子中,add函数使用return语句返回两个整数的和,而main函数则接收这个返回值并打印出来。

 六、C语言中数组作为函数参数

        在C语言中,数组是一种非常灵活的数据结构,常用于存储大量数据。在函数编程中,数组经常被用作函数参数,以便于传递和操作数据集合。本文将详细探讨如何将数组作为函数参数,以及这样做时需要注意的一些关键点。

1. 数组作为函数参数的基本概念
  • 数组名作为参数:在C语言中,当数组作为函数参数时,实际上传递的是指向数组首元素的指针。这意味着在函数内部无法直接知道数组的大小。

  • 指针与数组:由于数组的传递实际上是通过指针完成的,因此函数原型中可以使用指针类型来接收数组参数。

2. 传递一维数组
  • 声明函数:当函数需要接收一维数组作为参数时,可以在参数列表中使用数组类型。例如,int myFunction(int arr[])

    • 示例代码:

      ​
      #include <stdio.h>
      
      void printArray(int arr[], int size) {
          for (int i = 0; i < size; i++) {
              printf("%d ", arr[i]);
          }
          printf("\n");
      }
      
      int main() {
          int numbers[] = {1, 2, 3, 4, 5};
          int size = sizeof(numbers) / sizeof(numbers[0]);
          printArray(numbers, size); // 传递数组及其大小
          return 0;
      }
      
      ​

              在这个例子中,printArray函数接收一个整数数组和一个表示数组大小的整数。函数通过循环打印数组中的每个元素。

3. 传递多维数组
  • 声明函数:传递多维数组时,只需对除第一维之外的其他所有维度指定大小。例如,对于二维数组int arr[10][20],在函数参数中可以声明为int myFunction(int arr[][20])

    • 示例代码:

      ​
      #include <stdio.h>
      
      void printMatrix(int arr[][3], int rows) {
          for (int i = 0; i < rows; i++) {
              for (int j = 0; j < 3; j++) {
                  printf("%d ", arr[i][j]);
              }
              printf("\n");
          }
      }
      
      int main() {
          int matrix[3][3] = {
              {1, 2, 3},
              {4, 5, 6},
              {7, 8, 9}
          };
          printMatrix(matrix, 3); // 传递二维数组及其行数
          return 0;
      }
      
      ​

              在这个例子中,printMatrix函数接收一个二维整数数组和一个表示行数的整数。函数通过两层循环打印数组中的每个元素。

4. 注意事项
  • 数组大小:由于函数无法直接知道数组的大小,因此在传递数组时通常需要显式传递数组的大小。

  • 指针操作:在函数内部,数组参数被视为指针。因此,对数组参数的任何操作都相当于对指针的操作。

  • 修改数组:由于传递的是指针,函数内部对数组的修改将影响原始数组。

5. 结论

        在C语言中,将数组作为函数参数是一种常见且有效的做法。通过这种方式,可以轻松地在函数之间传递大量数据,同时保持代码的整洁和高效。理解数组作为参数的传递方式,以及如何正确地在函数中使用这些数组,对于C语言编程来说是非常重要的

七、C语言中的嵌套调用和链式访问

1. 嵌套调用

        嵌套调用是指在一个函数执行过程中调用另一个函数。

  • 示例代码

    ​
    #include <stdio.h>
    
    void functionB() {
        printf("Function B is called.\n");
    }
    
    void functionA() {
        printf("Function A starts.\n");
        functionB(); // 嵌套调用
        printf("Function A ends.\n");
    }
    
    int main() {
        functionA();
        return 0;
    }
    
    ​

            在这个例子中,functionA在执行过程中调用了functionBfunctionB执行完毕后,控制权返回到functionA

2. 链式访问

        链式访问是一种连续调用多个函数的模式,其中每个函数的返回值作为下一个函数的参数。

  • 示例代码

    ​
    #include <stdio.h>
    
    struct Calculator {
        int value;
        struct Calculator* add(int val) {
            this->value += val;
            return this;
        }
        struct Calculator* subtract(int val) {
            this->value -= val;
            return this;
        }
    };
    
    int main() {
        struct Calculator calc;
        calc.value = 10;
        calc.add(5).subtract(2); // 链式访问
        printf("The result is: %d\n", calc.value);
        return 0;
    }
    
    ​

            在这个例子中,Calculator结构体有两个方法:addsubtract。每个方法都对value进行操作,并返回结构体本身。这样就可以连续调用多个方法。

3. 结论

        嵌套调用和链式访问是C语言中重要的函数交互模式。嵌套调用允许函数之间相互调用,有助于任务的分解。链式访问则提供了一种连续调用多个函数的方法。理解这两种模式对于C语言编程来说是非常有帮助的。

八、函数的声明与定义

 函数声明

                函数声明(Function Declaration)是告诉编译器函数的名称、返回类型和参数类型的过程。它不包含函数体,只是提供了函数的接口。声明通常出现在函数定义之前,以便在函数调用时,编译器能够识别函数的参数和返回类型。

​
int add(int a, int b); // 函数声明

​
        函数定义

                        函数定义(Function Definition)提供了函数的实际主体,包括返回类型、参数列表和执行的具体代码。函数可以在声明之后定义,也可以在声明的同时定义。

​
int add(int a, int b) {
    return a + b;
}

​

单个文件中的函数

        在单个文件中,函数的声明和定义通常更为直接。你可以先声明函数,然后定义它们,或者直接定义函数(在这种情况下,定义本身就充当了声明)。编译器在编译单个文件时能够轻易地识别这些函数。

多个文件中的函数

        在多个文件的项目中,情况变得稍微复杂。假设你有一个函数在文件a.c中定义,但在文件b.c中调用。为了使b.c中的代码能够正确识别a.c中的函数,你需要创建一个头文件(比如func.h),在其中声明这些函数,然后在b.c中包含这个头文件。

​
// func.h
int add(int a, int b);

// a.c
#include "func.h"
int add(int a, int b) {
    return a + b;
}

// b.c
#include "func.h"
int main() {
    int result = add(3, 4);
    return 0;
}

​

static和extern关键字

          static关键字

       static关键字在C语言中有多种用途,但在这里我们关注它在函数中的作用。当static用于函数定义时,它使得该函数在编译单元内部可见。这意味着该函数只能在定义它的文件内被调用,其他文件即使包含了声明,也无法调用这个函数。

​
// a.c
static int add(int a, int b) {
    return a + b;
}

​
          extern关键字

        extern关键字用于声明一个变量或函数,它的定义在其他文件中。当你有一个在多个文件中使用的函数时,你可以在每个需要调用该函数的文件中使用extern声明,以便编译器知道这个函数在其他地方定义。

​
// func.h
extern int add(int a, int b);

// a.c
#include "func.h"
int add(int a, int b) {
    return a + b;
}

// b.c
#include "func.h"
int main() {
    int result = add(3, 4);
    return 0;
}

​

总结

        在C语言中,函数的声明和定义是构建程序逻辑的关键。在单个文件中,这些操作相对简单。但在多个文件的项目中,需要使用头文件来声明函数,并使用staticextern关键字来控制函数的可见性和链接。正确使用这些概念,可以编写出结构清晰、易于维护的代码。

  • 34
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值