一丶函数
定义:
一个可以完成特定功能的代码模块 函数可以实现代码的复用
三要素:
功能,参数,返回值
格式:
存储类型 数据类型 函数名(参数列表) // 参数 形参
{
函数体; // 功能
return 返回值; // 返回值
}
注意:(1) 没有参数:参数列表可以省略,也可以用 void
(2) 没有返回值:数据类型为 void,函数内部没有return语句
(3) 有返回值:要根据返回值的数据类型定义函数的数据类型
(4) 定义子函数时可以直接定义在主函数的上面,如果定义在主函数下面需要提前声明函数,声明函数:数据类型 函数名(参数列表); // 形参
形参和实参的区别:
形参是函数定义时,定义的形参变量。是形式上存在的参数,只有在电泳函数时才会开辟内存空间。
实参是调用函数时,实际传递的值。实际存在的值。
形参的个数要和实参的个数一一对应(数据类型也要对应)
特点:
函数不调用不执行, 函数调用多次就会执行多次
函数的传参:
1.值传递:
单向传递(实参--->形参)修改形参的值 实参不会发生变化
#include<stdio.h>
int fun(int a,int b)
{
int sum;
sum = a + b;
return sum;
}
int main(int argc, char const *argv[])
{
int a = 10;
int b =20;
int sum = fun(a,b); //a,b传参给函数后,a,b的值并不会发生改变
printf("%d\n",sum);
return 0;
}
2.地址传递:
双向传递,在函数中修改形参,实参会一起改变(把变量的地址传递过去,通过地址对原内容修改)
#include<stdio.h>
void fun(int *p1,int*p2)
{
int c =*p1;
*p1 = *p2;
*p2 = c; //交换ab的值
}
int main(int argc, char const *argv[])
{
int a =1,b=2; //a = 1,b=2
fun(&a,&b); //将a,b的地址传给fun函数,函数中形参改变后,实参也会改变
printf("%d %d\n",a,b); //a = 2 , a = 1
return 0;
}
3.数组传递
#include <stdio.h>
void *fun(char *p)
{
for (int a = 0; a < 5; a++,p++)
printf("%c", *p);
}
int main(int argc, char const *argv[])
{
char buf[32] = "hello";
char *p = fun(buf);
return 0;
}
二丶开辟堆区空间
为什么存在动态内存开辟
在技术方面,普通的空间申请,都是在全局或者栈区,全局一般不太建议大量使用,而栈空间有限,那么如果一个应 用需要大量的内存空间的时候,需要通过申请堆空间来支持基本业务。
在应用方面,程序员很难一次预估好自己总共需要花费多大的空间。想想之前我们定义的所有数组,因为其语法约束,我们必须得明确"指出"空间大小.但是如果用动态内存申请(malloc)因为malloc是函数,而函数就可以传参,也就意味着,我们可以通过具体的情况,对需要的内存大小进行动态计算,进而在传参申请,提供了很大的灵活性。
需要手动开辟空间,手动释放、如果只开辟不释放,所用的空间会越来越少
开辟空间
void *malloc(size_t size);
功能:在堆区开辟空间
参数:size:开辟空间的大小(单位:字节)
返回值:成功:返回开辟空间的首地址
失败:NULL // 为什么出现开辟失败,它没有足够大的空间了
释放空间
#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 (NULL == p)
{
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;
}
1. 手动开辟堆区空间,要注意内存泄漏 ,当指针指向开辟堆区的空间之后,又对指针重新赋值,则没有指针指向开辟堆区空间,就会造成内存泄露
2. 使用完堆区空间之后及时释放空间