题目1:写两个函数,分别求两个整数的最大公约数和最小公倍数,用主函数调用这两个函数,并输出结果。两个整数由键盘输人。
求最大公约数的方法:辗转相除法
对于任意两个整数a和b(b不为0),a和b的最大公约数等于b和a除以b的余数r的最大公约数。
用数学表达式表示就是:
gcd(a, b) = gcd(b, a mod b)
其中,gcd(a, b)表示a和b的最大公约数,a mod b表示a除以b的余数。
思路如下:
- 初始化两个整数a和b,其中a是较大的数,b是较小的数(如果b大于a,可以交换它们)。
- 计算a除以b的余数r。
- 如果r为0,则b就是a和b的最大公约数,算法结束。
- 否则,将b的值赋给a,将r的值赋给b,然后返回步骤2继续计算。
这个过程会一直重复,直到余数为0为止。此时,非零的除数就是两个数的最大公约数。
#include <stdio.h>
// 计算最大公约数(GCD)
int gcd(int a, int b) {
// 当b不为0时,继续循环
while (b != 0) {
// 临时保存b的值
int temp = b;
// 更新b为a除以b的余数
b = a % b;
// 更新a为原来的b值
a = temp;
}
// 返回最大公约数
return a;
}
// 计算最小公倍数(LCM)
int lcm(int a, int b) {
// 使用公式 a * b / gcd(a, b) 来计算最小公倍数
return (a / gcd(a, b)) * b;
}
int main() {
int num1, num2;
int result_gcd, result_lcm;
// 提示用户输入两个整数
printf("请输入两个整数,用空格隔开:");
// 读取用户输入的两个整数,并保存到num1和num2
scanf("%d %d", &num1, &num2);
// 确保num1是较大的数,如果不是则交换
if (num1 < num2) {
// 交换num1和num2的值
int temp = num1;
num1 = num2;
num2 = temp;
}
// 调用gcd函数计算最大公约数,并将结果保存到result_gcd
result_gcd = gcd(num1, num2);
// 调用lcm函数计算最小公倍数,并将结果保存到result_lcm
result_lcm = lcm(num1, num2);
// 打印最大公约数
printf("最大公约数(GCD)为:%d\n", result_gcd);
// 打印最小公倍数
printf("最小公倍数(LCM)为:%d\n", result_lcm);
return 0;
}
题目2:求方程 {ax}^2+bx+c=0的根,用3个函数分别求当: b^2-4ac大于0、等于0和小于0时的根并输出结果。从主函数输入a,b,c的值。
- 根据判别式
Δ = b^2 - 4ac
判断方程根的情况。 - 当
Δ > 0
时,方程有两个不相等的实根。 - 当
Δ = 0
时,方程有两个相等的实根(即一个重根)。 - 当
Δ < 0
时,方程无实根(有共轭复数根)。
#include <stdio.h>
#include <math.h>
// 定义求解一元二次方程的函数
void solveQuadratic(double a, double b, double c) {
// 计算判别式
double d = b * b - 4 * a * c;
// 如果判别式大于0,方程有两个不同的实根
if (d > 0) {
// 计算第一个根
double x1 = (-b + sqrt(d)) / (2 * a);
// 计算第二个根
double x2 = (-b - sqrt(d)) / (2 * a);
// 打印两个根
printf("根是 %.2lf 和 %.2lf\n", x1, x2);
}
// 如果判别式等于0,方程有两个相同的实根(或称为一个重根)
else if (d == 0) {
// 计算重根
double x = -b / (2 * a);
// 打印重根
printf("根是 %.2lf\n", x);
}
// 如果判别式小于0,方程没有实根
else {
printf("无实数根\n");
}
}
int main() {
double A, B, C;
// 提示用户输入一元二次方程的系数
printf("请输入一元二次方程的系数 A, B 和 C: ");
// 读取用户输入的系数
scanf("%lf %lf %lf", &A, &B, &C);
// 调用函数求解一元二次方程
solveQuadratic(A, B, C);
return 0;
}
题目3:写一个判素数的函数,在主函数输人一个整数,输出是否为素数的信息。
思路
判断一个整数是否为素数,首先需要了解素数的定义:一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫作素数;否则称为合数。
为了判断一个数是否为素数,我们可以从2开始到该数的平方根(包含)进行遍历,如果在这个范围内存在任何一个数能够整除该数,那么该数就不是素数。如果没有找到任何一个数能够整除该数,那么该数就是素数。
#include <stdio.h>
#include <math.h>
#include <stdbool.h> // 引入bool类型和true/false宏
// 判断素数的函数
bool isPrime(int num) {
// 小于等于1的数不是素数
if (num <= 1) {
return false;
}
// 遍历从2到sqrt(num)的整数
for (int i = 2; i <= sqrt(num); i++) {
// 如果能被整除,则不是素数
if (num % i == 0) {
return false;
}
}
// 如果没有找到能整除的数,则是素数
return true;
}
int main() {
int num;
// 提示用户输入一个整数
printf("请输入一个整数: ");
scanf("%d", &num);
// 调用isPrime函数并输出结果
if (isPrime(num)) {
printf("%d 是素数\n", num);
} else {
printf("%d 不是素数\n", num);
}
return 0;
}
题目4:写一个函数,使给定的一个3X3的二维整型数组转置,即行列互换。
思路:
二维数组的转置即是将原数组的行变为列,列变为行。具体来说,对于3x3的二维数组,我们需要遍历数组的每一个元素,并将第i行第j列的元素与第j行第i列的元素进行交换。但是,由于转置是对称的,我们只需要遍历数组的上三角(包括对角线)部分即可,这样可以避免重复交换。
#include <stdio.h>
void func(int arr[3][3]);
// 二维数组转置函数
void func(int arr[3][3]) {
// 遍历数组的上三角部分(包括对角线)
// 因为矩阵是对称的,所以只需要交换上三角的元素即可
for (int i = 0; i < 3; i++) {
for (int j = i + 1; j < 3; j++) { // 注意这里j从i+1开始,避免重复交换对角线元素
// 交换arr[i][j]和arr[j][i]
int temp = arr[i][j];
arr[i][j] = arr[j][i];
arr[j][i] = temp;
}
}
}
// 主函数
int main() {
// 定义一个3x3的二维整型数组
int arr[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
// 打印原始数组
printf("原始数组:\n");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", arr[i][j]);
}
printf("\n");
}
// 调用转置函数
func(arr);
// 打印转置后的数组
printf("转置后的数组:\n");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", arr[i][j]);
}
printf("\n");
}
return 0;
}
题目5:写一个函数,使输人的一个字符串按反序存放,在主函数中输入和输出字符串。
思路
- 使用两个指针,一个从字符串开头,一个从末尾开始。
- 交换两个指针所指的字符,然后向中间移动指针。
- 重复直到两个指针相遇或交叉。
#include <stdio.h>
#include <string.h>
void reverse_string(char* str) { //定义一个反转字符串的函数,参数为字符指针
char *end = str + strlen(str) - 1; //定义一个指针指向字符串的末尾
char temp; //定义一个临时变量用于交换字符
while (str < end) { //当字符串未反转完时循环
temp = *str; // 将当前字符存储到临时变量中
*str++ = *end; // 将末尾字符放到当前位置
*end-- = temp; // 将临时变量中的字符放到末尾位置
}
}
int main() {
char str[] = "Hello, World!"; // 定义一个字符串
printf("Original string: %s\n", str); // 打印原始字符串
reverse_string(str); // 调用反转字符串函数
printf("Reversed string: %s\n", str); // 打印反转后的字符串
return 0;
}
题目6:写一个函数,将两个字符串连接
#include <stdio.h>
#include <string.h>
void concatenate_strings(char* dest, const char* src) {
strcat(dest, src);
}
int main() {
char dest[100] = "Hello, ";
const char* src = "World!";
concatenate_strings(dest, src);
printf("Concatenated string: %s\n", dest);
return 0;
}
题目7:写一个函数,将一个字符串中的元音字母复制到另一字符串,然后输出。
#include <stdio.h>
#include <string.h>
// 定义一个函数,将字符串中的元音字母复制到另一个字符串中
void copy_vowels(char *src, char *dst) {
int i, j = 0;
for (i = 0; src[i] != '\0'; i++) {
// 判断当前字符是否为元音字母
if (src[i] == 'a' || src[i] == 'e' || src[i] == 'i' || src[i] == 'o' || src[i] == 'u' ||
src[i] == 'A' || src[i] == 'E' || src[i] == 'I' || src[i] == 'O' || src[i] == 'U') {
dst[j++] = src[i]; // 将元音字母复制到目标字符串中
}
}
dst[j] = '\0'; // 在目标字符串末尾添加结束符
}
int main() {
char src[] = "Hello, World!";
char dst[20];
copy_vowels(src, dst); // 调用函数,将元音字母复制到目标字符串中
printf("在这个字符串中,元音字母为: %s\n", dst); // 输出目标字符串
return 0;
}
题目8:写一个函数,输人一个4位数字,要求输出这4个数字字符,但每两个数字间空一个空格。如输人1990,应输出“1 9 9 0”。
#include <stdio.h>
void print_digits_with_space(int num) {
// 将数字转换为字符串
char num_str[5];
sprintf(num_str, "%d", num);
// 遍历字符串中的每个字符,并在每两个字符之间添加一个空格
for (int i = 0; i < 4; i++) {
printf("%c ", num_str[i]);
}
printf("\n");
}
int main() {
int num = 1990;
print_digits_with_space(num);
return 0;
}
题目9:编写一个函数,由实参传来一个字符串,统计此字符串中字母、数字、空格和其他字符的个数,在主函数中输人字符串以及输出上述的结果。
#include <stdio.h>
#include <string.h>
void count_chars(const char *str, int *letters, int *digits, int *spaces, int *others) {
//初始化所有计数器为0
*letters = *digits = *spaces = *others = 0;
// 遍历字符串中的每个字符
for (int i = 0; str[i] != '\0'; i++) {
// 如果字符是字母(大写或小写)
if ((str[i] >= 'a' && str[i] <= 'z') || (str[i] >= 'A' && str[i] <= 'Z')) {
(*letters)++; // 字母计数器加1
}
// 如果字符是数字
else if (str[i] >= '0' && str[i] <= '9') {
(*digits)++; // 数字计数器加1
}
// 如果字符是空格
else if (str[i] == ' ') {
(*spaces)++; // 空格计数器加1
}
// 如果字符是其他类型
else {
(*others)++; // 其他字符计数器加1
}
}
}
int main() {
char input[100]; // 用于存储用户输入的字符串
int letters, digits, spaces, others; // 用于存储各类字符的计数
// 提示用户输入一个字符串
printf("请输入一个字符串:");
// 从标准输入读取字符串到input中,最多读取99个字符(留一个位置给'\0')
fgets(input, sizeof(input), stdin);
// 去掉字符串末尾的换行符(如果存在)
input[strcspn(input, "\n")] = '\0';
// 调用count_chars函数来计算字符的数量
count_chars(input, &letters, &digits, &spaces, &others);
// 打印结果
printf("字母个数:%d\n", letters);
printf("数字个数:%d\n", digits);
printf("空格个数:%d\n", spaces);
printf("其他字符个数:%d\n", others);
return 0;
}
题目10:写一个函数,输人一行字符,将此字符串中最长的单词输出。
#include <stdio.h>
#include <string.h>
int main() {
char str[100]; // 定义一个字符数组str,用于存储用户输入的字符串
printf("请输入一行字符:"); // 提示用户输入一行字符
fgets(str, sizeof(str), stdin); // 使用fgets函数从标准输入读取最多99个字符(最后一个位置留给'\0')
char longestWord[100] = ""; // 定义一个字符数组longestWord,用于存储最长的单词,初始化为空字符串
char currentWord[100] = ""; // 定义一个字符数组currentWord,用于存储当前正在处理的单词,初始化为空字符串
int i = 0; // 定义一个循环计数器i,初始化为0
// 遍历字符串str中的每个字符
while (str[i] != '\0') {
// 如果当前字符是空格或换行符
if (str[i] == ' ' || str[i] == '\n') {
// 如果currentWord的长度大于longestWord的长度
if (strlen(currentWord) > strlen(longestWord)) {
// 将currentWord复制到longestWord中
strcpy(longestWord, currentWord);
}
// 重置currentWord为空字符串,以便存储下一个单词
currentWord[0] = '\0';
} else {
// 如果当前字符不是空格或换行符,则将其添加到currentWord中
// 注意:这里使用strncat函数,但只追加一个字符,因为后面没有null终止符,所以直接用数组索引赋值可能更简单
strncat(currentWord, &str[i], 1); // 也可以直接使用 currentWord[strlen(currentWord)] = str[i]; currentWord[strlen(currentWord)+1] = '\0';
}
// 移动到下一个字符
i++;
}
printf("最长的单词是:%s\n", longestWord);
return 0; // 程序正常结束
}
题目11:写一个函数,用“起泡法”对输人的10个字符按由小到大顺序排列。
起泡法就是冒泡法,用于排序的一种算法
传送门:冒泡排序
#include<stdio.h>
void output_array(int *p,int len){
int i = 0;
for(i = 0;i < len;i++){
printf("%d ",p[i]);
}
printf("\n");
return;
}
void bubble_sort(int *p,int len){
int i = 0,j = 0;
//比较轮数
for(i = 0;i < len -1;i++){
//每一轮交换的次数
for(j = 0;j < len - 1 - i;j++){
//p[j] == *(p + j)
if(p[j] > p[j + 1]){
//交换数据
int temp = p[j];
p[j] = p[j + 1];
p[j +1] = temp;
}
}
}
return;
}
int main(){
int a[10] = {100,90,80,70,60,50,40,30,20,10};
int len = sizeof(a) / sizeof(a[0]);
printf("原始数据为:\n");
output_array(a,len);
printf("经过冒泡排序之后的数据为:\n");
bubble_sort(a,len);
output_array(a,len);
return 0;
}
题目12:用递归方法求n阶勒让德多项式的值,递归公式为
根据图中的公式计算就行了,不难
#include <stdio.h>
double legendre(int n, double x) {
if (n == 0) {
return 1;
} else if (n == 1) {
return x;
} else {
return ((2 * n - 1) * x * legendre(n - 1, x) - (n - 1) * legendre(n - 2, x)) / n;
}
}
int main() {
int n = 5;
double x = 0.5;
double result = legendre(n, x);
printf("x = %f 时,%d阶勒让德多项式的值为 %f\n", x, n, result);
return 0;
}
题目13:写几个函数:
①输人10个职工的姓名和职工号;
②按职工号由小到大顺序排序,姓名顺序也随之调整;
③要求输人一个职工号,用折半查找法找出该职工的姓名,从主函数输人要查找的职工号,输出该职工姓名。
折半查找传送门:折半查找
使用的是第九章的结构体类型来实现的,没学过的跳过这一个题。
#include <stdio.h>
#include <string.h>
#define MAX_EMPLOYEES 10
#define MAX_NAME_LENGTH 50
// 定义职工结构体
typedef struct {
char name[MAX_NAME_LENGTH];
int id;
} Employee;
// ① 输入10个职工的姓名和职工号
void inputEmployees(Employee employees[], int n) {
for (int i = 0; i < n; ++i) {
printf("请输入第%d个职工的姓名: ", i + 1);
scanf("%s", employees[i].name);
printf("请输入第%d个职工的职工号: ", i + 1);
scanf("%d", &employees[i].id);
}
}
// ② 按职工号由小到大顺序排序, 姓名顺序也随之调整,冒泡排序,见上面的题目11
void sortEmployees(Employee employees[], int n) {
for (int i = 0; i < n - 1; ++i) {
for (int j = 0; j < n - i - 1; ++j) {
if (employees[j].id > employees[j + 1].id) {
// 交换职工信息
Employee temp = employees[j];
employees[j] = employees[j + 1];
employees[j + 1] = temp;
}
}
}
}
// ③ 折半查找法找出职工姓名
char* binarySearch(Employee employees[], int n, int id) {
int low = 0, high = n - 1;
while (low <= high) {
int mid = (low + high) / 2;
if (employees[mid].id == id) {
return employees[mid].name;
} else if (employees[mid].id < id) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return NULL; // 没有找到
}
// 主函数
int main() {
Employee employees[MAX_EMPLOYEES];
// ① 输入10个职工的姓名和职工号
inputEmployees(employees, MAX_EMPLOYEES);
// ② 按职工号由小到大顺序排序, 姓名顺序也随之调整
sortEmployees(employees, MAX_EMPLOYEES);
// 测试排序结果
printf("排序后的职工信息:\n");
for (int i = 0; i < MAX_EMPLOYEES; ++i) {
printf("姓名: %s, 职工号: %d\n", employees[i].name, employees[i].id);
}
// ③ 要求输入一个职工号, 查找并输出该职工的姓名
int idToSearch;
printf("请输入要查找的职工号: ");
scanf("%d", &idToSearch);
char* nameFound = binarySearch(employees, MAX_EMPLOYEES, idToSearch);
if (nameFound) {
printf("职工号 %d 对应的姓名是: %s\n", idToSearch, nameFound);
} else {
printf("未找到职工号 %d 对应的职工\n", idToSearch);
}
return 0;
}
题目14:写一个函数,输人一个十六进制数,输出相应的十进制数。
思路:
- 创建一个函数,接收一个字符串类型的十六进制数作为参数。
- 初始化一个变量用于存储十进制结果。
- 遍历输入的十六进制数字符串,从最高位到最低位。
- 对于每一位字符,将其转换为对应的十进制数值。
- 将每一位的十进制数值乘以16的相应次方,然后累加到结果变量中。
- 返回结果变量。
#include <stdio.h>
#include <string.h>
// 将单个十六进制字符转换为对应的十进制数值
int charToDec(char c) {
// 判断字符是否为0-9之间的数字
if (c >= '0' && c <= '9') {
return c - '0'; // 字符减去'0'字符的ASCII值得到相应的数字
}
// 判断字符是否为A-F之间的大写字母
else if (c >= 'A' && c <= 'F') {
return c - 'A' + 10; // 字符减去'A'字符的ASCII值后加10得到对应的数字
}
// 判断字符是否为a-f之间的小写字母
else if (c >= 'a' && c <= 'f') {
return c - 'a' + 10; // 字符减去'a'字符的ASCII值后加10得到对应的数字
}
// 如果字符不是有效的十六进制字符,则返回-1表示非法字符
else {
return -1; // 非法字符
}
}
// 将十六进制字符串转换为对应的十进制数值
int hexToDec(const char *str) {
int len = strlen(str); // 获取字符串的长度
int result = 0; // 初始化结果为0
// 遍历字符串中的每个字符
for (int i = 0; i < len; i++) {
// 调用charToDec函数将当前字符转换为十进制值
int decValue = charToDec(str[i]);
// 如果转换失败(即遇到非法字符),则打印错误信息并返回-1
if (decValue == -1) {
printf("非法字符:%c\n", str[i]);
return -1;
}
// 累加每个字符的十进制值,注意十六进制到十进制的转换需要乘以16的相应幂次
// 使用位移运算符<<来模拟乘以16的幂次,因为16的幂次等价于2的4次幂的幂次
result += decValue * (1 << (4 * (len - i - 1)));
}
// 返回最终的十进制数值
return result;
}
int main() {
char hex[] = "1A3F"; // 定义一个十六进制字符串
int decValue = hexToDec(hex); // 调用hexToDec函数将十六进制字符串转换为十进制数值
// 如果转换成功(即没有遇到非法字符),则打印结果
if (decValue != -1) {
printf("十六进制数 %s 对应的十进制数为: %d\n", hex, decValue);
}
return 0;
}
题目15:用递归法将一个整数n转换成字符串。例如,输人483,应输出字符串”483”。n的位数不确定,可以是任意位数的整数。
思路:
- 创建一个递归函数,接收一个整数n作为参数。
- 如果n小于10,直接将n转换为字符并返回。
- 否则,将n除以10取整,然后递归调用该函数。
- 将递归结果与当前n对10取余的结果拼接起来,形成字符串。
- 返回最终的字符串。
#include <stdio.h>
#include <string.h>
// 递归函数,将整数n转换为字符串并存储在str数组中
void intToStr(int n, char str[]) {
// 如果n除以10的结果不为0,说明n的位数大于1,继续递归处理n的十位数及以上部分
if(n / 10 != 0)
intToStr(n / 10, str);
// 计算当前字符串str的长度(注意:此时str中存储的是之前递归调用产生的结果)
int length = strlen(str);
// 将n的个位数转换为字符('0'的ASCII值为48,所以n % 10 + '0'得到的是对应的字符)
// 并将其放置在str的当前末尾位置
str[length] = n % 10 + '0';
// 在新的字符后面添加字符串的终止符'\0'
str[length+1] = '\0';
}
int main() {
// 定义一个足够大的字符数组来存储转换后的字符串
char str[100] = "";
// 调用intToStr函数,将整数483转换为字符串并存储在str中
intToStr(483, str);
// 打印转换后的字符串
printf("%s\n", str);
// 程序正常结束
return 0;
}
题目16:给出年、月、日,计算该日是该年的第几天。
#include <stdio.h>
int main() {
// 定义年、月、日变量
int year, month, day;
// 提示用户输入年月日,并指定输入格式
printf("请输入年月日(格式:yyyy mm dd):");
// 使用scanf函数读取用户输入的年、月、日,并将它们存储在对应的变量中
scanf("%d %d %d", &year, &month, &day);
// 定义一个数组,存储每个月的天数(不包括闰年的二月)
// 注意:这里从1开始计数,0位置作为占位符
int days_in_month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
// 判断是否是闰年,如果是闰年,则二月份有29天
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
days_in_month[2] = 29;
}
// 定义变量total_days,用于计算该日期是该年的第几天
int total_days = 0;
// 使用for循环遍历从1月到输入月份之前的所有月份
for (int i = 1; i < month; i++) {
// 将每个月的天数累加到total_days中
total_days += days_in_month[i];
}
// 将输入日期的天数加到total_days中
total_days += day;
// 输出结果
printf("该日是该年的第%d天。\n", total_days);
// 程序正常结束
return 0;
}