c基础 函数

news2024/11/15 17:16:03

函数

1.函数基本用法

1.1定义和三要素

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

三要素:功能 参数 返回值

参数:参数就是在函数声明时和函数调用时定义的变量。它用于传递信息给函数。

【1】实参是在函数调用中实际传递给函数的参数;而形式参数是函数声明中接受实参的参数。实参是有具体的数据。

【2】形参只是一个声明的形式,可以理解为一个符号名字。

返回值:函数返回值是函数调用后唯一留下的右值。(右值:只能放在运算符右边)

1.2函数的声明和定义

函数的声明: 存储类型 数据表类型 函数名(数据类型 形参1,数据类型 形参2,...) ;

函数定义格式:

存储类型 数据表类型 函数名(数据类型 形参1,数据类型 形参2,...) ;

{

        函数体;

}

其中:

函数名称:一个标识符

数据类型:是整个函数返回值类型,如果没有就用void

形式参数说明逗号分隔多个变量说明形式通常简称为形参

形参:形式参数就是声明函数时指函数名后括号中的变量,因为形式参数只有在函数调用的过程中才实例化(分配内存单元),所以就叫形式参数。

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

注意:在函数体中,表达式语句里使用的变量必须事先已有说明,否则不能使用。

return后面加表达式,语句中表达式的值,要和函数的<数据类型>保持一致。

总结函数数据

没有参数参数列表可以省略也可以写成void

没有返回值就写void,函数内部没有return

有返回值 根据 返回值 数据 类型 定义 函数 数据 类型

定义子函数时可以直接定义在主函数上面,如果定义在主函数下面需要提前声明函数

类型void可以省略或者表达式结果返回(即写成return;)

1.3函数调用

1.没有返回值:直接调用:函数名(实参)

2.有返回值 如果需要接收返回值就要函数定义一个返回值类型相同变量return 返回出去

实参:在调用有参函数时,函数名后面括号中的参数称为“实参”,是我们真实传给函数的参数,实参可以是:常量、变量、表达式、函数等。

无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。

例:

编写一个函数,函数的2个参数,第一个是一个字符,第二个是一个char *,

返回字符串中该字符的个数。

#include <stdio.h>
#include <string.h>
int geshu(char a,char *p){
    int num=0;
    for(int i=0;i<strlen(p);i++){
        if(a==p[i]){
            num++;
        }
    }
    return num;
}
int main(){
    char s[32]="";
    char a;
    char *p=s;
    scanf("%c",&a);
    gets(s);
    int g=geshu(a,p);
    printf("%d",g);

}

1.4 函数传参

 值传递

单向传递实参这个数据传递形参使用函数改变形参函数外的实参不会受影响,因为他们属于不同空间

#include <stdio.h>

void fun(int a, int b)   //a=10  b=30
{
    a++;  //a=11
    b++;  //b=31
    printf("in fun: %d %d\n", a, b);  //11 31
}

int main(int argc, char const *argv[])
{
    int n1 = 10, n2 = 30;
    fun(n1, n2);
    printf("in main: %d %d\n", n1, n2);  //10 30

    return 0;
}

地址传递

双向传递函数通过传递地址修改地址所指空间内容实参随之变化

#include <stdio.h>

void fun(int *a, int *b)  //a=&n1 b=&n2
{
    (*a)++;           //*a =*&n1 = n1       
    (*b)++;           //*b = *&n2 = n2
    printf("in fun: %d %d\n", *a, *b);   //11 31
}

int main(int argc, char const *argv[])
{
    int n1 = 10, n2 = 30;
    fun(&n1, &n2);  //n1=11  n2=31
    printf("in main: %d %d\n", n1, n2);   //11 31

    return 0;
}

数组传递

和地址传递一样,参数中存在地址,也就是指针。

#include <stdio.h>

void fun(int *p, int n) //p=a
{
    p[2] = 100;                 //a[2] =100
    printf("fun: ");
    for (int i = 0; i < n; i++)
        printf("%d ", p[i]); //或者用*(p+i)
    printf("\n");
}

int main(int argc, char const *argv[])
{
    int a[5] = {1, 2, 3, 4, 5};
    fun(a, 5);

    printf("main: ");
    for (int i = 0; i < 5; i++)
        printf("%d ", a[i]); //1 2 100 4 5
    printf("\n");

    return 0;
}

1.5 函数和栈区(stack)

 栈区的概念

