Bootstrap

C语言字符串练习题

8.判断回文数

【问题描述】
输入一个不超过8位的正整数,判断它是不是回文数。例如,12321是回文数。
【输入形式】
一个正整数
【输出形式】
是回文数
或者
不是回文数
【样例输入1】
123321
【样例输出1】
123321是回文数

#include <stdio.h>

int main() {
    int num, reversed = 0, original, remainder;
    
    // 输入正整数
    scanf("%d", &num);
    // 保存原始输入数值
    original = num; 
    
    // 反转数字
    while (num != 0) {
    	// 获取最后一位
        remainder = num % 10;  
        // 拼接反转数
        reversed = reversed * 10 + remainder;  
        // 去掉最后一位
        num /= 10;  
    }
    
    // 判断是否是回文数
    if (original == reversed) {
        printf("%d是回文数\n", original);
    } else {
        printf("%d不是回文数\n", original);
    }

    return 0;
}

  • scanf(“%d”, &num) 用于输入正整数。
  • 通过 while 循环获取每一位数字并构造反转后的数值 reversed。
  • 比较原始数字 original 和反转后的数字 reversed,若相等则是回文数。

9. 统计单词数量

【问题描述】
用空格或换行分开的字符串称为单词。输入多行字符串,直到遇到了单词“stop"时才停止。最后输出单词的数量。用于分割单词的空格或换行可能多于1个。单词数量不包括“stop"
【输入形式】
任意多个单词,stop结束
【输出形式】
单词个数【样例输入】
Monday Tuesday Wednesday
Thursday Friday Saturday
Sunday
stop
【样例输出】
7

库函数版本

#include <stdio.h>
#include <string.h>

int main() {
    char word[100];  // 用于存储每次输入的一行字符串
    int count = 0;    // 记录单词数量
    
    // 循环读取输入,直到遇到 "stop"
    while (1) {
        // 使用 fgets 函数读取一行输入,最大读取 100 个字符
        fgets(word, sizeof(word), stdin);
        
        // 去掉输入字符串末尾的换行符
        // strcspn(word, "\n") 找到字符串中第一个换行符的位置,然后将其替换成 '\0'
        word[strcspn(word, "\n")] = 0;
        
        // 如果输入的是 "stop",则结束输入循环
        if (strcmp(word, "stop") == 0) {
            break;  // 跳出循环
        }
        
        // 使用 strtok 函数按空格分割字符串
        // strtok 函数会返回指向每个单词的指针,每次调用返回下一个分隔的单词
        char *token = strtok(word, " ");  // 第一个分割的单词
        while (token != NULL) {
            count++;  // 每找到一个单词就增加计数
            token = strtok(NULL, " ");  // 获取下一个单词
        }
    }
    
    // 输出统计的单词数量
    printf("%d\n", count);
    
    return 0;  // 程序正常结束
}

strcmp:

  • if (strcmp(word, “stop”) == 0):strcmp 比较两个字符串,如果相等(即输入为 “stop”),返回 0,程序就会跳出循环并结束输入。

strtok:

  • strtok(word, " ");:strtok 函数用于按空格分割字符串。第一次调用时,传入原字符串,它会返回第一个分割出的单词。
  • token = strtok(NULL, " ");:后续调用 strtok 时传入 NULL,它会继续处理同一字符串并返回下一个分割出的单词,直到没有更多的单词(返回 NULL)。

非库函数版本

#include <stdio.h>

