C语言学习笔记之函数

news2025/5/21 0:54:19

文章目录

      • 1、函数的基本用法
      • 2、函数的参数传递
        • 2.1 全局变量
        • 2.2 复制传递方式
        • 2.3 地址传递方式
      • 3、函数的传参—数组
      • 4、指针函数
      • 5、递归函数和函数指针
        • 5.1 递归函数
        • 5.2 函数指针
        • 5.3 函数指针数组

1、函数的基本用法

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

一般形式如下:

  • <数据类型>  <函数名称>(<形式参数说明>) 
    {            
    	语句序列;            
    	return[(<表达式>)];
    } 
    
  • <数据类型>是整个函数的返回值类型。

  • return[(<表达式>)]语句中表达式的值,要和函数的<数据类型>保持一致。如无返回值应该写为void型

  • <形式参数说明>是逗号””分隔的多个变量的说明形式

  • 大括弧对 {<语句序列> },称为函数体;<语句序列>是大于等于零个语句构成的

函数的说明就是指函数原型

其中,<形式参数说明>可以缺省说明的变量名称,但类型不能缺省

  • 例如:
    • double Power(double x, int n) ;
    • double Power(double, int);

函数的使用也叫函数的调用,形式如下:

函数名称(〈实际参数〉)

  • 实参就是在使用函数时,调用函数传递给被调用函数的数据。需要确切的数据
  • 函数调用可以作为一个运算量出现在表达式中,也可以单独形成一个语句。对于无返回值的函数来讲,只能形成一个函数调用语句。

编写一个函数显示 “Hello, guy! ”,然后编写主程序main调用它。

#include <stdio.h>

void Displayhello()
{
    printf("Hello,guy!\n");
}
int main()
{
	Displayhello(); //调用
      
	return 0;
}

定义求xn值的函数( x是实数, n为正整数)

#include <stdio.h>

double power(double x, int n) //函数的说明(需要放在主函数前面)
{
        double r = 1;
        int i;

        for (i = 1; i <= n; i++)
                r *= x;

        return r;
}

int main() 
{
        double x, ret;
        int n;

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

        ret = power(x, n);//函数的调用

        printf("%lf %d = %lf\n", x, n, ret);

        return 0;
}

2、函数的参数传递

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

  • 全局变量
  • 复制传递方式
  • 地址传递方式
2.1 全局变量
  • 全局变量就是在函数体外说明的变量,它们在程序中的每个函数里都是可见的
  • 全局变量一经定义后就会在程序的任何地方可见。函数调用的位置不同,程序的执行结果可能会受到影响。不建议使用

例如:

#include <stdio.h>

double x = 2;//全局变量
int n = 3;	 //全局变量

double power();

int main() 
{
//        double x = 2;
//        int n = 3;
        double ret;

        ret = power();

        printf("%lf %d = %lf\n", x, n, ret);

        return 0;
}

double power() 
{
        double r = 1;
        int i;

        for (i = 1; i <= n; i++)
                r *= x;

        return r;
}

2.2 复制传递方式
  • 调用函数将实参传递给被调用函数,被调用函数将创建同类型的形参并用实参初始化
  • 形参是新开辟的存储空间,因此,在函数中改变形参的值,不会影响到实参

例如:

#include <stdio.h>

double power(double, int);

int main() 
{
        double x = 2;
        int n = 3;
        double ret;

        printf("&x=%p &n=%p\n", &x, &n);

        ret = power(x, n);

        printf("%lf %d = %lf\n", x, n, ret);

        return 0;
}

double power(double a, int b) //double a = x; int b = n;
{
        double r = 1;
        int i;

        printf("&a=%p &b=%p\n", &a, &b);

        for (i = 1; i <= b; i++)
                r *= a;

        return r;
}

例如:写一个函数,实现两个数据的交换

#include <stdio.h>

void  swap(int x, int y);

