C语言:函数

这是很基础的教程,我只是写给自己看,作为一个学习笔记记录一下,如果正在阅读的你觉得简单,请不要批评,可以关掉选择离开

如何学好一门编程语言

  • 掌握基础知识,为将来进一步学习打下良好的基础。
  • 上机实践,通过大量的例题学习怎么设计算法,培养解题思路。
  • 养成良好的编码习惯,注释一定要写,要不然保你一周后自己写的代码都不认识了。

函数

  每个 C 程序都至少有一个主函数 main() ,和0个或若干个额外定义的函数。

函数定义

  函数定义提供了函数的实际主体,告诉编译器 函数名返回类型 和 参数 等信息

返回类型 函数名( 参数列表 )
{
   函数主体
}
  • 返回类型:指定函数返回值的数据类型。void 表示没有返回值
  • 函数名:函数的名字
  • 参数:当函数被调用时,向函数传递的值。这个参数可以是变量,也可以是函数,也可以没有参数。没有参数可以不写也可以写 void
  • 函数主体:包含函数执行任务的语句

 return 0 是终止该函数,和 exit(0) 是终止程序。

函数声明

  • 当函数定义在函数调用前 则不需要函数声明
  • 当函数定义在函数调用后 则需要在调用前需要先声明
返回类型 函数名( 参数列表 );

在函数声明中,参数的名称并不重要,只有参数的类型是必需的,因此下面也是有效的声明:

int max(int num1, int num2);
int max(int, int);

调用函数

函数名(实参);            // 无返回 调用函数
返回值 = 函数名(实参);    // 有返回 调用函数

案例:

#include <stdio.h>

int max(int num1, int num2);    /* 函数声明 */

int main () {
    /* 局部变量定义 */
    int a = 100;
    int b = 200;
    int ret;

    /* 调用函数来获取最大值 */
    ret = max(a, b);

    printf( "最大值为 : %d\n", ret );   // 200

    return 0;
}

/* 函数返回两个数中较大的那个数 */
int max(int num1, int num2) {
    /* 局部变量声明 */
    int result;

    if (num1 > num2)
        result = num1;
    else
        result = num2;

    return result;
}

函数传参

函数参数被分为 形参 和 实参;

  • 形参:在函数定义及函数说明时的参数,形参变量只有被调用时才分配内存单元
  • 实参:在函数调用时给出的参数

当调用函数时,有两种向函数传递参数的方式:

位置传参实参和形参的位置必须一一对应

#include <stdio.h>

/* 函数声明 */
void swap(int x, int y);

int main () {
    /* 局部变量定义 */
    int a = 100;
    int b = 200;

    printf("交换前,a 的值: %d\n", a );   // 100
    printf("交换前,b 的值: %d\n", b );   // 200

    /* 调用函数来交换值 */
    swap(a, b);

    printf("交换后,a 的值: %d\n", a );   // 100
    printf("交换后,b 的值: %d\n", b );   // 200

    return 0;
}
/* 函数定义 */
void swap(int x, int y) {
    int temp;

    temp = x; /* 保存 x 的值 */
    x = y;    /* 把 y 赋值给 x */
    y = temp; /* 把 temp 赋值给 y */

    return;
}

关键字传参:按形参的名字给形参赋值,实参名必须与形参名进行匹配,因此实参的顺序和形参的顺序可以不一致。

指针传参:通过指针传递方式,形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作。

#include <stdio.h>

/* 函数声明 */
void swap(int *x, int *y);

int main () {
    /* 局部变量定义 */
    int a = 100;
    int b = 200;

    printf("交换前,a 的值: %d\n", a );   // 100
    printf("交换前,b 的值: %d\n", b );   // 200

    /* 调用函数来交换值
     * &a 表示指向 a 的指针,即变量 a 的地址
     * &b 表示指向 b 的指针,即变量 b 的地址
    */
    swap(&a, &b);

    printf("交换后,a 的值: %d\n", a );  // 200
    printf("交换后,b 的值: %d\n", b );  // 100

    return 0;
}