int main() {
    char ch;
    int count = 0;  // 单词数量
    int inWord = 0; // 标志是否在单词中

    while (1) {
        ch = getchar();  // 读取一个字符

        // 判断是否是 's',然后接着读取后续的字符判断是否为 'stop'
        if (ch == 's') {
            char word[4];  // 用于存储 "stop" 的字符
            word[0] = ch;
            word[1] = getchar();
            word[2] = getchar();
            word[3] = getchar();

            // 检查是否是 "stop"
            if (word[0] == 's' && word[1] == 't' && word[2] == 'o' && word[3] == 'p') {
                break;  // 如果是 "stop",则退出循环
            } else {
                // 如果不是 "stop",将读取的字符重新放回输入流
                ungetc(word[3], stdin);
                ungetc(word[2], stdin);
                ungetc(word[1], stdin);
            }
        }

        // 判断是否是单词的开始或结束
        if (ch != ' ' && ch != '\n') {  // 非空格和换行字符,属于单词的一部分
            if (!inWord) {  // 如果之前不在单词中,进入一个新的单词
                count++;
                inWord = 1;  // 标记正在单词中
            }
        } else {  // 空格或换行符表示单词的结束
            inWord = 0;
        }
    }

    // 输出统计的单词数量
    printf("%d\n", count);

    return 0;
}
  • getchar():使用 getchar() 持续读取字符,直到遇到空格或换行符。
  • 判断 “stop”:当检测到输入为字母 ‘s’ 时,我们手动读取接下来的三个字符来判断是否为 “stop”。
  • 统计单词:通过判断每次非空格和换行字符的出现时,是否是单词的开始(即进入一个新的单词)。如果之前是空格或换行符,设置 inWord 为 0。
  • 跳过空格和换行符:当遇到空格或换行符时,设置 inWord 为 0,表示已经离开当前单词。

1. inWord 变量的定义:
inWord 是一个布尔变量(值为 0 或 1),用于标记程序当前是否处于一个单词的内部。

  • inWord = 1:表示程序当前正在读取一个单词。
  • inWord = 0:表示程序当前不在单词内(即已经遇到空格或换行符,结束了一个单词)。

2. inWord 的作用:

  • inWord 的作用是用来判断和控制是否开始一个新的单词。在逐个字符读取的过程中,空格或换行符被认为是单词的分隔符,因此我们需要判断何时开始一个新单词以及何时结束一个单词。

关键逻辑:

开始一个新单词:

  • 当程序读取到一个不是空格和换行的字符(例如字母、数字等),且之前的字符是空格或换行时,表示遇到了一个新的单词。
  • 此时,inWord 设置为 1,表示我们现在已经进入了一个新单词。

-结束当前单词:

  • 当程序读取到空格或换行符时,表示当前单词的结束。
  • 此时,inWord 设置为 0,表示当前不在单词内。

3. 如何使用 inWord 来计算单词数量:
我们通过检查 inWord 的状态来决定是否增加单词的计数器。

  • 当 inWord 为 0(之前是空格或换行),且当前字符是字母或数字时,我们认为这是一个新单词的开始,增加单词计数,并将 inWord 设置为 1。

  • 当 inWord 为 1(正在处理一个单词)时,程序继续读取字符,直到遇到空格或换行符,此时 inWord 被设置回 0,准备下次读取新的单词。


再优化版本

#include <stdio.h>
int main() {
    char ch;
    int count = 0;    // 单词计数
    int inWord = 0;   // 标志是否在单词中

    while (1) {
        ch = getchar();  // 逐个字符读取输入

        // 检查是否输入 "stop",如果是则结束
        if (ch == 's') {
            if (getchar() == 't' && getchar() == 'o' && getchar() == 'p') {
                break;  // 如果是 "stop",跳出循环
            }
        }

        // 判断字符是否是字母或数字,如果是,则属于一个单词的一部分
        if (ch != ' ' && ch != '\n') {  // 非空格和换行字符
            if (!inWord) {  // 如果之前没有进入过单词,说明是一个新的单词
                count++;  // 增加单词计数
                inWord = 1;  // 标记已经在单词中
            }
        } else {  // 空格或换行符表示单词结束
            inWord = 0;  // 标记不在单词中
        }
    }

    // 输出单词数量
    printf("%d\n", count);

    return 0;
}

10.求数组最大、最小值及平均值

【问题描述】
输入n个(1<n<=10)正整数并保存到一个数组中,求出最大值、最小值、平均值(保留2位小数),以及最大值、最小值在数组中的下标分别是多少。
【输入形式】
共输入2行
第1行输入整数的个数n
第2行输入n个整数,用空格分隔
【输出形式】
需要输出5行
第1行输出最大值
第2行输出最大值的下标
第3行输出最小值
第4行输出最小值的下标
第5行输出平均值