int main() 
{
        int a = 10;
        int b = 20;

        printf("before:%d %d\n", a, b);

        swap(a, b);

        printf("after:%d %d\n", a, b);

        return 0;
}
//int x = a; int y = b;
void  swap(int x, int y) 
{
        int t;
        t = x;
        x = y;
        y = t;
}

2.3 地址传递方式
  • 按地址传递,实参为变量的地址,而形参为同类型的指针
  • 被调用函数中对形参的操作,将直接改变实参的值(被调用函数对指针的目标操作,相当于对实参本身的操作)
#include <stdio.h>

void  swap(int * x, int * y);

int main() 
{
        int a = 10;
        int b = 20;

        printf("before:%d %d\n", a, b);

        swap(&a, &b);

        printf("after:%d %d\n", a, b);

        return 0;
}
//int * x = &a; int *y = &b;
void  swap(int * x, int * y) 
{
        int t;
        t = *x;//a
        *x = *y;
        *y = t;
}

例如:编写一个函数,统计字符串中小写字母的个数,并把字符串中的小写字母转化成大写字母

#include <stdio.h>

int str_fun(char * p);

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

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

        return 0;
}

int str_fun(char * p) //char * p = s;
{
        int num = 0;
        while (*p != '\0') {//while (*p)
                if (*p <= 'z' && *p >= 'a') {
                        num++;
                        *p -= ' ';
                }
                p++;
        }
        return num;
}

3、函数的传参—数组

全局数组传递方式

复制传递方式

  • 实参为数组的指针,形参为数组名(本质是一个指针变量)

地址传递方式

  • 实参为数组的指针,形参为同类型的指针变量

例如:编写函数,计算一个一维整形数组的所有元素的和

//写法1:
#include <stdio.h>

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));
    //sizeof(a)/sizeof(int)=元素个数

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

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

        for (i = 0; i < n;i++) {
                printf("%d\n", data[i]);
                ret += data[i];
        }

        return ret;
}
//写法2:
#include <stdio.h>

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;
{//int n = sizeof(a)/sizeof(int);
        int ret = 0;
        int i;

        for (i = 0; i < n;i++) {
                printf("%d\n", data[i]);
                ret += data[i];
        }

        return ret;
}

例如:编写函数,删除字符串中的空格

#include <stdio.h>

void del_space(char * s1);

int main(int argc, char *argv[])
{
        char s[] = "   h  a   sdf g  ";

        puts(s);
        del_space(s);
        puts(s);

        return 0;
}

void del_space(char * s1) 
{
        char * s2;

        s2 = s1;

        while (*s1) {
                if (*s1 == ' '){
                        s1++;
                }
                else {
                        *s2 = *s1;
                        s1++;
                        s2++;
                }
        }
        *s2 = '\0';
}

多维数组与函数

  • 多维数组作为参数在函数间的传递也有全局数组、复制传递和地址传递三种方式。

4、指针函数

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

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

<数据类型>  *  <函数名称>(<参数说明>) {      
语句序列;
}

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

下面程序是否有问题,若有问题,如何修改?

#include <stdio.h>
char *  mystring()  {
	 char str[20];//局部变量,
	 strcpy(str, “Hello”);
	 return str;
}
int  main(void)
{
	 printf(%s\n”, mystring());//最后结果乱码
       return 0;
}

修改后

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

//char str[20];
char * mystring();

int main(int argc, char *argv[])
{
        char * r;
        
        r = getstring();
        printf("---%s---\n", getstring());

        //(*r)++;
        puts(r);

        return 0;
}

char * mystring() 
{
        //char str[20];//error
        //static char str[20]; //静态变量
        char * str = "hello";  //不需要改的情况下可以使用

       // strcpy(str, "hello");

        return str;
}

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

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

char * del_space(char * s);

