函数
1、函数基础语法(函数定义、调用、声明)
2、函数的使用注意事项(传值、返回值)
3、企业级函数(复用性、维护性、扩展性)——华为编码
函数基础语法:
1、函数三要素:函数名、函数形参、函数返回值
函数名:命名提现自注释性,提高代码可读性:动词_名词[4]
函数形参:传什么类型就用什么类型的变量来接;(a == 元素指针 aa == int (*a)[] aaa = int (*aa)[][]
函数的返回值:return 0;——结束当前函数 exit(1);——结束整个程序
2、函数使用形式:函数的声明(在调用函数前需要声明函数)、函数的定义、函数调用
函数定义:函数名、函数的返回值、形参的类型及变量名
函数调用:函数名、实参的变量名或者实参的地址
函数声明:函数名、函数返回值、形参的类型(变量名可以不提供):不分配内存空间
函数的注意事项:
1、函数的传参:
传值(传实参变量名) VS 传地址(传实参变量的地址)
当只使用不修改实参变量内存空间的值,在函数调用时传实参变量名;(只能使用不能修改)
当即使用也修改实参变量内存空间的值,在函数调用时传实参变量的地址;(既能使用又能修改)
练习:编写一个函数,实现交换两个整数变量的值
swap_int.c文件中:
void swap_int(int *left,int *right)
{
*left = *left ^ *right;
*right = *left ^ *right;
*left = *left ^ *right;
}
swap_int.h:
extern void swap_int(int *,int *);
main.c:
#include <stdio.h>
#include "swap_int.h"
int main(int argc,char *argv[])
{
int left = 5;
int right = 6;
swap_int(&left,&right);
printf("left = %d right = %d\n",left,right);
return 0;
}
传值(传实参变量名) VS 传地址(传实参变量的地址)
当只使用不修改实参变量内存空间的值,在函数调用时传实参变量名;(只能使用不能修改)
当即使用也修改实参变量内存空间的值,在函数调用时传实参变量的地址;(既能使用又能修改)
#include <stdio.h>
int main(int argc,char *argv[])
{
void func(char *ptr)
{
ptr++;
}
char *ptr = "hello world";
func(ptr);
printf("%s\n",ptr);
return 0;
}
打印结果还是helloworld(ptr传的是实参变量名,只能使用不能修改)
#include <stdio.h>
int main(int argc,char *argv[])
{
void func(char **ptr)
{
(*ptr)++;
}
char *ptr = "hello world";
func(&ptr);
printf("%s\n",ptr);
return 0;
}
打印结果为elloworld
判断:修改指针变量对应内存空间值(指针变量的地址),还是要修改指针变量指向内存空间的值(传指针变量名)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void get_mem(char *ptr)
{
ptr= (char *)malloc(sizeof(char) * 100);
}
int main (int argc,char **argv)
{
char *ptr;
get_mem(ptr);
strcpy(ptr,"hello world");
printf("ptr = %s\n",ptr);
return 0;
}
**出现段错误:**get_mem(ptr)传的是实参变量名,只能使用不能修改,ptr是野指针
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void get_mem(char **ptr)
//char * get_mem(char *ptr)
{
*ptr= (char *)malloc(sizeof(char) * 100);
if(NULL == ptr)
{
printf("malloc error!\n");
exit(1);
}
int main (int argc,char **argv)
{
char *ptr;
get_mem(&ptr);
//ptr = get_mem(ptr);
memset(ptr,0,sizeof(char)*100);//初始化
strcpy(ptr,"hello world");
printf("ptr = %s\n",ptr);
free(ptr);//释放
ptr = NULL;//置空
return 0;
}
2、传出参数,传入参数(大多数函数实参)
传入参数:传递给函数只使用不修改的实参
传出参数:传递给函数修改的实参(相当于函数返回值)
函数如何返回多个值?利用传出参数
int func(char * ptr)
{
*ptr = 'a';//实参op
result = 5;
}
char op;
int result = func(&op);
统计字符串中最长连续数字子串的长度并获得最长连续数字子串:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int continue_max_str(char *dest,char *src)
{
int len = 0;
int max_len = 0;
while(*src != '\0')
{
while((*src >= '0' && *src <= '9') && *src != '\0')
{
len++;
src++;
}
if(len > max_len)
{
strncpy(dest,src - len,len);
*(dest + len) = '\0';
max_len = len;
}
len = 0;
src++;
}
return max_len;
}
int main(int agrc, char *argv[])
{
char *src = (char *)malloc(sizeof(char) * 100);
char *dest = (char *)malloc(sizeof(char) * 100);
printf("Plesae input src:\n");
scanf("%s", src);
printf("src = %s\n", src);
int max_len = continue_max_str(dest,src);
printf("the max len = %d\n", max_len);
printf("the max str = %s\n",dest);
return 0;
}
3、主函数参数(命令行参数)
argc:保存参数的个数
argv:参数保存在argv指针数组里
atoi函数:将字符串转成整型
4、函数返回值
不能返回局部变量的地址
char func3()
{
char src[100] = "hello world";
return src;
}
char *temp = func3();
printf("temp = %s\n,temp);
结果为temp = NULL;栈空间局部变量执行完函数会释放
企业级函数的编写:低耦合高内聚
编写一个函数,该函数可以实现将一个整数转为字符串:
int2str.h
#include <stdio.h>
#include <string.h>
extern char * int2str(int num);
#define MAX_SIZE 1024
main.c
#include <stdio.h>
#include "int2str.h"
int main(int argc,char **argv)
{
int num;
printf("please input num:\n");
scanf("%d",&num);
char *result = int2str(num);
printf("result = %s\n",result);
return 0;
}
int2str.c
#define MAX_SIZE 1024
static void reverse_str(char *src)
{
if(NULL == src)
{
return;
}
char temp;
int len = strlen(src);
for(int i = 0;i<=len/2;i++)
{
temp = *(src + i);
*(src + i) = *(src + len -1 - i);
*(src + len -1 - i) = temp;
}
return;
}
char * int2str(int num)
{int i = 0;
static char src[MAX_SIZE]
while(num != 0)
{
src[i]=num % 10 + '0';
num = num / 10;
i++;
}
src[i] = '\0';
reverse_str(src);
return src;
}
函数指针变量:变量,保存地址,地址是函数的地址(函数的入口地址)
函数名:指针,保存函数地址(函数入口地址)
函数指针的作用,什么时候用?做形参
函数指针的工程应用作用:
1、隐藏调用接口和调用形式(提高统一的调用方式);2、间接体现多态,提高代码的扩展性;
函数指针数组:数组,数组里的每个元素都是函数指针
int ((fp1)(int))[10]:
fp1:函数指针变量,指向的函数形参int,返回值是一个数组指针,该指针指向的数组里的每个元素都是int;
int ((*arr[5])())();
arr:函数指针数组,数组里的每个元素都是函数指针,指向一个形参为空返回值为函数指针,该指针指向一个形参为空,返回值为int ;
float ((*b())[])();
b:b是一个函数,形参为空,返回值为指针,指向一个数组,数组里每个元素都是指针,返回值为float
可变参数:
可变参数的实现原理:
1、形参在栈空间上是连续存储的
2、第一个形参用来说明后面参数类型或者个数