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

目录
相关文章
|
11月前
|
人工智能 测试技术 开发者
软件测试/人工智能|Python函数与调用:解放编程力量的关键
软件测试/人工智能|Python函数与调用:解放编程力量的关键
|
2月前
|
开发者 UED
代码之外:软件开发者如何培养跨界思维
在技术飞速发展的今天,软件开发者面临的挑战已超越单纯编码技能。本文探讨了跨界思维的重要性及其对职业成功的推动作用。跨界思维能促进创新、提高适应性和增强沟通能力。通过学习新知识、参与多学科项目、建立多元化网络、培养创新思维及学习设计思维,开发者可全面提升自身能力。这不仅增强个人竞争力,还促进团队创新。
|
4月前
|
数据采集 算法 大数据
代码之舞:探索软件开发的艺术与科学
在软件工程的广阔天地里,编程不仅仅是一系列指令的堆砌,它更像是一场精心编排的舞蹈。本文将深入探讨软件开发中的艺术性和科学性如何交织在一起,通过实际案例分析,揭示高效编码背后的逻辑美学和创造性思维。我们将一同穿梭于代码行间,体验技术与创新的完美融合,感受那些让软件项目从平凡走向卓越的微妙之处。 【7月更文挑战第21天】
58 1
|
6月前
|
设计模式 算法 程序员
代码与诗意:软件开发中的创造性思维
【2月更文挑战第16天】在数字世界的构建中,技术并非只是冰冷的逻辑与算法堆砌,它同样蕴含着创造力与艺术性。本文通过探索软件开发过程中的非传统元素,揭示了编程背后的创造性思维和艺术表现。从设计模式到代码重构,再到用户界面的美学设计,每一环节都体现了技术人员对于美的追寻和技术的诗性表达。文章将深入探讨如何将创造性原则融入日常开发工作,以提升软件质量并丰富开发者的技术体验。
|
程序员 容器
程序员基本素养和特质
程序员基本素养和特质
|
架构师 算法
架构师培养计划-无限思维——变量
架构师培养计划-无限思维——变量
68 0
|
设计模式 算法 程序员
培养编程思维的关键——从最基础开始
在当今信息时代,编程已经成为一项不可或缺的技能。而要成为一名优秀的程序员,除了掌握具体的编程语言和工具,更重要的是培养良好的编程思维。本文将从最最基础的层面入手,探讨如何培养编程思维。
251 0
|
安全 数据可视化 定位技术
黑客马拉松促进编程和公民思想
2月21日,迈阿密戴德镇政府在Miami Ad School举办的编程比赛中开放了政府数据库。 2015年Code Across 的主题围绕21世纪的政府。 这次编程比赛时间与国际数据开放日2月21日吻合。 这次活动以数字化的方式回答了关于政府和社区的常见问题,为迈阿密戴德镇的健康状况、人口资源、社会服务和其他公民服务建立了一个开源指向。
133 0
黑客马拉松促进编程和公民思想
|
人工智能 Dart 安全
关于当今软件开发的四件会让过去的程序员大吃一惊的事
  过去的盲点给我们提供了另一种思考未来的方式。 技术变革的步伐并没有放缓。 在一两年之内,我们大多数人仍然会思考世界。 我们期待着很多变化,并且我们花了大量时间想象它们。 但是在雷达之下发生了什么? 我们期望哪些发展永远不会实现? 我们今天很少有人期望发生什么革命?   软件开发改变了世界。 我们只看到其中一些即将到来。关于当今软件开发的四件会让过去的程序员大吃一惊的事
174 0
|
分布式计算 前端开发 Java
3 个方法,教你提升程序员的自我价值
3 个方法,教你提升程序员的自我价值
282 0

相关实验场景

更多
下一篇
无影云桌面