目录
1.函数是什么?
y=f(x)这是数学中的函数。在C语言中的函数是:子程序。
子程序是大型程序中的某部分代码,由一个或多个语句块组成,它负责完成某项特定任务,而且相较于其他代码,具备相对的独立性。一般有输入参数并有返回值(可以没有),提供对过程的封装和细节的隐藏。这些代码通常被集成软件库。
2.C语言中函数的分类
- 1.库函数
- 2.自定义函数
库函数是C语言本身提供给我们可以直接使用的函数,比如说printf()函数,strlen()函数,system()函数,strcmp()函数等都是库函数。
自定义函数是自己创造实现的一种函数。
2.1库函数
为什么会有库函数呢?
支持可移植性(跨平台性)和提高程序的效率,把常用的函数提供给我们使用。
怎么学习库函数呢?
学习网址:(电脑端)
Reference - C++ Reference (cplusplus.com)
C语言常用的库函数有:
- IO函数:输入输出函数(如scanf、printf、getchar、putchar)
- 字符串操作函数:与字符串相关的(如strcmp)
- 字符操作函数
- 时间/日期函数
- 数学函数
- 其他库函数
使用库函数,必须包含#include对应的头文件。
如一个库函数:1.strlen()(函数名)
size_t strlen ( const char * str );
Get string length
strlen()函数的参数是:const char * str;返回类型是:size_t
作用是:获取字符串长度,返回的是无符号整型(size_t)
即使用时是:传一个字符串给它(放在它的括号里),然后再把它的返回值((size_t)类型)接收一下。
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "abc";
int len = strlen(arr);//返回值保存起来放到len里
printf("%d", len);
//printf("%s",len)是错误的。返回的值是打印的值,是整型。
return 0;
}//3
更标椎的写法:
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "abc";
size_t len = strlen(arr);
printf("%u", len);
return 0;
}//3
//因为size_t—>unsigned int
//打印无符号字符串时用%u
所以:
%d——打印有符号整数,能打印出正负;
%u——打印无符号整数,打印正数。
2.strcpy库函数——功能是:拷贝一个字符串
char *strcpy( char *strDestination, const char *strSource );
目的地 源头
char *是一种指针,即strcpy的参数是两个指针:strDestination和strSource
返回类型也是char *也是一种指针。
指针存放的是地址。所以传的参数是地址。
即意思是:把源头拷贝到目的地中。
返回的是:目的地,即返回的是目标字符串
strDestination是目的地字符串,strSource 是源字符串
在文档中看到的Null表达的意思是\0
#include<stdio.h>
#include<string.h>
int main()
{
//把arr2中内容拷贝到的arr1
char arr1[20] = {0};//目的地
char arr2[] = "HELLO";//源数据
strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}//HELLO
3.memset库函数——功能:为一个指针设置内存
void *memset( void *dest, int c, size_t count );
void *dest:dest是设置内存块的起始位置即目的地,指向目的地的指针dest。要设置哪个空间,初始化哪个空间dest就是谁。
int c:c是设置的字符
size_t count :count是设置字符的个数
即函数的意思是:把从dest位置开始向后的count个字节的内容初始化我们想要的c里放的字符。
函数返回的是:dest
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "hello world";
//把hello改成xxxxx,h开始,就是目的地
memset(arr,'x',5);
printf("%s", arr);
//先把arr传过去,数组名代表的是数组首个元素(h)的地址,要改成x字符,把x传过去,要改5个字符。
return 0;
}//xxxxx world
注意:int c是整型,这里传的是字符x,因为字符本身是ASCII值。
4、scanf()函数
scanf()函数在读取正常的时候会返回有效数字1(因为只读一个数字);在读取失败的时候会返回EOF,利用这个特点可以写多组输入。
(OJ在线判题中题型分为I/O型和接口型,这两种都又分为一组输入和多组输入,大多是多组输入。接口型只需完成规定的函数就可以了)。
如果scanf()返回的结果不等于EOF,说明读取正常。
//判断整数奇偶性——一组输入(只能输入一个判断一个)
#include <stdio.h>
int main()
{
int m = 0;
scanf("%d", &m);
if (m % 2 == 1)
{
printf("Odd\n");
}
else
{
printf("Even\n");
}
return 0;
}
//判断整数奇偶性——多组输入(可以输入多个判断多个)
#include <stdio.h>
int main()
{
int m = 0;
while (scanf("%d", &m) != EOF)
{
if (m % 2 == 1)
{
printf("Odd\n");
}
else
{
printf("Even\n");
}
}
return 0;
}
有些编译器下可以Ctrl+z结束循环。
EOF——end of file的缩写,文件的结束标志,一般放在文件末尾,作为文件的结束标志而存在的。scanf()函数本身读取失败的时候会返回EOF。
多组输入还可以写成~的形式:
#include <stdio.h>
int main()
{
int m = 0;
while (~scanf("%d", &m))
{
if (m % 2 == 1)
{
printf("Odd\n");
}
else
{
printf("Even\n");
}
}
return 0;
}
因为:
EOF的本质是-1
-1的在内存中存储的补码是:11111111111111111111111111111111
~EOF是:00000000000000000000000000000000(~是取反)
全0为假,即不会进入循环。
这种写法也对,说明当scanf()函数返回的结果是EOF时循环就停下。
借此题再看一道例题:判断是元音还是辅音
——输入描述:多组输入,每行输入一个字母。
——输出描述:针对每组输入,输出为一行,如果输入字母是元音(包括大小写),输出“Vowel”,如果输入字母是非元音,输出“Consonant”。
#include <stdio.h>
int main()
{
char ch = 0;
char v[] = { 'a','A','e','E','i','I','o','O','U','u' };
while (~scanf("%c", &ch))
{
//遍历数组
int i = 0;
for (i = 0; i < 10; i++)
{
if (ch == v[i])
{
printf("Vowel\n");
break;
}
}
if (i == 10)
{
printf("Consonant\n");
}
//清理缓冲区中的\n
getchar();
}
return 0;
}
注意:无论是scanf()函数还是getchar()函数他们在读取数据的时候是从缓冲区读的,在键盘和函数之间还放了一个缓冲区。
scanf在读取字符的时候,为了让它读取在输入数字(例如输入了a)后面还敲了\n,而scanf()函数只读取%c一个字符,当敲了一个a和\n的时候,a拿走放进ch里处理会打印Vowel,当下一次sxanf()读取的时候,缓冲区还有\n,scanf就把\n拿走了,\n放到ch里,\n不是元音字母还会打印Consonant,即\n会干扰打印结果。所以需要清理掉\n,即用getchar()函数把刚刚留下的\n拿走,达到清理缓冲区的作用。
或者:
while (~scanf("%c", &ch))—变成—>while (~scanf("%c\n", &ch))
#include <stdio.h>
int main()
{
char ch = 0;
char v[] = { 'a','A','e','E','i','I','o','O','U','u' };
while (~scanf("%c\n", &ch))
{
int i = 0;
for (i = 0; i < 10; i++)
{
if (ch == v[i])
{
printf("Vowel\n");
break;
}
}
if (i == 10)
{
printf("Consonant\n");
}
}
return 0;
}
%c是从缓冲区拿走一个字符,后面如果有\n,则也会把缓冲区的\n顺便拿走——这种方法仅限于拿字符的时候可以拿走\n,拿整形的时候是不起效果的。
或者:
while (~scanf("%c", &ch))—变成—>while (~scanf(" %c", &ch))
#include <stdio.h>
int main()
{
char ch = 0;
char v[] = { 'a','A','e','E','i','I','o','O','U','u' };
while (~scanf(" %c", &ch))
{
int i = 0;
for (i = 0; i < 10; i++)
{
if (ch == v[i])
{
printf("Vowel\n");
break;
}
}
if (i == 10)
{
printf("Consonant\n");
}
}
return 0;
}
在%c的前面加上空格,会跳过空白字符。因为\n是看不见的空白字符,跳过\n也就相当于清理掉缓冲区的\n了。第一次输入a时a前面没有空白字符,scanf()直接拿走a,\n还在缓冲区,当下一次输入字符如b时,本质是想读b,因为在b之前还留有刚刚的\n,则跳过\n直接拿b。
2.2自定义函数
自己创建的函数(程序员也是艺术家,创造函数)
自定义函数和库函数一样,有函数名,返回值类型和函数参数。但不一样的是这些都是我们自己来设计——这给程序员很大的发挥空间。
前面一个库函数的讲解:
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "abc";
size_t len = strlen(arr);
//strlen是函数名,传给strlen的是它的参数arr,返回的值放到Len里面了。
printf("%u", len);
return 0;
}
函数的基本组成:
ret_type fun_name(paral, *)
{
statement;//语句项
}
ret_type 函数返回类型
fun_name 函数名
paral 函数参数
大括号括的是函数体,函数体里是语句项
举例:
写一个函数可以找出两个整数中的最大值
代码展示:(用的是自定义的函数)
#include<stdio.h>
int get_max(int x, int y)
{
int z = 0;
z = (x > y ? x : y);
return z;
}
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
int m = get_max(a, b);
printf("%d\n", m);
return 0;
}
代码讲解:
#include<stdio.h>
//a和b是两个整数,传给get_max()函数,则int x来接收,int y来接收
int get_max(int x,int y)
{
//当x和y的较大值找到后就需要返回——创建z变量,z求出x和y的较大值
int z = 0;
z = (x > y ? x : y);
//x大于y吗?如果大于,那较大值就是x,否则就是y
return z;
}
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
//写一个函数:get_max——获取最大值
//get_max();算出a和b的较大值,则传进去a和b
//get_max(a, b);找到较大值,要告诉较大值是几,则返回较大值,则把较大值放到m里去
int m = get_max(a, b);//即get_max就把a和b的较大值找出来返回放到m中
printf("%d\n", m);
return 0;
}//还没有这个函数get_max,则在主函数上面创造
这里实现get_max函数时,get_max就是函数名,int x和int y是两个参数,即a和b传的就是它——这是输入操作
int z = 0;
z = (x > y ? x : y);//这两行是加工制造,最后return z;把算出的z再返回来。因为z的类型是int,所以在int get_max(int x, int y)前面写了int
所以get_max函数返回的是整型值,所以接收时也用整型来接收,所以是int m
(所以函数返回类型,函数返回值,接收值这三者是相呼应的)
上述函数只有一个语句块({}),有返回值。
如没有返回值的函数:menu()函数,只需要它打印菜单。
上述函数若x=y则返回x或y都可以,若x<=y则返回y。
#include<stdio.h>
void menu()
{
printf("******* 1.play *******\n");
printf("******* 0.exit *******\n");
}
int main()
{
menu();
return 0;
}//******* 1.play *******
//******* 0.exit *******
调用一次,在屏幕上就打印一次;
调用两次,就在屏幕上打印两次。
#include<stdio.h>
void menu()
{
printf("******* 1.play *******\n");
printf("******* 0.exit *******\n");
}
int main()
{
menu();
return 0;
}//*