#include <stdio.h>

int main() {
    int n;
    
    // 输入整数的个数
    scanf("%d", &n);
    
    int arr[n];  // 定义一个数组来保存输入的整数
    int max, min, max_index, min_index;
    int sum = 0;
    
    // 输入 n 个整数
    for (int i = 0; i < n; i++) {
        scanf("%d", &arr[i]);
    }
    
    // 初始值设为数组的第一个元素
    max = min = arr[0];
    max_index = min_index = 0;
    
    // 遍历数组,计算最大值、最小值以及它们的下标
    for (int i = 0; i < n; i++) {
        sum += arr[i];  // 累加总和
        
        // 查找最大值和最小值
        if (arr[i] > max) {
            max = arr[i];
            max_index = i;
        }
        if (arr[i] < min) {
            min = arr[i];
            min_index = i;
        }
    }
    
    // 输出最大值
    printf("%d\n", max);
    // 输出最大值的下标
    printf("%d\n", max_index);
    // 输出最小值
    printf("%d\n", min);
    // 输出最小值的下标
    printf("%d\n", min_index);
    // 输出平均值,保留两位小数
    printf("%.2f\n", (float)sum / n);
    
    return 0;
}

  • scanf(“%d”, &n); 用来读取整数的个数。
  • scanf(“%d”, &arr[i]); 用来读取每个整数并存储到数组 arr 中。

11.求矩阵各行元素之和

【问题描述】
输入m,n 和一个m*n矩阵(最大为10 x10),求他们的各行元素之和。
【输入形式】
第一行输入m和n的值
然后输入m行n列的矩阵【输出形式】
每行元素之和,共m行【样例输入】
2 3
1 2 3
4 5 6
【样例输出】
第0行元素之和是6
第1行元素之和是15

#include <stdio.h>

int main() {
    int m, n;
    
    // 输入矩阵的行数和列数
    scanf("%d %d", &m, &n);
    
    int matrix[m][n];  // 定义一个 m x n 的矩阵
    
    // 输入矩阵的元素
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            scanf("%d", &matrix[i][j]);
        }
    }
    
    // 计算并输出每行元素之和
    for (int i = 0; i < m; i++) {
        int row_sum = 0;  // 记录当前行的元素和
        for (int j = 0; j < n; j++) {
            row_sum += matrix[i][j];  // 累加当前行的每个元素
        }
        printf("第%d行元素之和是%d\n", i, row_sum);  // 输出当前行的元素和
    }
    
    return 0;
}

1. 输入:

  • scanf(“%d %d”, &m, &n);:首先读取矩阵的行数 m 和列数 n。
  • scanf(“%d”, &matrix[i][j]);:逐个读取矩阵的元素,并存储到 matrix 二维数组中。

2. 计算每行元素之和:

  • int row_sum = 0;:每次计算新的一行时,初始化 row_sum 为 0。
  • 在内部的 for 循环中,逐个累加每行的元素。

3. 输出:

  • printf(“第%d行元素之和是%d\n”, i, row_sum);:输出当前行的和。

12.求字符串长度

【问题描述】
任意输一行字符串(包括空格),求其长度(不用strlen函数)
【输入形式】
任意一个字符串【输出形式】
长度
【样例输入】
abcd efg
【样例输出】
8

#include <stdio.h>

int main() {
    char str[100];  // 定义一个数组保存输入字符串
    int length = 0;  // 初始化长度为0

    // 输入一行字符串,包括空格
    fgets(str, sizeof(str), stdin);
    
    // 手动计算字符串长度
    while (str[length] != '\0' && str[length] != '\n') {
        length++;  // 每读取一个字符,长度加1
    }
    
    // 输出字符串长度
    printf("%d\n", length);
    
    return 0;
}

1. 输入字符串:

  • 使用 fgets 函数读取一整行字符串,包括空格。
  • fgets(str, sizeof(str), stdin):从标准输入读取一行,存储到 str 中,最多读取 sizeof(str) - 1 个字符。

2. 计算长度:

  • 从索引 0 开始,遍历字符串,直到遇到字符串结束标志 ‘\0’。
  • 如果 fgets 读取到换行符 ‘\n’,我们也停止计数,因为换行符不是字符串内容的一部分。