int main(int argc, char *argv[])
{
        //char * r;
        char str[]= "   how    are  you  ";
        char s[50], s2[50];
        
//        r = del_space(str);
 //       printf("---%s---\ n", r);

        //strcpy(s, del_space(str));
        strcpy(s2, strcpy(s, del_space(str)));//m=n=k
        puts(str);
        puts(s);
        puts(s2);

        return 0;
}

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

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

        return r;
}

例如:编写一个指针函数, 实现字符串连接

#include <stdio.h>

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

int main(int argc, char *argv[])
{
        //char * r;
        char dest[50] = "welcome to";
        char src[] = "China";
        
        puts(mstrcat(dest, src));
        puts(dest);

        return 0;
}

char * mstrcat(char * dest, const char * src) 
{
        char * r = dest;

        while (*dest++);

        dest--;

        while (*dest++ = *src++);

        return r;
        /*
        char * r = dest;

        while (*dest++);

        dest--;

        while (*src) {
                *dest++ = *src++;
        }

        *dest = '\0';

        return r;
        */
        /*
        char * r = dest;

        while (*dest) {
                dest++;
        }

        while (*src) {
                *dest = *src;
                dest++;
                src++;
        }

        *dest = '\0';

        return r;
        */
}

例如:编写一个指针函数,把整数123转化成字符串”123”。

#include <stdio.h>

char * itoa(int n);

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

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

        s = itoa(n);

        puts(s);

        return 0;
}

char * itoa(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;
                i++;
                j--;
        }

        return p;
}

5、递归函数和函数指针

5.1 递归函数

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

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

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

例如:编写一个递归函数,计算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);
}

例如:编写一个递归函数,计算斐波那契数列(与下面类似)

一般而言,兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来。如果所有兔子都不死,那么一年以后可以繁殖多少对兔子?

我们不妨拿新出生的一对小兔子分析一下:第一个月小兔子没有繁殖能力,所以还是一对两个月后,生下一对小兔对数共有两对三个月以后,老兔子又生下一对,因为小兔子还没有繁殖能力,所以一共是三对

#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);
}

5.2 函数指针

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

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

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

  • <数据类型> (*<函数指针名称>)(<参数说明列表>);
  • <数据类型>是函数指针所指向的函数的返回值类型
  • <参数说明列表>应该与函数指针所指向的函数的形参说明保持一致
  • (*<函数指针名称>)中,*说明为指针()不可缺省,表明为函数的指针
#include <stdio.h>

int add(int a, int b) {
        return a+b;
}
int sub(int a, int b) {
        return a-b;
}
int mul(int a, int b) {
        return a*b;
}

int main(int argc, char *argv[])
{
        int m = 10, n = 20;
        
        int  (* p)(int, int);

        p = add;

        //printf("%d\n", add(m, n));
        printf("%d\n", (*p)(m, n));

        p = sub;
        printf("%d\n", (*p)(m, n));

        return 0;
}
5.3 函数指针数组

函数指针数组是一个保存若干个函数名的数组

一般形式如下

  • <数据类型> (*<函数指针数组名称> [<大小>] )(<参数说明列表> );
    • 其中,<大小>是指函数指针数组元数的个数
    • 其它同普通的函数指针
#include <stdio.h>

int add(int a, int b) {
        return a+b;
}
int sub(int a, int b) {
        return a-b;
}
int mul(int a, int b) {
        return a*b;
}

int main(int argc, char *argv[])
{
        int m = 10, n = 20;
        
        int  (* p[2])(int, int);//int * p[3]

        p[0] = add;

        //printf("%d\n", add(m, n));
        printf("%d\n", (*p[0])(m, n));

        p[1] = sub;
        printf("%d\n", (*p[1])(m, n));

        return 0;
}

例如:调用C库中的qsort函数来实现整形数组的排序。

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

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

int main(int argc, char *argv[])
{
        int s[] = {89, 23, 10, 8, 7, 61}, 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);

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2380350.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】模版(1)

