C语言学习记录(七)——分支、循环、函数、递归习题总结
while(条件表达式) 循环体 12
while循环中,当条件表达式成立时,才会执行循环体中的语句,每次执行期间,都会对循环因子进行修改(否则就成为死循环),修改完成后如果while条件表达式成立,继续循环,如果不成立,循环结束。故:while循环条件将会比循环体多执行一次。
2.以下程序的运行结果是?#inclde<stdio.h> int main(){ int a = 0, b = 0; for (a = 1, b = 1; a <= 100; a++){ if (b >= 20) break; if (b % 3 == 1){ b = b + 3; continue; } b = b - 5; } printf("%dn", a); return 0; } 1234567891011121314
分析: 第一次循环:a = 1,b = 1--->b小于20, if不成立,b%3 == 1%3 == 1成立,b=b+3, 此时b的值为4 第二次循环:a = 2,b = 4--->b小于20, if不成立,b%3 == 4%3 == 1成立,b=b+3, 此时b的值为7 第三次循环:a = 3,b = 7--->b小于20, if不成立,b%3 == 7%3 == 1成立,b=b+3, 此时b的值为10 第四次循环:a = 4,b = 10--->b小于20,if不成立,b%3 == 10%3 == 1成立,b=b+3, 此时b的值为13 第五次循环:a = 5,b = 13--->b小于20,if不成立,b%3 == 13%3 == 1成立,b=b+3, 此时b的值为16 第六次循环:a = 6,b = 16--->b小于20,if不成立,b%3 == 16%3 == 1成立,b=b+3, 此时b的值为19 第七次循环:a = 7,b = 19--->b小于20,if不成立,b%3 == 19%3 == 1成立,b=b+3, 此时b的值为22 第八次循环:a = 8,b = 22--->b大于20,if成立,循环break提出 最后打印a:8 12345678910 3.给定两个数,求这两个数的最大公约数
思路为:
有两个整数a和b,
①a%b得到余数c
②若c = 0,则b即为两数的最大公约数
③若c ≠ 0,则a = b, b = c然后再去执行①
#include<stdio.h> //写法一 int main(){ int a = 0; int b = 0; int c = 0; printf("%s:n","请输入两个整数"); scanf("%d %d", &a, &b); do{ c = a % b; if (c == 0){ printf("%d 为两数的最大公约数n", b); } a = b; b = c; } while(c != 0); } //写法二 int main(){ int a = 18; int b = 24; int c = 0; while(c = a % b){ a = b; b = c; } printf("%dn", b) }
12345678910111213141516171819202122232425 4.打印出1000年到2000年之间的闰年思路为:
能被4整除,不能被100整除的年份为闰年;或者能被400整除的年份为闰年
#include<stdio.h> int main(){ for (int i = 1000; i <= 2000; i++){ if (i %4 == 0 && i % 100 ! = 0 || i % 400 == 0){ printf("%d年", i); } } } 12345678 5.打印出100~200之间的素数,以及素数的个数
思路为:
素数:即质数,除了1和自己之外,再没有其他的约数,则该数据为素数
方法一:
判断i是否为素数:用[2, i)之间的每个数据去被i除,只要有一个可以被整除,则不是素数
#include<stdio.h> int main(){ int i = 0; int count = 0; for (i = 100; i <= 200; i++){ int j = ; for (j = 2; j < i; j++){ if (i % j == 0){ break; } } if (j == 1){ count++; printf("%d", i); } } printf("ncount = %dn", count); return 0; }
12345678910111213141516171819方法二:
上述方法一中,超过i的一半的数据肯定不是i的倍数,进行了许多没有意义的运算,优化为,拿到一个数据i只需要检测[2, i/2]区间内是否有元素可以被i整除,可以说明i不是素数。
#include<stdio.h> int main(){ int i = 0; int count = 0; for (i = 100; i <= 200; i++){ int j = ; for (j = 2; j < i/2; j++){ if (i % j == 0){ break; } } if (j > i/2){ count++; printf("%d", i); } } printf("ncount = %dn", count); return 0; }
1234567891011121314151617181920方法三:
再优化后为,如果i能够被[2, sqrt(i)]之间的任意数据整除,则i不是素数。愿意:如果 m能被2 ~ m-1之间任一整数整除,其二个因子必定有一个小于或等于sqrt(m),另一个大于或等于 sqrt(m)。
#include<stdio.h> int main(){int i = 0;int count = 0;for(i=101; i<=200; i++){//2->i-1int j = 0;for(j=2; j<=sqrt(i); j++){if(i%j == 0){break;}}if(j>sqrt(i)){count++;printf("%d ", i);}}printf("ncount = %dn", count);return 0; }
1234567891011121314151617181920方法四:
继续对方法三优化,只要i不被[2, sqrt(i)]之间的任何数据整除,则i是素数,但是实际在操作时i不用从101逐渐递增到200,因为出了2和3之外,不会有两个连续相邻的数据同时为素数。
int main() {int i = 0;int count = 0;for(i=101; i<=200; i+=2){//2->i-1int j = 0;for(j=2; j<=sqrt(i); j++){if(i%j == 0){break;}}if(j>sqrt(i)){count++;printf("%d ", i);}}printf("ncount = %dn", count);return 0; }
1234567891011121314151617181920 6.数9的个数,从1到100的所有整数中出现多少个数字9思路为:
①给一个循环从1遍历到100,拿到每个数据后进行一下操作
②a. 通过%的方式取当前数据的个位,检测个位数据是否为9,如果是,给计数器加1
b. 通过/的方式取当前数据的十位,检测十位数据是否是9,如果是,给计数器加1
循环一直继续,直到所有的数据检测完,所有9的个数已经统计在count计数中。
#include<stdio.h> int main(){ int i = 0;; int count = 0; for (i = 1; i <= 100; i++){ if (i % 10 == 9) count++; if (i / 10 == 9) count++; } printf("%dn", count); return 0; } 12345678910111213' 7.分数求和,计算1/1 - 1/2 + 1/3 - 1/4 + 1/5 + … + 1/99 - 1/100的值,打印出结果
思路为:
①从上述表达式可以分析出
a. 该表达式主要由100项,基数项为正,偶数项为负
②设置一个循环从1~100,给出表达式中的每一项:1.0/i, 注意此处不能使用1,否则结果全部为0然后使用flag标记控制奇偶项,奇数项为正,偶数项为负然后将所有的项相加即可。
#include <stdio.h> int main() {int i = 0;double sum = 0.0;int flag = 1;for(i=1; i<=100; i++){sum += flag*1.0/i;flag = -flag;}printf("%lfn", sum);return 0; } 1234567891011121314' 8.求最大值,求10个整数中最大值
思路:
采用循环的方式输入一个数组使用max标记数组中的最大值,采用循环的方式依次获取数组中的每个元素,与max进行比较,如果arr[i]大于 max,更新max标记的最大值,数组遍历结束后,max中保存的即为数组中的最大值。int main() {int arr[10] = {0};int i = 0;int max = 0;for(i=0; i<10; i++){scanf("%d", &arr[i]);}max = arr[0];for (i = 1; i < 10; i++){ if(arr[i] > max) max = arr[i];}printf("max = %dn", max);return 0;
12345678910111213141516 9.乘法口诀表,输出9*9乘法口诀表#include<stdio.h> int main(){ int i = 0; for (i = 1; i <= 9; i++){ int j = 0; for (j = 1; j <= i; j++){ printf("%d * %d = %d", i, j, i*j); } prrintf("n") } return 0; } 123456789101112 10.猜数字游戏
int ret = rand()%100:生成[0 - 100)之间的随机数
srand((unsigned)time(NULL)):保证每次电脑生成的随机数不一样。
void menu(){printf("**********************n");printf("*******1.play******n");printf("*******0.exit*********n");printf("**********************n"); } void game(){ int randNume = rand() % 100 + 1; while(1){ printf("请输入你要猜的数字:n"); int num = 0; scanf("%d", &num); if (num < randNum){ printf("找小了n"); } else if (num > randNum){ printf("找大了n"); } else{ printf("找到了n"); break; } } } int main(){ srand((unsigned)time(NULL)); int imput = 0; do{ menu(); printf("请输入你的操作:1代表玩儿,0代表退出"); scanf("%d", &input); switch (input){ case 1: game(); break; case 0: printf("退出游戏n"); default: printf("输入有误n"); break; } } while (input != 0) }
12345678910111213141516171819202122232425262728293031323334353637383940414243 11.二分查找,编写代码在一个整形的序列数组中查找具体的每个数,找到了打印出数字所在下标,找不到输出:找不到。思路:
找到数组的中间位置检测中间位置的数据是否与要查找的数据key相等a: 相等,找到,打印下标,跳出循环
b: key < arr[mid], 则key可能在arr[mid]的左半侧,继续到左半侧进行二分查找
c: key > arr[mid], 则key可能在arr[mid]的右半侧,继续到右半侧进行二分查找
如果找到返回下标,否则继续,直到区间中没有元素时,说明key不在集合中,打印找不到。
易错点:
right的右半侧区间取值,该值决定了后序的写法while循环的条件是否有等号求中间位置的方法,直接相加除2容易造成溢出更改left和right的边界时,不确定是否要+1和-1// 方法一,采用[left, right] 区间 #include <stdio.h> int main() {int arr[] = {1,2,3,4,5,6,7,8,9,10};int key = 3;int left = 0;int right = sizeof(arr)/sizeof(arr[0])-1; // right位置的数据可以取到while(left<=right) // right位置有数据,必须要添加=号{int mid = left+(right-left)/2; //可能造成数据溢出if(arr[mid]>key) // key小于中间位置数据,说明key可能在左半侧,需要改变右边界{right = mid-1; // right位置的数据可以取到,因此right=mid-1}else if(arr[mid]<key)// key大于中间位置数据,说明key可能在右半侧,需要改变左边界{left = mid+1; // left位置的数据可以取到,因此left=mid+1}else{printf("找到了,下标是:%dn", mid); break;}}if(left>right)printf("找不到n");return 0; } // 方法二,采用[left, right) 区间 #include <stdio.h> int main() {int arr[] = {1,2,3,4,5,6,7,8,9,10};int key = 3;int left = 0;int right = sizeof(arr)/sizeof(arr[0]); // right位置的数据取不到while(left<right) // right位置没有数据,此处不需要添加={int mid = left+(right-left)/2; //这种方法不会溢出 //int min = letf + (right - left) / 2 这种算法可能造成溢出if(arr[mid]>key) // key小于中间位置数据,说明key可能在左半侧,需要改变右边界{right = mid; // right位置的数据取不到,因此right=mid,不需要减1}else if(arr[mid]<key)// key大于中间位置数据,说明key可能在右半侧,需要改变左边界{left = mid+1; // left位置的数据可以取到,因此left=mid+1}else{printf("找到了,下标是:%dn", mid); break;}}if(left>=right)printf("找不到n");return 0; }
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859 二、关于函数与递归部分习题总结 1.关于函数的细节补充:(1)关于函数返回值:
①一个函数只能返回一个结果,可以考虑将两个数放在一个数组中,返回数组的地址
②将形参存在数组中,修改数组中的内容,可以通过数组将修改结果带出去
//a为指针型变量,存放地址 //b为指针型变量,存放地址 void fun(int *a, int *b){ //fun(&c, &d) 传指针 *a = 10; //解引用地址后,对地址里面的值进行赋值 *b = 20; } 123456
void fun(int a, int b){ //fun(c, d) 传值 a = 10; b = 20; } 1234
③形参如果用指针,最终指向的是外部的实参,在函数中对指向内容进行修改,改变的就是外部的实参
④全局变量不受函数的结束而结束,在函数中改变全局变量,主调函数中可以看到改变之后的结果。
(2)关于函数的调用:
①形参按照值的方式传递,将来形参就是实参的一份临时拷贝,修改形参不会影响外部的实参。
②函数可以传地址调用,传地址调用的时候,可以通过形参操作实参(此处拷贝的是一个地址,地址当中的值是通过解引用直接拿到的)。
③函数可以嵌套调用,但不可以嵌套调用嵌套定义。
④函数可以没有返回值,如果没有返回值也就不需要待会任何结果。
⑤形参和实参在不同的函数中,即不同的作用域,因此形参和实参可以同名。
⑥函数之间的数据传递可以使用全局变量。
⑦函数的定义可以放在任意的文件中,使用时只需要包含头文件即可。
(3)关于递归的使用:
①递归的两个条件:Ⅰ、将问题转化为子问题,子问题与原问题具有相同解法
Ⅱ、递归的出口
②存在限制条件,当满足这个限制条件的时候,递归便不再继续。
③每次递归调用之后,都是将原问题进一步缩小,就会越来越接近这个限制条件。
④因为每次递归,相当于都是一次新的函数调用,而每次函数调用系统必须给该函数划分栈帧空间,内部的递 归函数没有退出,上层的递归就不能退出,栈帧就会累积许多块,如果累积超过栈的总大小,就会栈溢出。
(4)关于函数的声明和定义:
①函数的定义可以放在任意位置,函数的声明必须放在函数的使用之前。(函数在使用之前可以先声明无定义)
②函数定义在使用之后,使用之前没有声明时,编译器编译时识别不了该函数
③函数的声明只是告诉编译器函数返回值类型、函数名字以及函数所需要的参数,函数定义才是说明函数是怎么 实现的
(5)关于实参和形参:
①传参时不论是按照值还是指针方式传递,形参拿到的都是实参的一份拷贝。
②形参是在函数调用的时候才实例化,才开辟内存空间(函数没有调用时,新参没有空间)。
③如果是按照值的方式传递,形参和实参各自有各自的空间,改变形参不能改变外部的实参。
(5)关于函数的设计:
①高内聚低耦合即:函数体内部实现修改了,尽量不要对外部产生影响,否则:代码不方便维护。
②要尽可能不使用全局变量,全局变量每个方法都可以访问,很难保证数据的正确性和安全性。
③参数越少越好,否则用户在使用时体验不是很好,还得必须将所有参数完全搞明白才可以使用。
④设计函数时,尽量做到谁申请的资源就由谁来释放,否则如果交给外部使用者释放,外部使用者可能不知道或者忘记,就会造成资源泄漏。
(6)关于C语言函数的描述:
①可以没有参数和返回值类型,根据需要给出。
②函数的实参可能是变量,也可能是常量,也可能是宏,也可能是指针等等
③在使用库函数时,必须要包含该库函数所在的头文件,否则编译器将不能识别
④库函数是语言设计者为了让用户能够更好的使用,而给出的,但并不能解决用户的所有问题,因此其他问题还需要用户自己写方法解决
#include<stdio.h> #include<math.h> int isPirme(int n){int i = 2;for (i = 2; i <= sqrt(n); i++){if (n % i == 0){return 0;}}if (i > sqrt(n)){return 1;}return 0; } int main(){if (isPirme(30) == 0){printf("不是素数n");}else{printf("是素数n");} }
12345678910111213141516171819202122 3.函数判断闰年#include<stdio.h> int isLeapYear(int n){if (n % 4 == 0 && n % 100 != 0 || n % 400 == 0){return 1;}return 0; } int main(){if (isLeapYear(2020) == 1){printf("是闰年n");}else{printf("%不是闰年n");} } 123456789101112131415 4.交换两个整数,实现一个函数来交换两个整数的内容
思路:
题目比较简单,此处只需要清楚传值和传指针的区别即可。
传值:形参是实参的一份拷贝,函数运行起来后,形参是形参,实参是实参,形参和实参没有任何关联性,改变形 参时,不会对实参造成任何影响。
传地址:形参是实参地址的一份拷贝,形参指向的实体是实参,对形参解引用后,拿到的内容就是实参,因此对形参解引用之后的内容进行修改,改变的就是实参.
#include<stdio.h> void Exchange(int *pa, int *pb) {int tmp = 0;tmp = *pa;*pa = *pb;*pb = tmp; } int main(){int a = 50;int b = 100;Exchange(&a, &b);printf("交换后:%d %dn", a, b); } 1234567891011121314' 5.乘法口诀,写一个函数,打印乘法口诀表,口诀表的行数和列数自己制定
#include<stdio.h> void mult(int a){int i = 1;for (i = 1; i <= a; i++){int j = 1;for (j = 1; j <= i; j++){int mul = i * j;printf("%d * %d = %d ", i, j, mul);}printf("n");} } int main(){mult(9); } 123456789101112131415' 6.打印出一个数组的每一位,以递归的方式
#include<stdio.h> void printNumber(int n){if (n < 10){printf("%d ", n % 10);}else{printNumber(n / 10);printf("%d ", n % 10);} } int main(){printNumber(521); } 12345678910111213' 7.用递归和非递归的分别实现求n的阶乘(不考虑溢出问题)
#include<stdio.h> //递归方法 int FacD(int n){if (n == 1 ){return 1;}int ret = n * FacD(n - 1);return ret; } //循环方法 int FacX(int n) {int ret = 1;for (int i = 1; i <= n; i++){ ret *= i;}return ret; } int main(){printf("%dn", FacD(5)); printf("%dn", FacX(5)); }
123456789101112131415161718192021222324' 8.用递归和非递归的方法分别实现strlen函数#include<stdio.h> int MyStrlenD(const char*str){if (*str == ' '){return 0;}else{return 1 + MyStrlen(str + 1);} } int MyStrlenX2(char str[]){int size = 0;for (int i = 0; str[i] != ' '; i++){size++;}return size; } int main(){char *p = "abcde";printf("%dn", MyStrlenD(p));printf("%dn", MyStrlenX(p)); }
12345678910111213141516171819202122 9.用递归和非递归的方法分别实现字符串逆序思路:
①循环的方式
②递归方式:
对于字符串“abcdefg”,递归实现的大概原理:
/*******递归的方式写字符串长度函数*******/ int MyStrlen(char *str){if (*str == ' '){ //当传入的字符串中没有字符return 0; //字符串长度为0}else{return 1 + MyStrlen(str + 1); //运用递归,每递归一次长度加1,直到遍历到的' '时结束递归} } /*******递归方式写字符串反转*******/ void reverse_string(char *string){int len = MyStrlen(string); //调用上面的字符串长度函数if (len <= 1){ //当字符串长度小于等于1时,不执行return 0;}else{char temp = string[0]; //当字符串长度小于等于1时,不执行string[0] = string[len - 1]; //将最后一个字符赋给第一个字符;string[len - 1] = ' '; //将最后一个字符的内容赋为' ';reverse_string(string + 1); //递归调用下一次反转;string[len - 1] = temp; //将temp赋给当前的最后一个字符} } void reverse_stringX(char *arr){char *left = arr;char *right = arr + MyStrlen(arr) - 1;while (left < right){char tmp = *left;*left = *right;*right = tmp;left++;right--;} } int main(){char ch[] = "abcdefgh";reverse_string(ch);printf("%sn", ch);reverse_stringX(ch);printf("%sn", ch);return 0; }
1234567891011121314151617181920212223242526272829303132333435363738394041424344' 10.计算一个数的每位之和#include<stdio.h> int DigitSun(int x){if (x > 9){return x % 10 + DigitSun(x / 10);}else{return x;} } int main(){int num = 123456;printf("%dn", DigitSun(num));return 0; } 1234567891011121314' 11.递归实现n的k次方
#include<stdio.h> int MyPow(int n, int k){if (k > 0){return MyPow(n, k - 1)*n;}return 1; } int main(void) {int ret = MyPow(5, 5);printf("%dn", ret);return 0; } 12345678910111213' 12.计算斐波那契数
//递归 int fibD(int n){if (n <= 2)return 1;elsereturn fibD(n - 1) + fibD(n - 2); } //循环 int fibX(int n) {if (n <= 0){return -1;}int f1 = 1;int f2 = 1;int f3 = 1;for (int i = 3; i <= n; i++){f3 = f1 + f2;f1 = f2;f2 = f3;}return f3; } int main(){printf("%dn", fibD(30));printf("%dn", fibX(30)); }
123456789101112131415161718192021222324252627'相关知识
c语言函数习题
c语言面试题总结
R语言的apply族函数
2023年汉江师范学院普通专升本《C语言程序设计》考试大纲
Python 选择与循环
C语言:输出所有的水仙花数
如何用c语言输出一朵花
函数
《快学Scala》习题详解 第12章 高阶函数
C语言情人节玫瑰花代码
网址: C语言学习记录(七)——分支、循环、函数、递归习题总结 https://www.huajiangbk.com/newsview1388154.html
上一篇: “我的植物朋友”———三年四班制 |
下一篇: 鸢尾花(iris)数据集 |
推荐分享

- 1君子兰什么品种最名贵 十大名 4012
- 2世界上最名贵的10种兰花图片 3364
- 3花圈挽联怎么写? 3286
- 4迷信说家里不能放假花 家里摆 1878
- 5香山红叶什么时候红 1493
- 6花的意思,花的解释,花的拼音 1210
- 7教师节送什么花最合适 1167
- 8勿忘我花图片 1103
- 9橄榄枝的象征意义 1093
- 10洛阳的市花 1039