3. 输出长度:

  • 打印结果 length。

13.连接两行字符串

【问题描述】
任意输入两行字符串,把第二行字符串连接到第一行字符串末尾(不用strcat函数)
【输入形式】
共2行,每行一个字符串(含空格)【输出形式】
连接后的字符串【样例输入】
abcd
efg
【样例输出】
abcdefg

#include <stdio.h>

int main() {
    char str1[200];  // 用于存储第一行字符串,大小足够容纳拼接结果
    char str2[100];  // 用于存储第二行字符串
    int i = 0, j = 0;

    // 输入第一行字符串
    fgets(str1, sizeof(str1), stdin);
    // 输入第二行字符串
    fgets(str2, sizeof(str2), stdin);

    // 手动计算第一行字符串的末尾位置
    while (str1[i] != '\0' && str1[i] != '\n') {
        i++;  // 移动到第一行字符串的末尾
    }

    // 将第二行字符串逐字符连接到第一行的末尾
    while (str2[j] != '\0' && str2[j] != '\n') {
        str1[i] = str2[j];
        i++;
        j++;
    }

    // 添加字符串结束标志
    str1[i] = '\0';

    // 输出连接后的字符串
    printf("%s\n", str1);

    return 0;
}

1. 输入部分:

  • 使用 fgets 读取两行字符串到 str1 和 str2。
  • fgets 会自动在字符串末尾添加 ‘\0’,但可能会包含换行符 ‘\n’,需要跳过它。

2. 计算第一行字符串的末尾:

  • 遍历 str1 找到其末尾位置(即 ‘\0’ 或 ‘\n’ 之前的索引)。

3. 拼接字符串:

  • 遍历 str2,将每个字符复制到 str1 的末尾位置。

4. 手动添加字符串结束标志:

  • 在拼接完毕后,将 ‘\0’ 添加到 str1 的末尾。

14.删除特定字符后的所有字符

【问题描述】
输入一个字符串和一个特定字符,在字符串中剧除从该特定字符开始的所有字符。
【翰入形式】
共2行
第1行输入任意一个字符串(含空格)
第2行输入一个特定字符
【输出形式】
规除特定字符后的字符串是
【样例输入1】
abcdefg
【样例输出1】
特定字符是d
规除特定字符d后的字符串是abc

#include <stdio.h>

int main() {
    char str[200];   // 用于存储输入的字符串
    char target;     // 用于存储特定字符
    int i = 0;       // 遍历字符串的索引

    // 输入字符串
    fgets(str, sizeof(str), stdin);

    // 输入特定字符
    scanf(" %c", &target); // 注意前面的空格以忽略换行符

    // 查找特定字符的位置
    while (str[i] != '\0') {
        if (str[i] == target) {
            str[i] = '\0'; // 将特定字符位置设置为字符串结束标志
            break;         // 找到后立即停止
        }
        i++;
    }

    // 输出结果
    printf("特定字符是%c\n", target);
    printf("删除特定字符%c后的字符串是%s\n", target, str);

    return 0;
}

1. 输入部分:

  • 使用 fgets 输入字符串,可以包含空格。
  • 使用 scanf 输入特定字符,注意格式 " %c",空格用于跳过换行符。

2. 查找特定字符:

  • 使用 while 循环遍历字符串,检查每个字符是否等于目标字符。
  • 如果找到目标字符,将该位置设为字符串结束标志 ‘\0’,然后终止循环。

3. 截断字符串:

  • 一旦找到特定字符,后面的部分就会被截断,字符串只保留到特定字符之前。

15.自n处抽取字符串中m个字符

【问题描述】
编写程序,从输入的一行字符串中抽取一部分(从第n个字符开始抽取m个字符)构成一个新的字符串,并输出。n>0且n<=字符串的长度,否则提示起始位置-n-越界。
要求:n和m都由用户输入。
如果抽取的字符串长度不够,则按照实际长度抽取,例如,字符串为“abcde”,若n=2,m=3,则抽取结果为“bcd";若n=3,m=5,则抽取结果为“cde”;若n=0,m=4 则输出:起始位置0越界若n=6,m=2 则输出:起始位置6越界
【输入形式】
共3行
第1行任意输入一个字符串(含空格)
第2行输入n的值
第3行输入m的值
【输出形式】
抽取的新字符串
或者
起始位置n越界

