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

目录
相关文章
|
8月前
|
小程序 开发者 Python
揭秘python函数:编程艺术的核心力量
揭秘python函数:编程艺术的核心力量
|
8月前
|
存储 Python
揭秘python函数:编程艺术的核心力量(2)
揭秘python函数:编程艺术的核心力量(2)
|
8月前
|
人工智能 数据挖掘 程序员
代码力量:探寻编程在现代社会中的无限可能性
代码力量:探寻编程在现代社会中的无限可能性
|
7天前
|
开发者 C++
开发者 动机VS自律 孰轻孰重
开发者在追求卓越的过程中,内在动机与自律习惯都起着至关重要的作用。内在动机如同强大的引擎,驱使开发者探索新技术、攻克难题;而自律则像精准的时钟发条,确保代码质量和任务按时完成。两者相辅相成,缺一不可。动机赋予开发者前进的动力,而自律则保障其在面对挑战时不偏离轨道,持续提升自我。对于开发者而言,两者共同作用,才能实现不断成长与进步。
|
4月前
|
开发者 UED
代码之外:软件开发者如何培养跨界思维
在技术飞速发展的今天,软件开发者面临的挑战已超越单纯编码技能。本文探讨了跨界思维的重要性及其对职业成功的推动作用。跨界思维能促进创新、提高适应性和增强沟通能力。通过学习新知识、参与多学科项目、建立多元化网络、培养创新思维及学习设计思维,开发者可全面提升自身能力。这不仅增强个人竞争力,还促进团队创新。
代码之美:从混乱到秩序的编程旅程
在编程的世界里,代码不仅仅是冷冰冰的文字和符号的组合。它们是思想的载体,是解决问题的工具,更是艺术与科学的结晶。本文将带你领略编程过程中的美学,从最初的混乱无序到最终的清晰有序,探索如何通过良好的设计原则、清晰的逻辑结构以及持续的重构来提升代码质量,从而使得代码不仅能够高效运行,还能成为令人赏心悦目的艺术品。
|
5月前
|
算法
编程之旅:从代码到思维的蜕变
【8月更文挑战第20天】在数字化浪潮中,编程不仅是技术的实践,更是思维的锻炼。本文探讨了编程如何影响我们的思考方式,并分享了作者个人的技术感悟和成长经历。通过深入分析编程带来的逻辑思维、问题解决能力和持续学习的重要性,文章揭示了编程与日常生活之间的紧密联系,鼓励读者以更加开放和创新的心态面对挑战。
|
6月前
|
测试技术 UED
软件测试的科学与艺术:从数据导向到逻辑严密的实践
本文旨在探讨软件测试领域中数据导向和逻辑严密性的重要性,并分析如何通过科学严谨的方法提升测试效率和质量。文章首先概述了软件测试的基本概念和挑战,随后深入讨论了数据在测试设计和结果分析中的关键作用,以及如何利用逻辑推理来构建有效的测试案例和识别潜在缺陷。最后,本文提出了一系列实践建议,旨在帮助测试人员更好地整合数据驱动和逻辑推理方法,以实现软件测试的最优化。
52 0
|
8月前
|
存储 编译器 程序员
C语言调试大作战:与VS编译器共舞,上演一场“捉虫记”的艺术与科学
C语言调试大作战:与VS编译器共舞,上演一场“捉虫记”的艺术与科学
|
8月前
|
Python
揭秘python函数:编程艺术的核心力量(3)
揭秘python函数:编程艺术的核心力量(3)

热门文章

最新文章