栈用来存储函数内部的变量(包括main()函数)。它是一个FILO(First In Last Out,先进后出)的结构。每当一个函数声明一个新的变量它将被压入栈中。当一个函数运行结束后,这个函数所有在栈中相关的变量都将被删除,而且它们所占用的内存将会被释放。这就产生了函数内部的局部变量。栈区是一段非常特殊的内存区,它由CPU自动管理,所以你不必手动申请和释放内存。

内存由系统自动申请,在变量生命周期结束时由系统释放,也就是说,在程序运行的时候,系统有多个任务,就是检测变量是否该释放了,简单来说,就是cpu要抽时间去执行这部分功能。所以,如果这种变量比较多,不加节制的定义的话,那CPU的额外的工作量就会加大,综合下来,程序的运行效率就会低下。

 栈区(stack)的总结

 栈由CPU管理,无法修改

 变量自动地分配和释放

 栈并非没有限制,大部分栈都有一个上边界

 栈随着变量地产生和销毁生长和收缩

 栈区变量只有在函数创建它们

 2.开辟堆区(heap)空间

2.1 堆区概念

申请的空间种分为五个区域栈区(堆栈区),堆区,全局区,常量区,代码区,我们之前讲的这些定义变量、数组都是在内存的栈区存储。

堆区的特点:由我们程序员随时申请,由我们自己随时释放。

2.2 栈区的特点

堆区的特点:由我们程序员随时申请,由我们自己随时释放。

堆和栈的主要区别有:

 栈由系统自动分配,而堆是人为申请开辟;

 栈获得的空间较小,而堆获得的空间较大;

 栈由系统自动分配,速度较快,而堆一般速度比较慢;

 栈是连续的空间,而堆是不连续的空间是随机分配

 3.malloc 函数

3.1 定义

用man手册查看:

#include <stdlib.h>

void *malloc(size_t size);

功能:在堆区开辟大小为size的空间

参数:size:开辟空间的大小(单位:字节)

返回值:

成功:返回开辟空间的首地址

失败:NULL;

malloc()要和free()搭配使用

size_t大小:printf("%d\n",sizeof(size_t)); //4字节

3.2 用法

malloc内的参数是需要动态分配的字节数,而不是可以存储的元素个数!

当动态分配内存时,存储的是字符型数据,每个元素1字节,所以字节数刚好等于需要存储的元素个数(字符数+1);

如果存储的是整型或浮点型数据,字节数等于需要存储的元素个数 * 一个元素的字节数

代码格式

数据类型 *指针名 = (数据类型 *)malloc(n*sizeof(数据类型));

3.3 free()函数定义

#include <stdlib.h>

void free(void *ptr);

功能:释放之前调用 calloc、malloc 或 realloc 所分配的内存空间。

参数:ptr:堆区空间首地址

返回值:无

可以释放以后赋值空指针

free(p); //p成为野指针

p=NULL; //防止使用野指针

注意:

手动开辟堆区空间,要注意内存泄漏

当指针指向开辟堆区空间后,又对指针重新赋值,则没有指针指向开辟的堆区空间,就会造成内存泄漏。

使用完堆区空间后及时释放空间

3.4函数中开辟堆区的地址

以下代码

报段错,原因: 函数调用结束相当于销毁申请空间不会保留函数内部变量所以函数调用结束后p没了开始通过传参main函数q也就是NULL传递p也就是p指向NULL 函数内改变p指向指向堆区但是不会影响函数q因为qp两个空间所以函数调用结束后q改变还是指向NULL打印空指针段错误

解决方法1 通过返回

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

char *fun()
{
    char *p = (char *)malloc(32);
    strcpy(p, "hello");
        
    return p;
}

int main(int argc, char const *argv[])
{
    char *q = fun(); //q接收了函数的返回值也就是p保存的堆区地址
    printf("%s\n", q);
    free(q);

    return 0;
}

解决方法2 通过传参, 传递二级指针#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void fun(char **p)   //p=&q
{
    *p = (char *)malloc(32);   //*p = *&q =q

    strcpy(*p, "hello");
}

int main(int argc, char const *argv[])
{
    char *q = NULL;
    fun(&q);  //&q类型是char **
    printf("%s\n", q); 
    free(q);
    return 0;
}
解释: 通过传递二级指针&q也就是q地址传递fun函数p接收也就是p=&q也就是p指向q通过*p可以访问q*p重新赋值相当于q重新赋值所以函数*p(也就是q)指向堆区函数调用结束函数p销毁但是q已经指向堆区

4.string函数族

4.1strcpy

#include <string.h>

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

功能:把整个字符串复制,包括\0。