目录 1. 泛型编程 2. 函数模版 2.1 函数模版概念 2.2 函数模版格式 2.3 函数模版的原理 2.4 函数模版实例化方式 隐式实例化 显式实例化 2.5 模版参数的匹配原则 3. 模版类 模版类的定义格式 模版类的实例化 1. 泛型编程 如何实现一个通用的交换函数呢&#xff1f…

基于开源AI智能名片链动2+1模式S2B2C商城小程序源码的去中心化商业扩散研究

摘要&#xff1a;本文探讨在去中心化商业趋势下&#xff0c;开源AI智能名片链动21模式S2B2C商城小程序源码如何助力企业挖掘数据价值、打破信息孤岛&#xff0c;实现商业高效扩散。通过分析该技术组合的架构与功能&#xff0c;结合实际案例&#xff0c;揭示其在用户关系拓展、流…

5月19日day30打卡

模块和库的导入 知识点回顾&#xff1a; 导入官方库的三种手段导入自定义库/模块的方式导入库/模块的核心逻辑&#xff1a;找到根目录&#xff08;python解释器的目录和终端的目录不一致&#xff09; 作业&#xff1a;自己新建几个不同路径文件尝试下如何导入 一、导入官方库 …

白杨SEO:不到7天,白杨SEO博客网站百度搜索显示和排名恢复正常!顺带说说上海线下GEO聚会分享和播客红利

大家好&#xff0c;我是白杨SEO&#xff0c;专注SEO十年以上&#xff0c;全网SEO流量实战派&#xff0c;AI搜索优化研究者。 5月开始&#xff0c;明显就忙起来了&#xff0c;不管是个人陪跑还是企业顾问&#xff0c;不管是需要传统SEO还是新媒体流量&#xff0c;还是当下这个A…

Java 应用中的身份认证与授权:OAuth2.0 实现安全的身份管理

Java 应用中的身份认证与授权&#xff1a;OAuth2.0 实现安全的身份管理 在当今的软件开发领域&#xff0c;身份认证与授权是构建安全可靠应用的关键环节。而 Java 作为广泛使用的编程语言&#xff0c;在实现这一功能上有着诸多成熟的框架和方案。其中&#xff0c;OAuth2.0 凭借…

【氮化镓】偏置对GaN HEMT 单粒子效应的影响

2025年5月19日,西安电子科技大学的Ling Lv等人在《IEEE Transactions on Electron Devices》期刊发表了题为《Single-Event Effects of AlGaN/GaN HEMTs Under Different Biases》的文章,基于实验和TCAD仿真模拟方法,研究了单粒子效应对关断状态、半开启状态和开启状态下AlG…

Mysql 索引概述

索引&#xff08;index&#xff09;是帮助Mysql高效获取数据的数据结构 索引优点&#xff1a;1. 提高排序效率 2. 提高查询效率 索引缺点&#xff1a;1.索引占用空间&#xff08;可忽略&#xff09;2.索引降低了更新表的速度&#xff0c;如进行insert,update,delette 时效率降…

解决RAGFlow部署中镜像源拉取的问题

报错提示 Error response from daemon: Get "https://registry-1.docker.io/v2/ ": context deadline exceeded 解决方法 这个原因是因为拉取镜像源失败&#xff0c;可以在/etc/docker/daemon.json文件中添加镜像加速器&#xff0c;例如下面所示 {"registry…

uniapp打包H5,输入网址空白情况

由于客户预算有限&#xff0c;最近写了两个uniapp打包成H5的案例&#xff0c;总结下面注意事项 1. 发行–网站-PCWeb或手机H5按钮&#xff0c;输入名称&#xff0c;网址 点击【发行】&#xff0c;生成文件 把这个给后端&#xff0c;就可以了 为什么空白呢 最重要一点&#xf…

C++(21):fstream的读取和写入