#include <stdio.h>
#include <string.h>

int main() {
    char str[200];    // 输入的原字符串
    char result[200]; // 存储抽取后的字符串
    int n, m;         // 起始位置和抽取的字符数
    int length;       // 字符串的实际长度

    // 输入字符串
    fgets(str, sizeof(str), stdin);
    // 去掉字符串末尾的换行符
    str[strcspn(str, "\n")] = '\0';

    // 输入起始位置n和抽取字符数m
    scanf("%d", &n);
    scanf("%d", &m);

    // 获取字符串的长度
    length = strlen(str);

    // 检查起始位置是否越界
    if (n <= 0 || n > length) {
        printf("起始位置%d越界\n", n);
        return 0;
    }

    // 计算实际可抽取的字符数
    int extract_length = (n - 1 + m <= length) ? m : (length - (n - 1));

    // 抽取字符串
    for (int i = 0; i < extract_length; i++) {
        result[i] = str[n - 1 + i]; // n-1是实际索引
    }
    result[extract_length] = '\0'; // 添加字符串结束标志

    // 输出结果
    printf("抽取的新字符串是%s\n", result);

    return 0;
}

  1. 输入部分:
  • 使用 fgets 读取字符串,同时去掉可能的换行符。
  • 使用 scanf 输入起始位置 n 和抽取长度 m。
  1. 检查起始位置是否越界:
  • 起始位置 n 应满足 1 <= n <= length。
  • 如果 n 越界,输出错误提示并结束程序。
  1. 计算实际抽取长度:
  • 如果从第 n 个字符开始的剩余字符数小于 m,则实际抽取长度为剩余字符数。
  • 否则,抽取长度为 m。
  1. 抽取字符:
  • 通过循环将从 str[n-1] 开始的字符复制到 result 数组中。
  • 在结果字符串的末尾添加 \0 表示结束。

16.计算主对角线元素之和

【问题描述】输入一个4行4列的单精度数组,计算主对角线元素之和,保留1位小数输出。
【翰入形式】
4行4列单精度数据,数据之间用空格分隔
【翰出形式】
主对角线元素之和
【样例输入】
1.5 2.1 3.4 8.5
5.6 36 9923
3.5 1.6 8.5 7.6
1.0 22 34 5.6
【样例输出】
19.2

#include <stdio.h>

int main() {
    float matrix[4][4]; // 定义一个 4x4 单精度矩阵
    float sum = 0.0;    // 初始化主对角线元素的和为 0.0

    // 输入矩阵元素
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            scanf("%f", &matrix[i][j]);
        }
    }

    // 计算主对角线元素之和
    for (int i = 0; i < 4; i++) {
        sum += matrix[i][i]; // 主对角线元素的条件是 i == j
    }

    // 输出结果,保留 1 位小数
    printf("%.1f\n", sum);

    return 0;
}

17.数组合并

【问题描述]
分别输入两个长度为5的从小到大排好序的整数数组,将这两个数组合并到第三个数组中,保持从小到大的排序,并输出。
【输入形式】
共2行,每行5个整数,数据之间用空格分隔
【输出形式】
从小到大输出合并后的数组值,每个整数后面用一个空格进行分隔
【样例输入】
13579
02468
【样例输出】
0123456789

#include <stdio.h>

