目录
1、函数基础语法(函数定义、调用、声明)
2、函数的使用注意事项(传值、返回值)
一函数的基础知识
#include <stdio.h>
int add(int a,int b);//函数的声明
//函数放在主函数的前面
int add(int a,int b)
{
return a+b;
}
int main(int argc, char const *argv[])
{
/**
* 函数基础语法:
* 1、函数三要素:调用、函数定义、声明
* 2、函数的使用注意事项:传值、返回值
* 3、企业级函数(复用性、维护性、扩展性)--华为编码
*/
/**
* 1、函数三要素:函数名、函数形参、函数返回值
* 函数名:命名体现自注释,提高代码的可读性 :动词_名词(不要用拼音)
* 函数的形参:传什么类型,就要用什么类型的变量来接;(a ==元素指针,aa ==int(*a)[] aaa = int (*aa)[][])
* 函数的返回值:return 0;结束当前函数;exit(1);结束整个函数
* 2、函数的使用形式:函数的声明(在调用函数前需声明函数)、函数的定义、函数调用
* 函数定义:函数名、函数的返回值、形参的类型及变量名
* 函数调用:函数名、实参的变量名或者实参的地址
* 函数声明:函数名、函数返回值、形参的类型(变量名可以不提供);不分配内存空间
* */
int sum = add(5,6);//函数调用
printf("sum = %d\n",sum);
return 0;
}
二传值和传地址
传值
#include <stdio.h>
#include "swap_int.h"
/**
* 函数的注意事项:
* 1、函数的传参:
* 传值 VS 传地址
* */
int main(int argc, char const *argv[])
{
int a=5,b=6;
printf("left= %d,right = %d\n",a,b);
void swap_int(a,b);
printf("left= %d,right = %d\n",a,b);
return 0;
}
根据图解,没有调用到
传指针的时候,不要以为就是在传地址
三传地址
判断:修改指针变量对应内存空间的值(传指针变量的地址) ,还是要修改指针变量指向内存空间的值(传指针变量名)
#include <stdio.h>
void func(char **ptr)//这里就是在传递对应的地址
{
(*ptr)++;//从地址调取,从而改变值
}
//void func(char *ptr)
// //实际上只是在传递ptr的值而不是地址,形参是不可以改变的
// {
// ptr++;
// *ptr = 'E';
// }
int main()
{
char c[100] = "hello";
char *ptr ;
ptr = c;
//传指针的时候,不要以为就是在传地址
//判断:修改指针变量对应内存空间的值(传指针变量的地址)
// ,还是要修改指针变量指向内存空间的值(传指针变量名)
// func(&ptr);
func(c);
printf("ptr = %s\n",ptr);
return 0;
}
面试题
主要注意函数调用地址的方法
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//void get_men(char *ptr)//这里并没有将指针地址传递过去
//方法1
void get_men(char **ptr)
{
*ptr = (char *)malloc(sizeof(char) * 100);//动态分配空间
}
//方法2
char * get_men2(char *ptr)//字符指针型,返回的是地址
{
ptr = (char *)malloc(sizeof(char) * 100);
if(ptr == NULL)//是否分配成功
{
printf("malloc error!\n");
exit(1);//结束所有程序
}
return ptr;
}
int main(int argc, char const *argv[])
{
char *ptr;//ptr对应的内存空间
char *ptr1;
//get_men(ptr);//传实参变量名(只能使用不用修改) ptr野指针
get_men(&ptr);
ptr1=get_men2(ptr1);//返回值必须有人接着
memset(ptr,0,sizeof(char) * 100);//清除脏数据
strcpy(ptr,"hello world");
printf("ptr =%s\n",ptr);
strcpy(ptr1,"hello world");
printf("ptr1 =%s\n",ptr1);
return 0;
}
四函数的传出传入参数
传入参数:实际上就是只传递给函数但是不修改的实参
传出参数:传递给函数修改的实参(相当函数的返回值)
函数如果返回多个值?
利用传出参数
#include <stdio.h>
int func(char *ptr)
{
*ptr = 'a';//实参op
return 5;
}
int main(int argc, char const *argv[])
{
char op;
int result = func(&op);//op为传出参数
//op=='a' result == 5;
return 0;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.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);
// char *strncpy(char *dest, const char *src, // size_t n)
// 把 src 所指向的字符串复制到 dest,最多复制 n 个字 // 符。
// 当 src 的长度小于 n 时,dest 的剩余部分将用空字节填 // 充。
*(dest + len) = '\0';
max_len =len;
}
len = 0;
src++;
}
return max_len;
}
int main(int argc, char const *argv[])
{
//char *src;//此时空间地址不够,必须要动态分配
char *src = (char *)malloc(sizeof(char)*100);
char *dest = (char *)malloc(sizeof(char)*100);
printf("Please input src:\n");
scanf("%s",src);
printf("src = %s\n",src);
//int max_len=continue_max_str(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;
}
五命令行参数(主函数参数)
#include <stdio.h>
int main(int argc, char *argv[])//char **argv是一样的
{
//argc:命令行参数的个数
//argv:参数都保存在指针数组里面
printf("argc = %d\n",argc);
//将命令本身传递进去所以为1
for (int i = 0; i < argc; i++)
{
printf("argv[%d] = %s\n",i,argv[i]);
//保存的就是命令本身
}
return 0;
}
六使用注意事项
函数的返回值:不能返回局部变量的地址
如何返回多个值--结构体、传出参数
#include <stdio.h>
char * func3()
{
char src[100] = "hello world";
return src;//不能返回局部变量的地址,因为空间会释放
}
int * func4()
{
static int num = 6;
//使用static可以延长它的生命周期,至结束后释放
return #
}
int main(int argc, char const *argv[])
{
char * tmp = func3();
printf("tmp = %s\n",tmp);
int * p = func4();//p指向的空间已经被释放,所以无效
printf("tmp = %d\n",*p);
return 0;
//代表函数正常退出
//如果没有return 0;系统会挨个判断耽误时间
}
七函数指针
#include <stdio.h>
int add(int a,int b)
{
return a+b;
}
int test(int (*p_func)(int,int),int a,int b)//p_func:指向的函数称之为回调函数
{
return p_func(a,b);
}
int main(int argc, char const *argv[])
{
//函数指针变量:变量,保存地址,地址是函数的地址(函数的入口地址)
//函数名:指针,保存函数地址(函数入口地址)
//什么时候使用函数指针?做形参;
//函数指针功能应用作用:1、隐藏调用接口和调用形式 2、间接体现多态,提高代码的扩展性;
int sum = add(5,6);
int (*p_func)(int,int);//p_func:函数指针变量,指向函数地址,里面有两个int类型的形参
printf("sizeof(p_func) = %ld\n",sizeof(p_func));//函数指针在64位是8个字节,函数指针终究是指针
p_func = add;//传地址
//p_func = &add;//函数名找地址(编译也不会出错)
printf("%d\n",p_func(5,6));
//printf("%d\n",(*p_func)(5,6));//不涉及到步长
test(add,5,6);
return 0;
}
#include <stdio.h>
typedef int (*T)(int,int);//声明T为函数指针类型
void GetArray(int *a,int length)
{
printf("请输入10个数字:\n");
int i;
for(i = 0;i<length;i++)
{
scanf("%d",&a[i]);
}
}
int less (int x,int y)
{
return x<y?1:0;
}
int greater(int x,int y)
{
return x>y?1:0;
}
void Sort(int a[],int length,T p)//传入函数需要函数指针来接受
{
int i,j;
for(i = 0;i<length-1;i++)
{
for ( j = 0; j < length-1-i; j++)
{
int t = a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
}
void print(int *a,int length)
{
int i;
for(i = 0;i<length;i++)
{
printf("%d",a[i]);
}
printf("\n");
}
int main(int argc, char const *argv[])
{
int a[10]={0};
int length = sizeof(a)/sizeof(a[0]);
GetArray(a,length);
Sort(a,length,greater);
print(a,length);
return 0;
}
八函数指针数组及指针复杂声明
int a;
int *a;
int **a;
int a[10];
int *a[10];
int (*a)[10];
int (*a)(int);
int (*a[10])(int);
九复杂指针的声明
int *(*(*fp1)(int))[10];
fp1:函数指针变量,指向的函数形参int,返回值是一个指针数组,该指针指向的数组里面里的每个元素都是int *
int *(*(*arr[5])())();
arr:函数指针数组,数组里每个元素都是函数指针,指向一个形参为空,返回值为函数指针,该指针指向一个形参为空,返回值int *
float (*(*b())[])();
b:函数,形参为空,返回值为指针,指针指向一个数组,数组里的每个元素都是指针,这些指针指向函数,函数的形参为空,返回值为float
十可变参数
-
可变参数的实现原理
-
形参在栈空间上开辟空间的地址是连续的
-
三个宏
-
void va_start(va_list arg_ptr,prev_param);//va_list可变参数的类型
-
type va_arg(va_list arg_ptr,type);
-
void va_end(va_list arg_ptr);