C素养提升-函数专题

简介: 在c语言中,函数是一个完成特定功能的代码模块,其程序代码独立,通常要求有返回值,也可以是空值。

函数是一个完成特定功能的代码模块,其程序代码独立,通常要求有返回值,也可以是空值。

一般形式如下:

<数据类型> <函数名称>(<形式参数说明>)

函数的参数传递

函数之间的参数传递方式:

  • 全局变量
  • 复制传递方式
  • 地址传递方式

1.全局变量

全局变量就是在函数体外说明的变量,它们在程序中的每个函数里都是可见的。

全局变量一经定义就会在程序的任何地方可见。函数调用的位置不同,程序的执行结果可能会收到影响。不建议使用

2.复制传递

调用函数将实参传递给被调函数,被调用函数将创建同类型的形参并用实参初始化。

形参是新开辟的存储空间,因此,在函数中改变形参的值,不会影响到实参。

3.地址传递

按地址传递,实参为变量的地址,而形参为同类型的指针。

被调用函数中对形参的操作,将直接改变实参的值(被调用函数对指针的目标操作,相当于对实参本身的操作)。

#include <stdio.h>

int str_fun(char *p);

int main(int argc, char *argv[])
{
   
   
    char s[] = "welcome2023Jiangxi";
    int n;

    n = str_fun(s);
    printf("n=%d %s\n", n, s);

    return 0;
}

// char *p = n        我们需要习惯将形参联想等于实参,两端逻辑需要相通
int str_fun(char *p)
{
   
   
    int num = 0;
    while(*p != '\0')
    {
   
   
        if(*p <= 'z' && *p >= 'a')
        {
   
   
            num++;
            *p -= ' ';
        }
        p++;
    }
    return num;
}

image-20230131104155837

函数的传参--数组

  • 全局数组传递方式

  • 复制传递方式:实参为数组的指针,形参为数组名(本质是一个指针变量)

  • 地址传递方式:实参为数组的指针,形参为同类型的指针变量

案例一

#include <stdio.h>

int array_sum(int data[], int n);    //相当于int array_sum(int *data, int n);

int main(int argc, char *argv[])
{
   
   
        int a[] = {
   
   5, 9, 10, 3, 10};
        int sum = 0;

        sum = array_sum(a,sizeof(a) / sizeof(int));

        printf("sum=%d\n", sum);
        return 0;
}

int array_sum(int data[], int n)   // int data[] = a;-->error
{
   
                                   
        int ret = 0;
        int i;

        for(i = 0; i < n; i++)
        {
   
   
                ret += data[i]; 
        }
        return ret;
}

image-20230202113334614

上述程序需要我们对数组的元素个数进行计算,如果函数单纯传入一个数组,并且在程序代码段中再进行数组长度的计算,由于我们传入的是int data[],此时的int data[]实际就是int *data,使用sizeof()函数则会得到一个指针的字节长度,而并非我们想要的数组长度

案例二

// try to write a function,which delete the space character of character string.

#include <stdio.h>

void del_space(char *str);

int main(int argc, char *argv[])
{
   
          
        char a[] = "hello world,hello linux!";
        puts(a);
        del_space(a);
        puts(a);

        return 0; 
}
void del_space(char *str)
{
   
          
        char *p;
        p = str;
        while(*str)
        {
   
   
                if(*str == ' ')
                {
   
   
                        str++;
                }
                else
                {
   
   
                        *p = *str;
                        p++;
                        str++;
                }
        }
        *p = '\0';
}

image-20230202121727967

此处是删除一段字符串中的空格字符,在void del_space()函数中,我们采取的是指针地址传递的形式,由于我们需要实现的功能是删除字符串中多余的空格,所以当字符指针为空格时,指针向后移动一位,当遇到字符时,将指针字符2复制给指针字符1,同时两者地址同时后移一位,这里需要注意的是,当字符指针便利到最后一位\0时,代表字符串的末尾,因此我们也需要为赋值*p = '\0';代表末位。

指针函数

1.基本概念

指针函数是指一个函数的返回值为地址量的函数。

2.定义形式

函数指针的定义的一般形式如下:

<数据类型> * <函数名称>(<参数说明>){
   
   

语句序列;

}

`返回值:全局变量的地址 / static变量的地址 / 字符串常量的地址 / 堆的地址`

3.示例

// 编写一个指针函数,删除一个字符串中的空格