int main() {
    int arr1[5], arr2[5], merged[10];
    int i = 0, j = 0, k = 0;

    // 输入第一个数组
    for (i = 0; i < 5; i++) {
        scanf("%d", &arr1[i]);
    }

    // 输入第二个数组
    for (i = 0; i < 5; i++) {
        scanf("%d", &arr2[i]);
    }

    // 合并两个数组
    i = 0; j = 0; // 初始化两个数组的索引
    while (i < 5 && j < 5) {
        if (arr1[i] < arr2[j]) {
            merged[k++] = arr1[i++]; // 将 arr1[i] 放入结果数组
        } else {
            merged[k++] = arr2[j++]; // 将 arr2[j] 放入结果数组
        }
    }

    // 如果 arr1 有剩余元素,追加到结果数组
    while (i < 5) {
        merged[k++] = arr1[i++];
    }

    // 如果 arr2 有剩余元素,追加到结果数组
    while (j < 5) {
        merged[k++] = arr2[j++];
    }

    // 输出合并后的数组
    for (i = 0; i < 10; i++) {
        printf("%d ", merged[i]);
    }
    printf("\n");

    return 0;
}

合并逻辑:

  • 初始化两个索引 i 和 j,分别指向 arr1 和 arr2 的开头。
  • 逐个比较两个数组的当前元素,将较小的元素放入 merged 数组。
  • 如果一个数组被全部合并,直接将另一个数组的剩余部分追加到 merged 中。

18.统计数组中出现频率最高的数

【问题描述】
任意读入10个整数存放到数组a中,统计数组中出现频率最高的数,特出该数及其出现次数。
如果数组中没有重复出现的数,则输出"没有重复出现的数”;如果有多个频率最好的数字,按照输入的先后顺序全部输出,参考下的程序运行示例。
【输入形式】
10个整数,数据之间用空格分隔
【输出形式】
共2行
第1行输出a数组中的数据,每个数据后面用1个空格进行分隔第2行输出出现频率最高的数和出现次数
【样例输入】
11 22 33 33 44 55 66 77 88 99
【样例输出】
a数组元素为:11 22 33 33 44 55 66 77 88 99数组a中出现频率最高的数是33,出现次数为2

思路:

  1. 使用一个辅助数组 freq 来记录每个数的出现次数。
  2. 遍历数组,更新每个数的出现次数。
  3. 找出频率最高的次数及对应的数。
  4. 如果有多个数频率最高,则按照输入顺序依次输出。
#include <stdio.h>

int main() {
    int a[10];          // 用于存储输入的数组
    int freq[10] = {0}; // 用于存储每个数的出现次数
    int i, j;
    int max_freq = 1;   // 记录最高出现次数,初始值为 1
    int has_duplicates = 0; // 标记是否存在重复的数字

    // 输入 10 个整数
    for (i = 0; i < 10; i++) {
        scanf("%d", &a[i]);
    }

    // 输出数组元素
    printf("a数组元素为:");
    for (i = 0; i < 10; i++) {
        printf("%d ", a[i]);
    }
    printf("\n");

    // 统计每个数的出现次数
    for (i = 0; i < 10; i++) {
        for (j = 0; j < 10; j++) {
            if (a[i] == a[j]) {
                freq[i]++;
            }
        }
        // 更新最高频率
        if (freq[i] > max_freq) {
            max_freq = freq[i];
            has_duplicates = 1; // 存在重复数字
        }
    }

    // 输出结果
    if (max_freq == 1) {
        printf("没有重复出现的数\n");
    } else {
        printf("数组a中出现频率最高的数是:");
        for (i = 0; i < 10; i++) {
            if (freq[i] == max_freq) {
                printf("%d,", a[i]);
                freq[i] = 0; // 避免重复输出相同数
            }
        }
        printf("出现次数为%d\n", max_freq);
    }

    return 0;
}

1. 输入和输出数组:

  • 输入 10 个整数存入数组 a。
  • 使用 printf 输出数组的所有元素。

2. 统计频率:

  • 使用双重循环比较数组中的每个元素,计算它的出现次数,并存入 freq 数组。
  • 内层循环对每个元素进行比较,如果找到相同的值,则相应位置的频率值加 1。

3. 确定最高频率:

  • 每次更新 freq 时,比较其值是否大于当前的 max_freq,如果是,则更新 max_freq。
  • 同时通过标志变量 has_duplicates 确认是否存在重复数字。

4. 输出结果:

  • 如果最高频率为 1,则说明所有数字没有重复。
  • 如果存在最高频率,遍历 freq,输出所有频率等于 max_freq 的数。

祝小丢丢学有所成

;