/* 函数定义 */
void swap(int *x, int *y)
{
    int temp;
    temp = *x;    /* 保存地址 x 的值 */
    *x = *y;      /* 把 y 赋值给 x */
    *y = temp;    /* 把 temp 赋值给 y */

    return;
}

默认情况下,C 使用关键字传参,不能改变调用函数的实际参数,但是用关键字传参,可以改变实际参数。

作用域

  作用域定义变量所存在的区域,超过该区域变量就不能被访问。

局部变量:在函数或块的内部声明的变量。只能被该函数或该代码块内部的语句使用。

全局变量:定义在函数外部,通常是在程序的顶部。全局变量可以被任何函数访问。

注意:在程序中,局部变量和全局变量的名称可以相同,但是在函数内,如果两个名字相同,会使用局部变量值,全局变量不会被使用。

  当局部变量被定义时,系统不会对其初始化,您必须自行对其初始化定义全局变量时,系统会自动对其初始化,如下所示:

数据类型初始化默认值
int 0
char '\0'
float 0
double 0
pointer NULL

正确地初始化变量是一个良好的编程习惯,否则有时候程序可能会产生意想不到的结果

参数

数组传入函数

在函数中传递一个一维数组作为参数,

方式1:形参是一个指针

void myFunction(int *param)
  {...}

方式 2:形参是一个已定义大小的数组

void myFunction(int param[10])
  {...}

方式3:形式参数是一个未定义大小的数组:

void myFunction(int param[])
  {...}

案例

#include <stdio.h>

double getAverage(int arr[], int size); /* 函数声明 */

int main() {
    /* 带有 5 个元素的整型数组 */
    int balance[5] = {1000, 2, 3, 17, 50};
    double avg;

    /* 传递一个指向数组的指针作为参数 */
    avg = getAverage(balance, 5);

    /* 输出返回值 */
    printf("平均值是: %f ", avg);   // 214.400000

    return 0;
}

double getAverage(int arr[], int size) {
    int i;
    double avg;
    double sum = 0;

    for (i = 0; i < size; ++i) {
        sum += arr[i];
    }

    avg = sum / size;

    return avg;
}

函数返回数组

如果您想要从函数返回一个一维数组,您必须声明一个返回指针的函数,

int * myFunction()
  {...} 

案例

补充知识点:C 不支持在函数外返回局部变量的地址,除非定义局部变量为 static 变量。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/* 要生成和返回随机数的函数 */
int *getRandom() {
    static int r[10];
    int i;

    /* 设置种子 */
    srand((unsigned) time(NULL));
    for (i = 0; i < 10; ++i) {
        r[i] = rand();
        printf("r[%d] = %d\n", i, r[i]);
    }
    return r;
}

/* 要调用上面定义函数的主函数 */
int main() {
    int *p; /* 一个指向整数的指针 */
    int i;

    p = getRandom();
    for (i = 0; i < 10; i++) {
        printf("*(p + %d) : %d\n", i, *(p + i));
    }

    return 0;
}
r[0] = 313959809
r[1] = 1759055877
r[2] = 1113101911
r[3] = 2133832223
r[4] = 2073354073
r[5] = 167288147
r[6] = 1827471542
r[7] = 834791014
r[8] = 1901409888
r[9] = 1990469526
*(p + 0) : 313959809
*(p + 1) : 1759055877
*(p + 2) : 1113101911
*(p + 3) : 2133832223
*(p + 4) : 2073354073
*(p + 5) : 167288147
*(p + 6) : 1827471542
*(p + 7) : 834791014
*(p + 8) : 1901409888
*(p + 9) : 1990469526
结果

可变参数

有时候我们可能会希望 函数带有可变数量的参数,C语言的 stdarg.h 头文件 提供了实现可变参数功能的函数和宏。

int func(int, ... ) {
   ...
}
 