参数: char *dest :目标字符串首地址

const char *src:源字符串首地址

返回值:目标字符串首地址

4.2strcat

#include <string.h>

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

功能:用于字符串拼接

参数:

char *dest:目标字符串首地址

const char *src: 源字符串首地址

返回值:目标字符串首地址

 4.3strlen

#include <string.h>

size_t strlen(const char *s);

功能:计算字符串长度

参数:s:字符串的首地址

返回值:返回字符串实际长度,不包括‘\0’在内。

 4.4strcmp

#include <string.h>

int strcmp(const char *s1, const char *s2);

功能:用于字符串比较

参数:s1 s2用于比较多字符串

返回值:

从字符串首个字符开始比较字符ASCII的大小,如果相等继续向后判断。

正数: s1>s2

0 : s1== s2

负数: s1<s2

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

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

相关文章

钟氏崛起的奥秘:归隐与清议

话题的主角是钟皓&#xff0c;东汉后期人&#xff0c;颍川钟氏的第十代。他官做的不大&#xff0c;最高职务是一个小县的县长&#xff08;俸禄400石&#xff09;&#xff0c;远远没有父、祖辈高&#xff0c;父亲做到了光禄大夫、太守&#xff08;2000石&#xff09;。然而&…

【数据结构与算法】详解计数排序:小范围整数排序的最佳选择

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《数据结构与算法》 期待您的关注 ​ 目录 一、引言 二、计数排序的基本原理 三、实现步骤 1. 确定数据范围 2. 初始化计数数组…

JavaScript基础——JavaScript调用的三种方式

JavaScript简介 JavaScript的作用 JavaScript的使用方式 内嵌JS 引入外部js文件 编写函数 JavaScript简介 JavaScript&#xff08;简称“JS”&#xff09;是一种具有函数优先的轻量级&#xff0c;解释型或即时编译型的编程语言。它是Web开发中最常用的脚本语言之一&#x…

高清无水印,录屏软件对比盘点

现在生活中不论是想要记录赛事精彩瞬间、制作教学视频&#xff0c;都可以用录屏大师这样的录屏软件来实现。今天我就介绍几款备受好评的录屏工具。 1.福昕录屏大师 链接直达&#xff1a;https://www.foxitsoftware.cn/REC/ 这个软件就是一个专业的录屏工具。它可以控制屏幕…

UltraEdit v27文本代码程序编辑器免费版下载安装教程(亲测可用)

前言 UltraEdit 是一套功能强大的文本编辑器&#xff0c;可以编辑文本、十六进制、ASCII 码&#xff0c;完全可以取代记事本&#xff08;如果电脑配置足够强大&#xff09;&#xff0c;内建英文单字检查、C 及 VB 指令突显&#xff0c;可同时编辑多个文件&#xff0c;而且即使…

OrangePi AI Pro 固件升级 —— 让主频从 1.0 GHz 到 1.6 GHz 的巨大升级

前言 OrangePi AI Pro 最近发布了Ascend310B-firmware 固件包&#xff0c;据说升级之后可以将 CPU 主频从 1.0 GHz 提升至 1.6 GHz&#xff0c;据群主大大说&#xff0c;算力也从原本的 8T 提升到了 12T&#xff0c;这波开发板的成长让我非常的 Amazing 啊&#xff01;下面就来…

【学习日记】U-Boot 环境变量与 U-Boot 命令概述

本文记录了在学习 i.MX6ULL 的 U-Boot 代码时关于环境变量和 U-Boot 命令的一些关键点。 1 环境变量的定义 在 U-Boot 中&#xff0c;使用 #define 和反斜杠 \ 来定义多行字符串。 反斜杠 \&#xff1a; 反斜杠用于指示宏定义在下一行继续。这意味着所有的行将被视为一个连续的…

mqtt协议详解(0)初步认识mqtt

文章目录 1. 介绍2. 主要特性3. 架构1. 介绍 MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议)是一种构建在TCP/IP协议之上的轻量级、基于发布-订阅模式的消息传输协议,适用于资源受限的设备和低带宽、高延迟或不稳定的网络环境,例如IOT。 MQTT 协议于 1…

JVM:栈上的数据存储

文章目录 一、Java虚拟机中的基本数据类型 一、Java虚拟机中的基本数据类型 在Java中有8大基本数据类型&#xff1a; 这里的内存占用&#xff0c;指的是堆上或者数组中内存分配的空间大小&#xff0c;栈上的实现更加复杂。 Java中的8大数据类型在虚拟机中的实现&#xff1a;…

