函数
定义: 一个可以完成特定功能的代码模块
三要素: 功能、参数、返回值
定义格式
存储类型 数据类型 函数名(参数列表) // 形参
{
函数体; // 功能
return 返回值; // 返回值
}
函数调用
1) 没有返回值:直接调用:函数名(参数列表) // 实参
2) 有返回值:如果需要接收返回值,就要定义一个与返回值类型相同的变量接收,如果不需要接收返回值,就可以直接调用函数
函数特点
函数不调用不执行,函数调用多次就会执行多次
定义函数时会出现以下几种情况
1)有参数:函数名后的小括号需要按照定义变量的方式定义参数,调用时函数名后的小括号也要传递相应个数和类型的参数
2)没有参数:参数列表可以省略,也可以用 void,调用时也不需要写参数
3)有返回值:要根据返回值的数据类型定义函数的数据类型,在函数体内部 return 返回值
4)没有返回值:数据类型为 void,函数内部没有 return 返回值
5)定义子函数时可以直接定义在主函数的上面,如果定义在主函数下面需要提前声明函数
声明函数: 数据类型 函数名(参数列表); // 形参
参数的分类
形参:定义函数时写在小括号内的参数,用来接收实参的传值
实参:函数调用时写在小括号的内容,用来给形参传递值
注意:形参的个数与实参的个数一一对应(数据类型也要对应)
函数的传参
值传递
单向传递(实参--->形参)修改形参的值 实参不会发生变化
地址传递
双向传递 修改形参的值 实参会发生变化
地址传递本质是一个值传递
#include <stdio.h>
int fun(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
int main(int argc, char const *argv[])
{
int a = 10, b = 20;
fun(&a, &b);
printf("%d %d\n", a, b);
return 0;
}
数组传递
数组传参传递的为数组首元素的地址
数组中各元素在内存中连续存放
#include<stdio.h>
void fun(int *p,int n)
{
for(int i=0;i<n;i++)
{
printf("%d ",p[i]);
}
printf("\n");
}
int main(int argc, char const *argv[])
{
int arr[3]={1,2,3};
fun(arr,3);
return 0;
}
开辟堆区空间(动态内存开辟)
为什么存在动态内存开辟
<1>在技术方面,普通的空间申请,都是在全局或者栈区,全局一般不太建议大量使用,而栈空间有限,那么如果一个应用需要大量的内存空间的时候,需要通过申请堆空间来支持基本业务。
<2>在应用方面,程序员很难一次预估好自己总共需要花费多大的空间。想想之前我们定义的所有数组,因为其语法约束,我们必须得明确"指出"空间大小.但是如果用动态内存申请(malloc)因为 malloc 是函数,而函数就可以传参,也就意味着,我们可以通过具体的情况,对需要的内存大小进行动态计算,进而在传参申请,提供了很大的灵活性。
需要手动开辟空间,手动释放、如果只开辟不释放,所用的空间会越来越少
开辟 (malloc)
#include <stdlib.h>
void *malloc(size_t size);
功能:在堆区开辟空间
参数:size:开辟空间的大小(单位:字节)
返回值: 成功:返回开辟空间的首地址
失败:NULL // 为什么出现开辟失败,它没有足够大的空间了
释放 (free)
#include <stdlib.h>
void free(void *ptr);
功能:释放堆区空间
参数:ptr:堆区空间的首地址
返回值:无
#include<stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
// 可以这么开辟 malloc(40);
// 也可以这么开辟 malloc(size(int)*10);
int *p = (int *)malloc(sizeof(int) * 10);
if (p == NULL)
{
printf("开辟失败!\n");
return -1;
}
printf("开辟成功!\n");
// 在此去书写一些功能
for (int i = 0; i < 9; i++)
{
scanf("%d", &p[i]);
}
for (int i = 0; i < 9; i++)
{
printf("%d\n", p[i]);
}
// 空间使用完成之后,记得释放
free(p);
p = NULL;
return 0;
}
注意:
- 手动开辟堆区空间,要注意内存泄漏
- 使用完堆区空间后要及时释放空间 指针要及时置空
string 函数族
strcpy
#include <string.h>
char *strcpy(char *dest, const char *src);
功能:实现字符串复制
参数:char *dest:目标字符串首地址
const char *src:原字符串首地址
返回值:目标字符串首地址
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char s[32] = "hello";
char c[32] = "world";
strcpy(s, c); // 将 c 复制到 s 里面
printf("%s\n", s); // world
return 0;
}
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char s[32] = "hello";
char c[32] = "wor";
strcpy(s, c); // 复制包括 \0
printf("%s\n", s); // wor
return 0;
}
#include <string.h>
char *strncpy(char *dest, const char *src, size_t n);
功能:实现字符串复制
参数:char *dest:目标字符串首地址
const char *src:原字符串首地址
size_t n:复制字符个数
返回值:目标字符串首地址
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char s[32] = "hello";
char c[32] = "world";
strncpy(s, c, 3); // 这样就是把 wor 复制过去
printf("%s\n", s); // worlo
return 0;
}
strlen
#include <string.h>
size_t strlen(const char *s);
功能:计算字符串的实际长度
参数:s:字符串首地址
返回值:字符串的实际长度
strcat
#include <string.h>
char *strcat(char *dest, const char *src); 将原字符串拼接到目标字符串的后面
功能:用于字符串拼接
参数:char *dest:目标字符串首地址
const char *src:原字符串首地址
返回值:目标字符串首地址
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char s1[32] = "hello";
char *s2 = "world";
strcat(s1, s2);
printf("%s\n", s1); // helloworld
return 0;
}
char *strncat(char *dest, const char *src, size_t n); 拼接字符串的前 n 个字符
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char s1[32] = "hello";
char *s2 = "world";
strncat(s1, s2, 3);
printf("%s\n", s1); // hellowor
return 0;
}
strcmp
#include <string.h>
int strcmp(const char *s1, const char *s2); 比较两个字符串字符的大小
功能:用于字符串比较
参数:s1、s2 是字符串首地址
返回值: 从字符串首个字符开始比较字符的 ASCII 的大小,如果相等继续向后判断
正数 s1 > s2
0 s1 == s2
负数 s1 < s2
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char s1[] = "hello";
char s2[] = "helloworld";
char *s3 = "hqyj";
char *s4 = "nihaoshijie";
// int ret = strcmp(s1, s2); // s1 < s2 负数
// int ret = strcmp(s1, s3); // s1 < s3 负数
// int ret = strcmp(s2, s4); // s2 < s4 负数
int ret = strcmp(s3, s2); // s3 > s2 正数
printf("%d\n", ret);
return 0;
}
int strncmp(const char *s1, const char *s2, size_t n); 比较两个字符串前 n 个字符的大小
一般它会用来判断字符串是否相等
if(!strcmp(s1, s2))
{
printf("相等\n");
}
递归函数
定义:函数自己调用自己
执行过程:
递推阶段:从原问题出发,按递推公式从未知到已知,最终达到终止条件
回归阶段:按递归的终止条件求出结果,逆向逐步带入公式,回到原问题
#include <stdio.h>
void fun(int n)
{
if (n > 9)
fun(n / 10);
printf("%d\n", n % 10);//1 2 3 4
}
int fun1(int m)
{
if(m==1)
return 1;
return m*fun1(m-1);//5*4*3*2*1
}
int main(int argc, char const *argv[])
{
fun(1234);
printf("%d\n",fun1(5));//120
return 0;
}
函数编程练习
编写一个函数,返回一个字符串中某个字符出现的次数
#include <stdio.h>
void str(char *p, char c)
{
int i = 0;
while (*p)
{
if (*p == c)
{
i++;
}
p++;
}
printf("%c出现%d次\n", c, i);
}
int main(int argc, char const *argv[])
{
char s[32], ch;
printf("input str:\n");
scanf("%s", s);
printf("input ch:\n");
scanf(" %c", &ch);
str(s, ch);
return 0;
}
封装函数:找到数组中最大位置及其下标并输出
#include <stdio.h>
void fun(int s[], int t, int *k)
{
int max = s[0];
*k = 0;
for (int i = 1; i < t; i++)
{
if (s[i] > max)
{
max = s[i];
*k = i;
}
}
}
int main(int argc, char const *argv[])
{
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 0, 11}, k;
fun(a, 10, &k);
printf("%d %d\n", a[k], k);
return 0;
}
封装函数:向数组的指定位置插入元素
参数:数组首地址,数组元素个数,插入元素下标,插入元素值
#include<stdio.h>
void insert(int *p,int n,int post,int data)
{
int i=n;
while(i>=post)
{
p[i]=p[i-1];
i--;
}
p[post]=data;
}
int main(int argc, char const *argv[])
{
int arr[]={1,2,3,4,5,6};
int n=sizeof(arr)/sizeof(int);
n++;
insert(arr,n,3,10);
for(int i=0;i<n;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
return 0;
}
封装函数:删除数组指定位置的元素
参数:数组的首地址,数组元素的个数,删除元素的下标
#include<stdio.h>
void delete(int *p,int n,int post)
{
int i=0;
while(i<n)
{
if(i>=post)
{
p[i]=p[i+1];
}
i++;
}
}
int main(int argc, char const *argv[])
{
int arr[]={1,2,3,4,5,6};
int n=sizeof(arr)/sizeof(int);
delete(arr,6,2);
n--;
for(int i=0;i<n;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
return 0;
}
封装函数:遍历数组,打印数组内容
#include<stdio.h>
void show(int *p,int n)
{
int i=0;
while(i<n)
{
printf("%d ",p[i]);
i++;
}
}
int main(int argc, char const *argv[])
{
int arr[]={1,2,3,4,5,8};
int n=sizeof(arr)/sizeof(int);
show(arr,n);
printf("\n");
return 0;
}