int main(){
   func(2, 2, 3);
   func(3, 2, 3, 4);
}

函数 func() 最后一个参数写成省略号,即三个点号(...),省略号之前的那个参数是 int,代表了要传递的可变参数的总数。

具体步骤如下:

  • 定义一个函数,最后一个参数为省略号,省略号前面可以设置自定义参数数量。
  • 在函数定义中创建一个 va_list 类型变量,该类型是在 stdarg.h 头文件中定义的
  • 使用 va_start 宏来 初始化 va_list 变量。宏 va_start 是在 stdarg.h 头文件中定义的。
  • 使用 va_arg 宏来访问 va_list 变量中的每一项
  • 使用宏 va_end 来清理赋予 va_list 变量的内存。
#include <stdio.h>
#include <stdarg.h>

double average(int num, ...){
    va_list valist;     //创建一个 va_list 类型变量 valist
    double sum = 0.0;
    int i;

    va_start(valist, num);  // va_start宏初始化变量valist

    for (i = 0; i < num; i++){
        sum += va_arg(valist, int);     // va_arg宏访问valist成员
    }
    
    va_end(valist);// 清理 valist 内存

    return sum / num;
}

int main(){
    printf("2, 3, 4, 5的平均值为:%f\n", average(4, 2, 3, 4, 5));    // 3.500000
    printf("5, 10, 15的平均值为:%f\n", average(3, 5, 10, 15));    // 10.000000
}

递归

递归就是 函数自己调用自己(在使用递归时,程序员需要注意定义一个从函数退出的条件,否则会进入死循环)

案例:计算一个数的阶乘

#include <stdio.h>

// 声明定义一个函数
double factorial(unsigned int i){
    if (i <= 1){
        return 1;
    }
    return i * factorial(i - 1);
}

int  main(){
    int i = 15;
    printf("%d 的阶乘为 %f\n", i, factorial(i));    // 15 的阶乘为 1307674368000.000000
    return 0;
}
View Code

案例:生成斐波那契数列

#include <stdio.h>

int fibonaci(int i){
    if (i == 0){
        return 0;
    }
    if (i == 1){
        return 1;
    }
    return fibonaci(i - 1) + fibonaci(i - 2);
}

int  main(){
    int i;
    for (i = 0; i < 10; i++){
        printf("%d\t\n", fibonaci(i));
    }
    return 0;
}
View Code
0
1
1
2
3
5
8
13
21
34
结果

命令行参数

  命令行参数也是main函数的参数,执行程序时,可以从命令行传值给 C 程序。这些值被称为命令行参数,它们对程序很重要,特别是当您想从外部控制程序,而不是在代码内对这些值进行硬编码时,就显得尤为重要了。

  命令行参数是使用 main() 函数参数来处理的,main函数的参数只能有两个,习惯上这两个参数写为 main (int argc, char *argv[]) 

  • argc:整型实参,传入参数的个数,如果没有提供任何参数,argc 将为 1
  • argv[ ]:字符型指针数组,指向传递给程序的每个参数。
    • argv[0]:程序的名称
    • argv[1]:指向第一个命令行参数的指针
    • *argv[n]:最后一个参数

实例:先把代码编译成.exe文件,然后在cmd中执行 ./**.exe 参数1 参数2 

#include <stdio.h>

int main(int argc, char* argv[]){
    if (argc == 2){
        printf("提供的参数是 %s\n", argv[1]);
    }
    else if (argc > 2){
        printf("提供的参数太多.\n");
    }
    else{
        printf("期望一个参数.\n");
    }
}

  多个命令行参数之间用空格分隔,但是如果参数本身带有空格,那么传递参数的时候应把参数放置在双引号 "" 或单引号 '' 内部。让我们重新编写上面的实例

$./a.out "testing1 testing2"

Progranm name ./a.out
The argument supplied is testing1 testing2

参考

菜鸟教程

 

posted @ 2021-05-08 23:00  凌逆战  阅读(180)  评论(0)    收藏  举报