首页 分享 C语言学习记录(七)——分支、循环、函数、递归习题总结

C语言学习记录(七)——分支、循环、函数、递归习题总结

来源:花匠小妙招 时间:2024-12-31 21:23
一、关于分支、循环部分习题总结 1.关于while循环的概念

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语言函数的描述:
  ①可以没有参数和返回值类型,根据需要给出。
  ②函数的实参可能是变量,也可能是常量,也可能是宏,也可能是指针等等
  ③在使用库函数时,必须要包含该库函数所在的头文件,否则编译器将不能识别
  ④库函数是语言设计者为了让用户能够更好的使用,而给出的,但并不能解决用户的所有问题,因此其他问题还需要用户自己写方法解决

2.函数判断素数

#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.用递归和非递归的方法分别实现字符串逆序

思路:
①循环的方式

给两个指针,left放在字符串左侧,right放在最后一个有效字符位置交换两个指针位置上的字符left指针往后走,right指针往前走,只要两个指针没有相遇,继续2,两个指针相遇后,逆置结束

②递归方式:
对于字符串“abcdefg”,递归实现的大概原理:

交换a和g,以递归的方式逆置源字符串的剩余部分,剩余部分可以看成一个有效的字符串,再以类似的方式逆置

/*******递归的方式写字符串长度函数*******/ 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)数据集

推荐分享