【error】ModuleNotFoundError: No module named ‘mmcv.cnn.weight_init‘

from&#xff1a; oduleNotFoundError: No module named ‘mmcv.cnn.weight_init‘_modulenotfounderror: no module named mmcv.cnn-CSDN博客https://blog.csdn.net/qq_36679208/article/details/107815137?spm1001.2101.3001.6650.1&utm_mediumdistribute.pc_relevant.…

java基础 之 集合与栈的使用(二)

文章目录 List 和 Set的比较Set接口对于set的无序该怎么理解&#xff1f;&#xff08;一&#xff09;实现类&#xff1a;HashSet&#xff08;二&#xff09;实现类&#xff1a;LinkedHashSet【代码部分】HashSet 和 LinkedHashSet浅谈HashSet 和 LinkedHashSet的打印结果 &…

MYSQL-初级-事务篇

目录 概述为什么有事务&#xff1f; 事务操作事务的四大特性&#xff08;AICD&#xff09;原子性&#xff08;Atomicity&#xff09;一致性&#xff08;Consistency&#xff09;隔离性&#xff08;Isolation&#xff09;持久性&#xff08;Durability&#xff09; 并发事务问题…

为虚幻引擎C++项目设置VS开发环境

为虚幻引擎C项目设置VS开发环境 虚幻引擎&#xff08;简称UE&#xff09; 能与 Visual Studio&#xff08;简称VS&#xff09; 完美结合&#xff0c;使你能够快速、简单地改写项目代码&#xff0c;并能即刻查看编译结果。设置Visual Studio以使用虚幻引擎能提高开发者对虚幻引…

rust 桌面 sip 软电话(基于tauri 、pjsip库)

本文尝试下rust 的tauri 桌面运用 原因在于体积小 1、pjsip 提供了rust 接口官方的 rust demo 没编译出来 在git找了个sip-phone-rs-master https://github.com/Charles-Schleich/sip-phone-rs 可以自己编译下pjsip lib库替换该项目的lib 2、创建一个tauri demo 引用 [depe…

操作系统(4)——文件系统

目录 小程一言文件系统管理基础概念&功能基本概念文件的结构和属性文件的操作文件的安全性和权限控制文件系统的实现和分配方式 问题&解答1、文件系统在操作系统中起到什么作用&#xff1f;2、文件的逻辑结构和物理结构有何区别&#xff1f;3、如何理解文件权限控制在操…

时间序列异常值检验替换——基于Hampel滤波器

Hampel滤波器作为一种强大的时间序列异常值处理工具&#xff0c;在数据清洗和分析中发挥着重要作用。本文将深入研究Hampel滤波器的原理和数学推导&#xff0c;并通过实际代码演示其在异常值处理中的应用 1. Hampel滤波器简介 1.1 什么是Hampel滤波器&#xff1f; Hampel滤波…

【达梦数据库】通过线程pid定位会话SQL

【达梦数据库】通过线程pid定位会话SQL 1、查找数据库进程 ps -ef|grep dmserver2、通过进程pid去找对应的线程 top -H -p $pid -------------------- top命令经常用来监控linux的系统状况&#xff0c;是常用的性能分析工具&#xff0c;能够实时显示系统中各个进程的资源占用…

Signac包-1.Analyzing PBMC scATAC-seq

–https://stuartlab.org/signac/articles/pbmc_vignette 好的&#xff0c;开始学习scATAC-seq的数据是怎么玩的了&#xff0c;先跑完Signac的教程&#xff0c;边跑边思考怎么跟自己的课题相结合。 留意更多内容&#xff0c;欢迎关注微信公众号&#xff1a;组学之心 数据和R…

Qt安卓开发的一些概念

目录 1、Android 版本和 API 的对应关系&#xff1f; 2、ABI是什么 2.1、x86_64 2.2、x86 2.3、arm64-v8a 2.4、armeabi-v7a 3、不同架构的特点 3.1、32位 ARM 架构 (ARMv7) 3.2、64位 ARM 架构 (ARMv8-A) 3.3、32位 Intel 架构 (x86) 3.4、64位 Intel 架构 (x86-64…

vue+element-ui的列表查询条件/筛选条件太多以下拉选择方式动态添加条件(支持全选、反选、清空)

1、此功能已集成到TQueryCondition组件中 2、最终效果 3、具体源码(新增moreChoose.vue) <template><el-popoverpopper-class"t_query_condition_more":bind"popoverAttrsBind"ref"popover"v-if"allcheckList.length>0"…