1.函数的定义
在计算机科学中,子程序(英语:Subroutine, procedure, function, routine, method, subprogram, callable unit),是一个大型程序中的某部分代码, 由一个或多个语句块组 成。它负责完成某项特定任务,而且相较于其他代 码,具备相对的独立性。 一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软 件库。
2.C语言中函数的分类
2.1库函数
//使用库函数的例子,如strcpy //char* strcpy(char* destination, const char* source); //解释:把source指向的的字符串复制给destination #include <stdio.h> #include <string.h> int main() { char arr1[20] = { 0 }; char arr2[] = "hello bit"; strcpy(arr1, arr2); printf("%s", arr1);//hello bit return 0; }
//memset
//void* memset(void* ptr, int value, size_t num);
//解释:把指针ptr开始后num个字节的字符设置为value
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "hello bit";
memset(arr, 'x', 5);
printf("%s\n", arr);//xxxxx bit
return 0;
}
//sizeof
//sizeof是一个操作符
//是用来计算变量(类型)所占内存空间的大小,不关注内存中存放的具体内容
//单位是字节
//strlen
//strlen是一个库函数,是专门求字符串长度的,只能针对字符串
//从参数给定的地址向后一直找\0,统计\0之前出现的字符的个数
#include<stdio.h>
int main()
{
char str[] = "hello bit";//[hello bit\0]
printf("%d %d", sizeof(str), strlen(str));//10 9
return 0;
}
2.2自定义函数
//写一个函数可以找出两个整数中的最大值
#include<stdio.h>
int get_max(int x, int y)
{
return (x > y) ? (x) : (y);
}
int main()
{
int num1 = 10;
int num2 = 20;
int max = get_max(num1, num2);
printf("max = %d\n", max);//max = 20
return 0;
}
//写一个函数 - 交换2个整型变量的值(以下是错误代码) //函数返回类型的地方写出:void,表示这个函数不返回任何值,也不需要返回 //swap1在被调用的时候,实参传给形参,其实形参是实参的一份临时拷贝 //改变形参,不能改变实参 #include<stdio.h> void Swap1(int x, int y) { int z = 0; z = x; x = y; y = z; } int main() { int a = 10; int b = 20; printf("交换前:a=%d b=%d\n", a, b);//a=10 b=20 //传值调用 Swap1(a, b);//a,b叫实参 printf("交换后:a=%d b=%d\n", a, b);//err - a=10 b=20;没有发生变化 return 0; } //写一个函数 - 交换2个整型变量的值(以下是正确代码) #include<stdio.h> void Swap2(int* pa, int* pb) { int z = 0; z = *pa; *pa = *pb; *pb = z; } int main() { int a = 10; int b = 20; printf("交换前:a=%d b=%d\n", a, b);//a=10 b=20 Swap2(&a, &b);//传址调用 printf("交换后:a=%d b=%d\n", a, b);//a=20 b=10 return 0; }
3.函数的参数
形参是实参的一份临时拷贝。
4.函数的调用
//传址调用
//代码1
#include<stdio.h>
void test(int arr[])
{
arr[0] = 1;
arr[1] = 2;
}
int main()
{
int arr[2] = { 0 };
test(arr);
printf("%d %d\n", arr[0], arr[1]);//1 2
return 0;
}
//代码2
#include<stdio.h>
void test(int*p1, int *p2)
{
*p1 = 1;
*p2 = 2;
}
int main()
{
int a = 0;
int b = 0;
test(&a, &b);
printf("%d %d\n", a, b);//1 2
return 0;
}
5.函数的嵌套调用和链式访问
5.1嵌套调用
//嵌套调用
//函数和函数之间可以根据实际的需求进行组合的,也就是互相调用的
#include <stdio.h>
void new_line()
{
printf("hehe\n");
}
void three_line()
{
int i = 0;
for (i = 0; i < 3; i++)
{
new_line();
}
}
int main()
{
three_line();
return 0;
}
//函数可以嵌套调用,但是不能嵌套定义
//嵌套定义
#include<stdio.h>
int Add(int x, int y)
{
return x + y;
int sum(int x, int y)
{
return x - y;
}
}
int main()
{
int a = 0;
int b = 0;
Add(a, b)
return 0;
}
5.1.1例题
//写一个函数,每调用一次这个函数,就会将 num 的值增加1
//(方法1)
#include<stdio.h>
void Add(int* p)
{
(*p)++;
}
int main()
{
int num = 0;
Add(&num);
printf("%d\n", num);//1
Add(&num);
printf("%d\n", num);//2
Add(&num);
printf("%d\n", num);//3
return 0;
}
//(方法2)
#include<stdio.h>
int Add(int n)
{
return ++n;
}
int main()
{
int num = 0;
num = Add(num);
printf("%d\n", num);//1
num = Add(num);
printf("%d\n", num);//2
num = Add(num);
printf("%d\n", num);//3
return 0;
}
5.2链式访问
//把一个函数的返回值作为另外一个函数的参数
//链式访问
#include<stdio.h>
int main()
{
int len = strlen("abc");//3
printf("%d\n", len);
//链式访问
printf("%d\n", strlen("abc"));//3
printf("%d", printf("%d", printf("%d", 43)));//4321,因为printf的返回值是打印的字符的个数
return 0;
}
6.函数的声明和定义
#include<stdio.h> int main() { int a = 10; int b = 20; int Add(int x, int y);//函数声明一下 - 告知 int c = Add(a, b); printf("%d\n", c); return 0; } //函数的定义 int Add(int x, int y) { return x + y; }
7.函数的递归
7.1例题
7.1.1例题1
接受一个整型值(无符号),按照顺序打印它的每一位。 例如: 输入:1234,输出 1 2 3 4 #include <stdio.h> void print(int n) { if (n > 9) { print(n / 10); } printf("%d ", n % 10); } int main() { int num = 1234; print(num);//1 2 3 4 return 0; }
7.1.2例题2
//编写函数不允许创建临时变量,求字符串的长度 //代码1 #include <stdio.h> int my_strlen(char* str) //等价于int my_strlen(char str[]) { int count = 0; while (*str != '\0') { count++; str++; } return count; } int main() { char arr[] = "abcdef";//[abcdef\0] int len = my_strlen(arr); printf("%d\n", len);//6 return 0; }
//代码2 #include <stdio.h> int Strlen(const char* str) { if (*str != '\0') return 1 + Strlen(str + 1); else return 0; } int main() { char* p = "abcdef"; int len = Strlen(p); printf("%d\n", len);//6 return 0; }
8.函数的递归与迭代
//求n的阶乘
//递归
int Fac(int n)
{
if (n <= 1)
return 1;
else
return n * Fac(n - 1);
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fac(n);
printf("%d\n", ret);
return 0;
}
//迭代
#include<stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
int i = 0;
int ret = 1;
for (i = 1; i <= n; i++)
{
ret = ret * i;
}
printf("%d\n", ret);
return 0;
}
//求第n个斐波那契数 //递归 #include<stdio.h> int Fib(int n) { //统计第3个斐波那契数的计算机次数 if (n == 3) count++; if (n <= 2) return 1; else return Fib(n - 1) + Fib(n - 2); } int main() { int n = 0; scanf("%d", &n); int ret = Fib(n); printf("%d\n", ret); printf("count = %d\n", count); return 0; } //迭代 int Fib(int n) { int a = 1; int b = 1; int c = 1; while (n>2) { c = a + b; a = b; b = c; n--; } return c; } int main() { int n = 0; scanf("%d", &n); int ret = Fib(n); printf("%d\n", ret); return 0; }
9.练习
//打印100-200之间的素数
//素数是只能被1和它本身整除的数
//代码1
#include<stdio.h>
int main()
{
int i = 0;
int count = 0;
for (i = 100; i <= 200; i++) //for(i = 101; i <= 200; i + 2),偶数不是素数
{
//判断i是否为素数
//是素数就打印
//拿2~i-1之间的数字去试除i
int flag = 1;//flag是1,表示是素数
int j = 0;
for (j = 2; j <= i - 1; j++) //也可以写成for(j=2; j<=sqrt(i); j++),sqrt是开平方
{
if (i % j == 0)
{
flag = 0;
break;
}
}
if (flag == 1)
{
count++;
printf("%d ", i);
}
}
printf("\ncount = %d\n", count);
return 0;
}
//打印100-200之间的素数(函数版本)
//代码2
#include<stdio.h>
#include<math.h>
int is_prime(int n)
{
int j = 0;
for (j = 2; j <= sqrt(n); j++)
{
if (n % j == 0)
return 0;
}
return 1;
}
int main()
{
int i = 0;
int count = 0;
for (i = 101; i <= 200; i+=2)//注意这里不能写成i+2
{
if (is_prime(i) == 1)
{
printf("%d ", i);
count++;
}
}
printf("\ncount = %d\n", count);
return 0;
}
//写一个函数打印1000-2000之间的闰年
//如果判断是闰年返回1
//不是闰年,返回0
//一个函数如果不写返回类型,默认返回int类型
#include<stdio.h>
int is_leap_year(int n)
{
if ((n % 4 == 0 && n % 100 != 0) || (n % 400 == 0))
return 1;
else
return 0;
}
int main()
{
int y = 0;
for (y = 1000; y <= 2000; y++)
{
if (is_leap_year(y) == 1)
{
printf("%d ", y);
}
}
return 0;
}
//写一个函数,实现一个整形有序数组的二分查找
#include<stdio.h>
int binary_search(int arr[], int k, int s) //arr是一个指针变量,arr[]存储的是数组首元素的地址
{
int left = 0;
int right = s - 1;
while (left <= right)
{
int mid = (left + right) / 2;
if (arr[mid] > k)
{
right = mid - 1;
}
else if (arr[mid] < k)
{
left = mid + 1;
}
else
{
return mid;
}
}
return -1;//找不到了
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int key = 7;
//找到了就返回找到的位置的下标
//找不到返回-1
//数组arr传参,实际传递的不是数组的本身
//仅仅传过去了数组首元素的地址
int sz = sizeof(arr) / sizeof(arr[0]);
int ret = binary_search(arr, key, sz);
if (-1 == ret)
{
printf("找不到\n");
}
else
{
printf("找到了,下标是:%d\n", ret);
}
return 0;
}
//布尔(bool)类型
//判断真假,真的返回true,假的返回false
#include<stdio.h>
#include<stdbool.h>
#include<math.h>
bool is_prime(int n)
{
int j = 0;
for (j = 2; j <= sqrt(n); j++)
{
if (n % j == 0)
return false;
}
return true;
}
int main()
{
int i = 0;
for (i = 101; i <= 200; i+=2)
{
if (is_prime(i))
{
printf("%d ", i);
}
}
return 0;
}
//将三个整数由大到小输出
void swap(int* px, int* py)
{
int tmp = *px;
*px = *py;
*py = tmp;
}
int main()
{
int a = 0;
int b = 0;
int c = 0;
int max = 0;
scanf("%d %d %d", &a, &b, &c);
if (a < b)
{
swap(&a, &b);
}
if (a < c)
{
swap(&a, &c);
}
if (b < c)
{
swap(&b, &c);
}
printf("%d %d %d\n", a, b, c);
return 0;
}
//实现一个函数,打印乘法口诀表,口诀表的行数和列数自己指定
#include<stdio.h>
void print_table(int n)
{
int i = 0;
for (i = 1; i <= n; i++)
{
//打印一行
int j = 0;
for (j = 1; j <= i; j++)
{
printf("%d*%d=%-2d ", i, j, i * j);//-2d的意思是打印两位并且左对齐
}
printf("\n");
}
}
int main()
{
int n = 0;
scanf("%d", &n);
print_table(n);
return 0;
}
// 字符串逆序
// 将参数字符串中的字符反向排列(改变原字符串),不是逆序打印
// 比如:char arr[] = "abcdef"
//逆序之后为:fedcba
// 迭代
#include <stdio.h>
int main()
{
char arr[] = "abcdef"; //[a b c d e f \0]
int sz = sizeof(arr) / sizeof(arr[0]);
int left = 0;
int right = sz - 2;//strlen(arr)-1
while (left < right)
{
char tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
printf("%s\n", arr);//fedcba
return 0;
}
//函数
#include<stdio.h>
void reverse(char arr[])
{
int left = 0;
int right = strlen(arr) - 1;
while (left < right)
{
char tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
}
int main()
{
char arr[] = "abcdef"; //[a b c d e f \0]
reverse(arr);
printf("%s\n", arr);//fedcba
return 0;
}
//递归1
#include<stdio.h>
int my_strlen(char* str)
{
int count = 0;
while(*str != '\0')
{
str++;
count++;
}
return count;
}
void reverse(char* str)
{
char tmp = *str;//将字符串的第一个字符赋值给一个变量tmp
int len = my_strlen(str);//计算字符串的字符数
*str = *(str + len - 1);//将字符串的最后一个字符赋值给字符串的第一个字符
*(str + len - 1) = '\0';//将字符串的最后一个字符赋值为\0
if (strlen(str + 1) >= 2)//如果字符串的字符数>=2,则继续调用自己
reverse(str + 1);
*(str + len - 1) = tmp;//将tmp包含的字符串的第一个字符赋值给字符串的最后一个字符
}
int main()
{
char arr[] = "abcdef"; //[a b c d e f \0]
reverse(arr);
printf("%s\n", arr);//fedcba
return 0;
}
//递归2
#include<stdio.h>
int my_strlen(char* str)
{
int count = 0;
while (*str != '\0')
{
str++;
count++;
}
return count;
}
void reverse(char arr[], int left, int right)
{
char tmp = arr[left];//将首字符与末尾字符互换
arr[left] = arr[right];
arr[right] = tmp;
if (left+1 < right-1)//若下一次的左字符小于右字符,才继续递归
reverse(arr, left+1, right-1);
}
int main()
{
char arr[] = "abcdefg"; //[a b c d e f \0]
int left = 0;
int right = my_strlen(arr) - 1;
reverse(arr, left, right);
printf("%s\n", arr);//fedcba
return 0;
}
//计算一个数的每位之和(递归实现)
//写一个递归函数DigitSum(1729),输入一个非负整数,返回组成它的数字之和
//例如:调用DigitSum(1729),返回1+7+2+9,和为19
//输入:1729 输出:19
#include<stdio.h>
int DigitSum(unsigned int n)
{
if (n > 9)
return DigitSum(n / 10) + (n % 10);
else
return n;
}
int main()
{
unsigned int n = 0;//无符号整数不为负数
scanf("%u", &n);
int sum = DigitSum(n);
printf("%d\n", sum);
return 0;
}
//编写一个函数实现n的k次方,使用递归实现
//k = 0,1
//k > 0,Pow(n, k) -> n*Pow(n, k-1)
//k < 0,1.0/Pow(n, -k)
#include<stdio.h>
double Pow(int n, int k)
{
if (k > 0)
return n * Pow(n, k - 1);
else if (k == 0)
return 1;
else
return 1.0 / Pow(n, -k);
}
int main()
{
int n = 0;
int k = 0;
scanf("%d %d", &n, &k);
double ret = Pow(n, k);
printf("%lf\n", ret);
return 0;
}
//实现函数init() 初始化数组为全0
//实现print() 打印数组的每个元素
//实现reverse() 函数完成数组元素的逆置。
#include<stdio.h>
void init(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
arr[i] = 0;
}
}
void print(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
void reverse(int arr[], int sz)
{
int left = 0;
int right = sz - 1;
while (left<right)
{
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
print(arr, sz);//1 2 3 4 5 6 7 8 9 10
reverse(arr, sz);
print(arr, sz);//10 9 8 7 6 5 4 3 2 1
init(arr, sz);
print(arr, sz);//0 0 0 0 0 0 0 0 0 0
return 0;
}
#include<stdio.h> int fib(int n) { if (n <= 2) return n; else return fib(n - 1) + fib(n - 2); } int main() { int n = 0; scanf("%d", &n); int m = fib(n); printf("%d\n", m); return 0; }
//写一个函数,可以逆序一个字符串的内容
#include<stdio.h>
int main()
{
char arr[10001] = { 0 };
gets(arr); //可以读取空格
int len = strlen(arr);
int left = 0;
int right = len - 1;
while (left < right)
{
char tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
printf("%s\n", arr);
return 0;
}
//求出0-100000之间的所有“水仙花数”并输出。
//“水仙花数”是指一个n位数,其各位数字n的次方之和恰好等于该数本身,如:153=1^3+5^3+3^3
#include<stdio.h>
#include<math.h>
int main()
{
int i = 0;
for (i = 0; i <= 100000; i++)
{
int n = 1;
int tmp = i;//防止改变i的大小
int sum = 0;
//计算i是几位数
while (tmp/10)
{
n++;
tmp /= 10;
}
tmp = i;
//得到i的每一位,计算它的n次方之和
while (tmp)
{
sum += pow(tmp % 10, n);
tmp /= 10;
}
//判断是否为水仙花数
if (sum == i)
{
printf("%d ", sum);
}
}
return 0;
}
//输入一个整数数组,实现一个函数,
//来调整该数组中数字的顺序使得数组中所有的奇数位于数组的前半部分,
//所有偶数位于数组的后半部分
#include<stdio.h>
void print(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
void move(int arr[], int sz)
{
int left = 0;
int right = sz - 1;
while (left<right)
{
//从左往右找一个偶数,停下来
while ((left<right) && (arr[left] % 2 == 1))
{
left++;
}
//从右往左找一个奇数,停下来
while ((left<right) && (arr[right] % 2 == 0))
{
right--;
}
//交换奇数和偶数
if (left < right)
{
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
}
left++;
right--;
}
}
int main()
{
int arr[] = { 0 };
int i = 0;
int sz = sizeof(arr)/sizeof(arr[0]);
for (i = 0; i < sz; i++)
{
scanf("%d", &arr[i]);//arr+i - 输入
}
move(arr, sz);//调整
print(arr, sz);//输出
return 0;
}
//实现一个函数,可以左旋k个字符
//代码1
#include<stdio.h>
void left_rotate(char arr[], int k)
{
int len = strlen(arr);
//k不论多大也不会超过字符数,超过字符数的话会减去字符数的大小
k %= len;
int j = 0;
int i = 0;
for (i = 0; i < k; i++)
{
char tmp = arr[0];
for (j = 0; j < len - 1; j++)
{
arr[j] = arr[j + 1];
}
arr[len - 1] = tmp;
}
}
int main()
{
char arr[] = "abcdef";
int k = 0;
scanf("%d", &k);
left_rotate(arr, k);
printf("%s\n", arr);
return 0;
}
//代码2
#include<stdio.h>
#include<assert.h>
void reverse(char* left, char* right)
{
assert(left && right);
while (left < right)
{
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
//将字符串分成两个部分,分别逆序,然后再总体逆序
void left_rotate(char arr[], int k)
{
int len = strlen(arr);
k %= len;
reverse(arr, arr + k - 1);
reverse(arr + k, arr + len - 1);
reverse(arr, arr + len - 1);
}
int main()
{
char arr[] = "abcdef";
int k = 0;
scanf("%d", &k);
left_rotate(arr, k);
printf("%s\n", arr);
return 0;
}
//代码1 #include<stdio.h> int is_left_move(char arr1[], char arr2[]) { int len = strlen(arr1); int j = 0; int i = 0; for (i = 0; i < len; i++) { char tmp = arr1[0]; for (j = 0; j < len - 1; j++) { arr1[j] = arr1[j + 1]; } arr1[len - 1] = tmp; if (strcmp(arr1, arr2) == 0) return 1; } } int main() { char arr1[] = "abcdef"; char arr2[] = "cdefab"; //判断arr2中的字符能否由arr1中的字符旋转得到 int ret = is_left_move(arr1, arr2); if (ret == 1) printf("ok\n"); else printf("no\n"); return 0; } //代码2 #include<stdio.h> #include<string.h> int is_left_move(char arr1[], char arr2[]) { int len1 = strlen(arr1); int len2 = strlen(arr2); if (len1 != len2)//如果两个字符串长度不一样,那么肯定不是旋转得到的 return 0; strncat(arr1, arr1, len1);//自己追加自己 char* ret = strstr(arr1, arr2); if (ret == NULL) return 0; else return 1; } int main() { char arr1[20] = "abcdef"; char arr2[] = "cdefab"; int ret = is_left_move(arr1, arr2); if (ret == 1) printf("ok\n"); else printf("no\n"); return 0; }
//一个数组中只有两个数出现一次,其它所有数字都出现了两次
//编写一个函数找出这两个只出现一次的数字
#include<stdio.h>
void find_single_dog(int arr[], int sz, int* pd1, int* pd2)
{
int i = 0;
int ret = 0;
//1、数组所有元素进行异或
for (i = 0; i < sz; i++)
{
ret ^= arr[i];
}
//2、计算ret的二进制中右边第几位是1
int pos = 0;
for (pos = 0; pos < 32; pos++)
{
if (((ret >> pos) & 1) == 1)
{
break;
}
}
for (i = 0; i < sz; i++)
{
if (((arr[i] >> pos)&1) == 1)
{
*pd1 ^= arr[i];
}
else
{
*pd2 ^= arr[i];
}
}
}
int main()
{
int arr[] = { 1,2,3,4,5,6,1,2,3,4 };
int sz = sizeof(arr) / sizeof(arr[0]);
int dog1 = 0;
int dog2 = 0;
find_single_dog(arr, sz, &dog1, &dog2);
printf("%d %d", dog1, dog2);
//分组
// 1、所有数字异或
// 2、找出异或的结果数字中二进制的哪一位为1 - n
// 3、若第n位为1,分一组;第n位为0,分一组
//5^6
//101 - 5 1 1 3 3
//110 - 6 2 2 4 4
//011
return 0;
}