目录 1 ios::out 2 ios::in和is_open 3 put()方法 4 get()方法 4.1 读取单个字符 4.2 读取多个字符 4.3 设置终结符 5 getline() 1 ios::out 打开文件用于写入数据。如果文件不存在&#xff0c;则新建该文件&#xff1b;如果文件原来就存在&#xff0c;则打开时清除…

NAT/代理服务器/内网穿透

目录 一 NAT技术 二 内网穿透/内网打洞 三 代理服务器 一 NAT技术 跨网络传输的时候&#xff0c;私网不能直接访问公网&#xff0c;就引入了NAT能讲私网转换为公网进行访问&#xff0c;主要解决IPv4(2^32)地址不足的问题。 1. NAT原理 当某个内网想访问公网&#xff0c;就必…

Unity 多时间源Timer定时器实战分享:健壮性、高效性、多线程安全与稳定性能全面解析

简介 Timer 是一个 Unity 环境下高效、灵活的定时任务调度系统&#xff0c;支持以下功能&#xff1a; •支持多种时间源&#xff08;游戏时间 / 非缩放时间 / 真实时间&#xff09; •支持一次性延迟执行和重复执行 •提供 ID、回调、目标对象等多种查询和销毁方式 •内建…

【iOS】探索消息流程

探索消息流程 Runtime介绍OC三大核心动态特性动态类型动态绑定动态语言 方法的本质代码转换objc_msgSendSELIMPMethod 父类方法在子类中的实现 消息查找流程开始查找快速查找流程慢速查找流程二分查找方法列表父类缓存查找 动态方法解析动态方法决议实例方法类方法优化 消息转发…

413 Payload Too Large 问题定位

源头 一般是服务器或者nginx 配置导致的 nginx http {client_max_body_size 50m; # 调整为所需大小&#xff08;如 50MB&#xff09;# 其他配置... }nginx 不配置&#xff0c;默认是1M 服务器 spring 不配置也是有默认值的好像也是1M 如果出现413 可以试着修改配置来避…

2025年渗透测试面试题总结-360[实习]安全工程师(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 1. 自我介绍 2. WAF及其绕过方式 3. IPS/IDS/HIDS 4. 云安全 5. 绕过安骑士/安全狗 6. Gopher扩展…

Ubuntu16.04升级gcc/g++版本方法

0 前言 gcc与g分别是GNU的c和c编译器&#xff0c;Ubuntu16.04默认的gcc和g的版本是5.4.0&#xff0c;在使用一些交叉编译工具链会提示找不到GLIBC_2.27&#xff0c;而GLIBC_2.27又需要gcc 6.2以上版本&#xff0c;因此本文介绍Ubuntu16.04升级gcc/g版本的方法。 1 Ubuntu16.0…

微信小程序van-dialog确认验证失败时阻止对话框的关闭

使用官方(Vant Weapp - 轻量、可靠的小程序 UI 组件库)的before-close&#xff1a; wxml&#xff1a; <van-dialog use-slot title"名称" show"{{ show }}" show-cancel-button bind:cancel"onClose" bind:confirm"getBackInfo"…

OceanBase 的系统变量、配置项和用户变量有何差异

在继续阅读本文之前&#xff0c;大家不妨先思考一下&#xff0c;数据库中“系统变量”、“用户变量”以及“配置项”这三者之间有何不同。如果感到有些模糊&#xff0c;那么本文将是您理清这些概念的好帮手。 很多用户在使用OceanBase数据库中的“配置项”和“系统变量”&#…

【Python】Jupyter指定具体路径

一、右键Jupyter Notebook 右击Jupyter Notebook点击属性 二、修改以下两个地方

RNope:结合 RoPE 和 NoPE 的长文本建模架构

TL;DR 2025 年 Cohere 提出的一种高效且强大的长上下文建模架构——RNope-SWA。通过系统分析注意力模式、位置编码机制与训练策略&#xff0c;该架构不仅在长上下文任务上取得了当前最优的表现&#xff0c;还在短上下文任务和训练/推理效率方面实现了良好平衡。 Paper name …