今天分享一些练习题🙂🙂,快开学了,烦躁的很。
1.乘法口诀表 2.交换两个整数 3.函数判断闰年 4.函数判断素数 5.计算斐波那契数 6.递归实现n的k次方 7.计算一个数的每位之和(递归实现) 8.字符串逆序(递归实现) 9.strlen的模拟(递归实现) 10.求阶乘 11.打印一个数的每一位 12.使用函数实现数组操作 13.冒泡排序 14.【一维数组】交换数组
1.乘法口诀表
//题目1 //乘法口诀表 //实现一个函数,打印乘法口诀表,口诀表的行数和列数自己指定 如:输入9,输出9*9口诀表,输出12,输出12*12的乘法口诀表。 //乘法口诀表 //1*1=1 //2*1=2 2*2=4 .... //3*1=3 3*2=6 .... //.... //嵌套循环 //先打印行再打印列 //美观 //2d占两个位置,d占一个位置 //-2d是左对齐两个位置
//题目1 #include<stdio.h> void test(int n)//实现乘法口诀 { int i = 1; int j = 1; for (i = 1; i <= n; i++)//1 2... { for (j = 1; j <= i; j++)//1 2... { printf("%-d*%-d=%-2d ", i, j, i * j);//-2d左对齐两个空位 } printf("\n"); } } int main() { int n = 0; scanf("%d", &n);//输入一个数字 test(n); return 0; }
2.交换两个整数
//题目2 //交换两个整数 //实现一个函数来交换两个整数的内容。 //传值VS传址
//题目2 //交换两个整数 #include<stdio.h> void test1(int a, int b)//传值不能改变ab { int tmp = 0; tmp = a; a = b; b = tmp; } void test2(int* pa, int* pb)//传值不能改变ab { int tmp = 0; tmp = *pa; *pa = *pb; *pb = tmp; } int main() { int a = 0; int b = 0; scanf("%d %d", &a, &b); test1(a,b); printf("a=%d b=%d\n", a, b); test2(&a, &b); printf("a=%d b=%d", a, b); return 0;
3.函数判断闰年
//题目3 //函数判断闰年 //实现函数判断year是不是润年。 //能被4整除同时不能被10整除 //或者能被40整除
//题目3 //判断闰年 #include<stdio.h> int test(int year) { if (((year % 4 == 0) && (year % 10 != 0 ))|| (year % 40 == 0)) return 1; else return 0; } int main() { int year = 0; scanf("%d", &year); int ret=test(year); if (ret == 1) printf("是闰年\n"); if (ret == 0) printf("不是闰年\n"); return 0; }
4.函数判断素数
//题目4 //函数判断素数 //实现一个函数is_prime,判断一个数是不是素数。 利用上面实现的is_prime函数,打印100到200之间的素数。 //除到sqrt(i) //奇数
//题目四 //函数判断素数 #include<stdio.h> #include<math.h> void is_prime(int i) { int j = 0; int flag = 0; for (j = 2; j < sqrt(i); j++) { if (i % j == 0)//(0==i%j) { flag = 1; break;//不是素数 } } if (flag == 0) printf("%d ", i); } int main() { int i = 0; for (i = 100; i <= 200; i++)//进入100~200之间的数 { is_prime(i);//函数实现 } return 0; }
5.计算斐波那契数
//题目5 //计算斐波那契数 //递归和非递归分别实现求第n个斐波那契数 例如: 输入:5 输出:5 输入:10, 输出:55 输入:2, 输出:1 //1 1 2 3 5 8 13 21.... //a b c // a b c
//题目五 //计算斐波那契数 //递归 //1 1 2 3 5 8 13.... #include<stdio.h> int test(int n) { if (n <= 2) return 1; else return test(n - 2) + test(n - 1); } int main() { int n = 0; scanf("%d", &n); int ret = test(n); printf("%d", ret); return 0; }
//非递归 #include<stdio.h> int main() { int n = 0; scanf("%d", &n);//输入查找的数 int a = 1; int b = 1; int c = 2; while(n>3) { //进入循环c必须是2 a = b; b = c; c = a + b; n--; } printf("%d",c); return 0; } #include<stdio.h> int main() { int n = 0; scanf("%d", &n);//输入查找的数 int a = 1; int b = 1; int c = 1;//当n<2 输出1 while (n > 2) { //进入循环c必须是2 c = a + b; a = b; b = c; n--; } printf("%d", c); return 0; }
6.递归实现n的k次方
//题目6 //递归实现n的k次方 //编写一个函数实现n的k次方,使用递归实现。 //n的k次方==n*n的k-1次方==n*n*n的k-2次方 //如果k=0无论k是几都输出1 //如果n>0,则return n*test(n,k-1) //如果n<0,则1/n的k次方也就是。1/n的k次方→转化成正数计算
//题目六 //递归实现n的k次方 #include<stdio.h> double test(int n, int k) { if (k == 0) return 1; else if (k > 0) return n * test(n, k - 1); else return 1.0 / test(n, -k);//转化成k>0去计算 //return (1.0 / n) * test(1.0 / n, (-k)-1);❌ //因为这里会-k-1会跳转到k>0,就不是(1/n)了 } int main() { int n = 0; int k = 0; scanf("%d %d", &n, &k); double ret=test(n, k); printf("%lf", ret); return 0; }
7.计算一个数的每位之和(递归)
//题目7 //计算一个数的每位之和(递归) //写一个递归函数DigitSum(n),输入一个非负整数,返回组成它的数字之和 例如,调用DigitSum(1729),则应该返回1+7+2+9,它的和是19 输入:1729,输出:19
//题目七 //计算一个数的每位之和 #include<stdio.h> int test(int n) { if (n <= 9)//个位数 return n; else return test(n / 10)+n%10; } int main() { int n = 0; scanf("%d", &n); int ret = test(n); printf("%d", ret); return 0; }
8.字符串逆序(递归实现)
//题目8 //字符串逆序(递归实现) //编写一个函数 reverse_string(char * string)(递归实现) 实现:将参数字符串中的字符反向排列,不是逆序打印。 要求:不能使用C函数库中的字符串操作函数。 比如: char arr[] = "abcdef"; 逆序之后数组的内容变成:fedcba
非递归
//非递归 #include<stdio.h> void reverse_string(char arr[], int sz) { int left = 0; int right = sz-2;//易错 while (left < right) { char tmp = arr[left]; arr[left] = arr[right]; arr[right] = tmp; left++; right--; } } int main() { char arr[] = "abcdef"; int sz = sizeof(arr)/sizeof(arr[0]); reverse_string(arr,sz); printf("%s\n", arr); return 0; }
递归
//递归 #include<stdio.h> void reverse_string(char s[]) { size_t len = strlen(s);//计算的是\0前面的字符串的长度 char tmp = s[0]; s[0] = s[len - 1]; s[len-1] = '\0'; if (strlen(s + 1) >= 2) //需要加上\0,因为把置换right修改成了\0 //逆序元素个数必须大于等于2才可以逆序 reverse_string(s + 1); s[len - 1] = tmp; } int main() { char arr[] = "abcdef"; reverse_string(arr); printf("%s\n", arr); return 0; }
9.strlen的模拟(递归实现)
//题目9 //strlen的模拟(递归实现) //递归和非递归分别实现strlen
//题目九 // strlen模拟 // strlen的含义是:求字符串中有效字符的长度,不包括\0。 //递归 #include<stdio.h> int test(char arr[]) { if (*arr == '\0')//('\0' != *arr) return 0; else return 1 + test(arr+1); } int main() { char arr[] = "abcdef"; int ret = test(arr); printf("%d", ret); return 0; }
// strlen模拟 // strlen的含义是:求字符串中有效字符的长度,不包括\0。 //非递归 #include<stdio.h> int test(char arr[]) { int count = 0; //while (*arr != '\0') while ('\0'!=*arr) { count++; arr++; //arr+1; } return count; } int main() { char arr[] = "abcdef"; int ret=test(arr); printf("%d", ret); return 0; }
10.求阶乘
//题目10 //求阶乘 //递归和非递归分别实现求n的阶乘(不考虑溢出的问题)
//题目十 //求阶乘 //递归 #include<stdio.h> int test(int n) { if (n == 1) return 1; else return n * test(n - 1); } int main() { int n = 0; scanf("%d", &n); int ret = test(n); printf("%d", 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", ret); return 0; }
11.打印一个数的每一位
//题目11 //打印一个数的每一位 //递归方式实现打印一个整数的每一位
//题目十一 //打印一个数的每一位 #include<stdio.h> void test(int n) { if (n <= 9) printf("%d ", n); else//n>9 { test(n / 10); printf("%d ", n%10); } } int main() { int n = 0; scanf("%d", &n); test(n); return 0; }
12.概念辨析总结tips
- 能把函数处理结果的两个数据返回给主调函数有哪些办法?
- 形参用两个指针
- 形参用数组
- 用两个全局变量_全局变量可以给各个函数直接使用,所以全局变量的控制就比较难,我们建议再自己的代码中尽量减少全局变量的使用
- 注意return不能返回两个数,return只能带回一个数。🆗🆗🆗🆗🆗!
#include<stdio.h> //指针 void test1(int* pa, int* pb) { *pa = 4; *pb = 3; } //数组 void test2(int arr[5]) { arr[0] = 4; arr[1] = 3; } int main() { int a = 0; int b = 0; int arr[5] = { 0 }; test1(&a, &b); test2(arr); printf("a=%d b=%d\n", a, b); printf("arr[0]=%d arr[1]=%d\n", arr[0], arr[1]); return 0; } //全局变量 int a = 1; int b = 2; int main() { printf("a=%d b=%d", a, b); }
- 函数可以传值调用,传值调用的时候形参是实参的一份零临时拷贝。
- 函数可以传址调用,传址调用的时候,可以通过形参操作实参。
- 函数可以嵌套调用,但是不能嵌套定义。
- 函数调用后不一定带回返回值,例如只是想把某部分代码封装起来,避免与其他代码进行交互的过程,所以函数不一定有返回值。
- 实际参数和形式参数可以同名。
- 形参是在函数调用的时候才实例化,才开辟内存空间的。
- 按照传值的方式传递,形参和实参各自有各自的空间,改变形参不能改变外部的实参。
- 按照传址的方式传递,改变形参就是改变实参。
- 函数间的数据传递可以使用全局变量。
- 主调函数和被调函数不一定在同一个函数里。
- 函数的定义可以放在任意位置,函数声明必须放在函数使用之前。
- 函数必须保证先声明在使用。
- 函数声明:告诉编译器函数返回值类型函数名字和函数所需要的参数。
- 函数定义:说明函数是怎么实现的。
- 函数设计应该最求高内聚低耦合。
- 高内聚低耦合:函数体内部实现修改了,尽量不要对外部产生影响,否则:代码不方便维护。
- 尽量少使用全局变量,全局变量每个方法都可以访问,但是很难保证数据的正确性和安全性。
- 函数的参数不易过多。
- 设计函数时,尽量做到谁申请的资源就由谁释放,否则如果交给外部者释放,外部使用者可能不知道或者忘记,就会造成资源泄露。
- 函数的参数可能是变量,也可能是常量,也可能是宏,也可能是指针等等。
- 库函数的使用必须要包含对应的头文件。
- 函数中的形式参数是在栈中保存 (见下面)
- 在一个函数内定义的变量只在本函数范围内有效。
- 在一个函数内复合语句中定义的变量只能在复合语句中使用。
- C语言规定,在一个源程序中,main函数的位置可以任意。
- 存在限制条件,当满足这个限制条件的时候,递归便不在继续。
- 每次递归调用之后越来越接近这个限制条件。
- 递归层次太深,会出现死循环和栈溢出现象。
- 递归解体的思路:
- 将问题转化为其子问题,子问题要与原问题具有相同的解法
- 递归的出口
- 编写函数的方法:TDD_测试驱动开发_test drived development
- 关于指针类型+1
- 关于判断条件反起写
- 数组字符串坐标
- strlen-1 == sz-2 VS strlen == sz-1
关于以上练习题,大家可以动手写一写。🙂🙂🙂
✔✔✔✔✔感谢大家的阅读,若有错误和不足,欢迎指正!
代码----------→【gitee:https://gitee.com/TSQXG】
联系----------→【邮箱:2784139418@qq.com】