#include <stdio.h>
#include <string.h>

char *del_space(char *s);

int main(int argc, char *argv[])
{
   
   
        char * r;
        char str[] = "How   ar e  y ou!";

        r = del_space(str);
        printf("----%s---\n",r);

        puts(str);

        return 0;
}

char *del_space(char *s)
{
   
   
        char *p = s;
        char *r = s;

        while(*s)
        {
   
   
                if(*s == ' ')
                {
   
   
                        s++;
                }
                else
                {
   
   
                        *p = *s;
                        s++;
                        p++;
                }
        }
        *p = '\0';

        return r;
}

image-20230214135249007

// 编写一个函数,实现两个字符串的连接

#include <stdio.h>

char *mstrcat(char *dest, const char * src);

int main(int argc, char *argv[])
{
   
   
    char dest[59] = "welcome";
    char src[] = "makeru";

    puts(mstrcat(dest,src));
    puts(dest);

    return 0;
}

char *mstrcat(char *dest, const char * src)
{
   
   
    char *r = dest;
    while(*dest)
    {
   
   
        dest++;
    }
    while(*src)
    {
   
   
        *dest = *src;
        dest++;
        src++;
    }
    *dest = '\0';

    return r;
}

image-20230214140618531

// 编写一个函数,将传入的整型转成字符串

#include <stdio.h>

char * itoa(int n);
int main(int argc, char *argv[])
{
   
   
        int n;
        char s[50], *r;

        printf("input:");
        scanf("%d",&n);

        r = itoa(s, n);

        puts(r);
        puts(s);

        return 0;
}

char * itoa(char *p, int n)
{
   
   
        int r, i = 0, j;
        //static char p[50];

        while(n)
        {
   
   
                r = n % 10;
                n /= 10;
                p[i] = r + '0';
                i++;
        }
        p[i] = '\0';

        j = i - 1;
        i = 0;

        while(i < j)
        {
   
   
                r = p[i];
                p[i] = p[j];
                p[j] = r;
                j--;
                i++;
        }

        return p;
}

image-20230214143612736

递归函数

1.基本概念

递归函数是指一个函数的函数体中直接或间接调用了该函数自身

递归函数调用的执行过程分为两个阶段:

  • 递推阶段:从原问题出发,按递归公式递推从未知到已知,最终达到递归终止条件。
  • 回归阶段:按递归终止条件求出结果,逆向逐步代入递归公式,回归原问题。

2.示例

// 计算n!

#include <stdio.h>

int fac(int n);

int main(int argc, char *argv[])
{
   
   
    int n;

    printf("input:");
    scanf("%d",&n);

    printf("%d\n", fac(n));

    return 0;
}

int fac(int n)
{
   
   
    if(n == 0 || n == 1)
        return 1;
    return n * fac(n-1);
}

image-20230214144903183

// 编写一段程序,计算斐波那契序列

#include <stdio.h>

int fib(int n);

int main(int argc, char *argv[])
{
   
   
    int n = 1;
    while(n <= 10)
    {
   
   
        printf("%d ",fib(n));
        n++;
    }

    printf("\n");
    return 0;
}

int fib(int n)
{
   
   
    if(n == 1 || n == 2)
        return 1;
    return fib(n-1)+fib(n-2);
}

image-20230214145721633

函数指针

1.基本概念

函数指针用来存放函数的地址,这个地址是一个函数的入口地址

  • 函数名代表了函数的入口地址

2.定义形式

函数指针变量说明的一般形式如下:

<数据类型> (*<函数指针名称>) (<参数说明列表>);

eg:
int (*p)(int a, int b);

3.函数指针数组

定义:函数指针数组是一个保存若干个函数名的数组。

一般形式如下:

<数据类型> (*<函数指针数组名称>)(<大小>)(<参数说明列表>);

---<大小>:指函数指针数组元素的个数
---其他等同普通的函数指针

4.示例

// 编写一段程序,实现qsort()排序的功能

#include <stdio.h>

int compare(const void*, const void *);

int main(int argc, char *argv[])
{
   
   
        int s[] = {
   
   89, 23, 5, 54, 75}, n, i;
    n = sizeof(s) / sizeof(int);
    qsort(s, n, sizeof(int), compare);

    for(i = 0;i < n; i++)
        printf("%d ",s[i]);
    puts("");

    return 0;
}

int compare(const void* p, const void *q)
{
   
   
        return (*(int *)p - *(int *)q);
}

image-20230214173053208

目录
相关文章
|
9月前
|
安全 C语言 C++
【软件设计师备考 专题 】标准化机构及其作用
【软件设计师备考 专题 】标准化机构及其作用
104 0
|
9月前
|
人工智能 数据挖掘 程序员
代码力量:探寻编程在现代社会中的无限可能性
代码力量:探寻编程在现代社会中的无限可能性
|
5月前
|
开发者 UED
代码之外:软件开发者如何培养跨界思维
在技术飞速发展的今天,软件开发者面临的挑战已超越单纯编码技能。本文探讨了跨界思维的重要性及其对职业成功的推动作用。跨界思维能促进创新、提高适应性和增强沟通能力。通过学习新知识、参与多学科项目、建立多元化网络、培养创新思维及学习设计思维,开发者可全面提升自身能力。这不仅增强个人竞争力,还促进团队创新。
|
程序员
编程高手,都在培养自己的“硬核力”
编程高手,都在培养自己的“硬核力”
145 0
|
7月前
|
数据采集 算法 大数据
代码之舞:探索软件开发的艺术与科学
在软件工程的广阔天地里,编程不仅仅是一系列指令的堆砌,它更像是一场精心编排的舞蹈。本文将深入探讨软件开发中的艺术性和科学性如何交织在一起,通过实际案例分析,揭示高效编码背后的逻辑美学和创造性思维。我们将一同穿梭于代码行间,体验技术与创新的完美融合,感受那些让软件项目从平凡走向卓越的微妙之处。 【7月更文挑战第21天】
88 1
|
6月前
|
算法
编程之旅:从代码到思维的蜕变
【8月更文挑战第20天】在数字化浪潮中,编程不仅是技术的实践,更是思维的锻炼。本文探讨了编程如何影响我们的思考方式,并分享了作者个人的技术感悟和成长经历。通过深入分析编程带来的逻辑思维、问题解决能力和持续学习的重要性,文章揭示了编程与日常生活之间的紧密联系,鼓励读者以更加开放和创新的心态面对挑战。
|
8月前
|
设计模式 人工智能 算法
代码之舞:编程中的艺术与科学
【6月更文挑战第21天】在数字世界的广阔舞台上,编程不仅是逻辑和算法的冷硬交织,更是创造力与美学的灵动飞扬。本文将深入探讨编程的艺术性和科学性,揭示如何通过代码编织出功能性与美感并存的软件作品。我们将从编程的基础出发,探索其在解决复杂问题中的作用,以及如何通过设计模式、重构和测试驱动开发等技术手段提升代码质量。同时,文章还将讨论编程中的创新思维和持续学习的重要性,强调在技术快速迭代的时代,保持好奇心和适应性是程序员不可或缺的素质。最后,我们将以对未来编程趋势的展望作为结尾,鼓励读者在编程的道路上不断追求卓越,创造出既实用又具有艺术价值的作品。
76 5
|
8月前
|
机器学习/深度学习 算法 搜索推荐
编程之舞:探索算法的优雅与力量
【6月更文挑战第10天】在软件的世界里,算法是构筑数字宇宙的基石。它们如同精心编排的舞蹈,每一个步骤都充满着逻辑的美感和解决问题的力量。本文将带领读者走进算法的世界,一起感受那些精妙绝伦的编程思想如何转化为解决现实问题的钥匙。
44 3
|
9月前
|
安全 开发者
这些职场潜规则帮你做高效技术人
作者是一个从一线技术人摸爬滚打一步步成长起来的技术管理者,也算是慢慢积累了一些做事和管理的经验心得,三年的管理者快照能侧面佐证作者通过学习和实践从管理小白到逐渐摸到了一些管理门道的自我修炼之路是怎么走过来的。
|
程序员 测试技术 开发者
「程序员转型技术管理」必修的 10 个能力提升方向
对许多开发者而言,深耕技术,然后成为技术专家或许是职业发展的唯一答案。但如果你赞同「软件开发只是我众多职业目标中的一个」,也许你可以试试「技术管理之路」。 我原来觉得和计算机打交道比跟人打交道轻松得多,所以我成了一名软件开发者。一段时间后,我发现自己越来越多地在给别人提供帮助;我喜欢领导项目,热衷于推动更好的代码标准。于是,我几乎毫无挣扎地成为了一名技术管理者。
134 0

热门文章

最新文章