【黑马程序员】---C语言经典编程实例分析

时间:2022-06-01 16:51:43
------- android培训ios培训、期待与您交流! ----------


C语言经典编程题


题目01:在一个已知的字符串中查找最长单词,假定字符串中只含字母和空格,空格用来分隔不同的单词。

int main()
{
    // 用数组定义一个字符串
    char array[50] = "zha  junju  zhamengjun z mengjun";
    
    char *str = array;      // 定义指针变量str,指向数组array
    int len = 0;            // 定义变量len,用于计数
    int max = 0;            // 定义变量max,存放最长单词的长度
    char *p = 0;            // 定义指针变量p,指向最长单词的首字符
    
    // 判断指针当前指向的字符是不是'\0'
    while(*str != '\0')
    {
        if(*str != ' ')     // 判断字符是不是空格
        {
            len++;          // 计数加1
            
            // 判断最大长度跟len长度的大小
            if(max < len){
                max = len;    // 如果max小于len,将len赋值给max
                p = str - len + 1;    // 将单词的首字符的地址赋值给指针变量p
            }
            
            str++;       // 让指针str指向下一个字符
        }
        else
        {
            len = 0;     // 如果当前的字符为空格,将len初始化为0,重新计数
            str++;       //让指针str指向下一个字符
        }
    }
    
    // 给最大单词后面添加一个字符串结束标记'\0'
    *(p + max) = '\0';

    printf("最长的单词是%s\n", p);    // 在屏幕上输出最长的单词
    return 0;
}

心得体会:

(1)首先定义一个记录单词长度的变量len和存放最长单词的长度的整形变量max,并初始化max为0;

(2)通过while循环,遍历整个字符串,当遍历到的字符非空格时,变量len依次加1,若len的长度大于max,就将len赋值给max,同时用指针变量p记录单词的首字符地址。并且每判断依次,让指针指向下一个字符。

(3)当遍历到的字符是空格时就将len的长度赋值为0,重新计数,并且让指针str指向下一个字符。

(4)通过给最大单词后面一个字符赋值为‘\0’,以便输出最长单词。


题目02:编写一个int string_len(char *s),返回字符串s的字符长度(不包括\0)。

int string_len(char *s);    // 声明函数string_len(char *s)

int main()
{
    char *str = "zhamengjun哈哈";    // 利用指针定义一个字符串
    
    // 定义一个变量length,存储函数string_len返回的字符串的字符长度
    int length = string_len(str);
    
    // 在屏幕上输出打印字符串的字符长度
    printf("字符串%s的长度为%d\n", str, length);
    return 0;
}

int string_len(char *s)     // 定义函数string_len(char *s)
{
    int count = 0;          // 记录字符的个数
    
     // 判断指针当前指向的字符是不是'\0',
    while(*s != '\0')
    {
        count++;            // 字符个数增加1
        s++;                // 让指针s指向下一个字符
    }
    
    return count;               // 返回字符串的字符长度
}

心得体会:

(1)定义一个整形变量count记录字符的长度,并初始化初始长度为0;

(2)利用while循环来遍历字符串,直到遇到字符串结束标记‘\0'为止;

(3)每循环一次,计数变量count加1,让指针指向下一个字符;

(4)调用函数,输出结果。


题目03:编程实现将任意的十进制整数转换成任意R进制数(R在2-16之间)。

int main()
{
    
    int i = 0;      // 定义整型变量i计数
    int num = 0;    // 定义整型变量num,存储十进制整数
    int R = 0;      // 定义整型变量R,存储要转换的进制数
    int arr[100];    // 定义数组arr,存储转换结果
    
    char charOf[] = "012346789ABCDEF";    // 定义字符数组charOf,处理结果为ABCDEF的问题
    
    printf("请输入一个十进制整数\n");
    scanf("%d", &num);
    printf("请输入要转的进制数(在2~16)之间\n");
    scanf("%d", &R);
    printf("%d转%d进制的结果是:", num , R);
    
    // 取余法,实现十进制对其它进制的转换
    while (num != 0) {
        
        
        arr[i] = num % R;   // 将每一次的余数存储在整型数组中
        num = num / R;      // 得到商num,作除数,继续参与运算
        i++;                // 计数加1
        
    }
    
    while (i > 0) {
        
        i--;        // 这需先减一次,因为之前i++多加了一个下标
        
        // 将整型数组arr对应的字符数组charOf的值倒序输出
        char c = charOf[arr[i]];
        printf("%c", c);
    }
    
    printf("\n");
}


心得体会:

(1)定义一个数组arr,将每次十进制取余其它进制的的值保存在数组arr的每一个元素当中,从数组arr[0]开始;

(2)通过while循环,将每一次十进制除以其它进制的商赋值给num,以便作为下一个循环的除数,知道num为0为止;

(3)定义一个数组charOf,并初始化为“012346789ABCDEF”,将整形数组arr对应的字符数组charOf的值倒序输出

(4)要注意计数i的值到了哪一位


题目04:小明从2006年1月1日开始,每三天结识一个美女两天结识一个帅哥,编程实现当输入2006年1月1日之后的任意一天,输出小明那天是结识美女还是帅哥

#include <stdio.h>

// 用宏定义参考的年月日
#define Year 2006
#define Month 1
#define Day 1

int main()
{
    int year, month, day;   // 定义3个整型变量分别存储用户输入的年、月、日
    
    // 从键盘输入符合条件的日期
    do {
        printf("请输入一个在2006年1月1日之后的日期,格式为:yyyy-m-dd\n");
        scanf("%d-%d-%d", &year, &month, &day);
    } while ((year < Year || month < Month || day <= Day) || (month > 12 || month < 1) || (day > 31 || day < 1 ));
    
    int sumDaysOfYear = 0;  // 定义整形变量存储相隔年数的总天数
    
    // 利用循环求出相隔年数的总天数
    for (int y = Year; y < year; y++)
    {
        // 判断是平年还是闰年
        if (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
        {
            sumDaysOfYear += 366;   // 闰年一年366天
        }
        else
        {
            sumDaysOfYear += 365;   // 平年一年365天
        }
    }
    
    int sumDaysOfMonth = 0; // 定义整型变量存储相隔月份的总天数
    // 定义一个表示平年各个月份的整型数组
    int pingYear[] = {31,28,31,30,31,30,31,31,30,31,30,31};
    // 定义一个表示闰年各分月份的整型数组
    int yunYear[] = {31,29,31,30,31,30,31,31,30,31,30,31};
    
    // 利用循环求出相隔月份的总天数
    for (int m = Month; m < month; m++)
    {
        if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
        {
            sumDaysOfMonth += yunYear[month - 1];
        }
        else
        {
            sumDaysOfMonth += pingYear[month - 1];
        }
    }
    
    int days = day - Day; // 定义整型变量days,存储一个月内相隔的天数
    int sumDays = 0;    // 定义整型变量sumDays,存储两个时间点相隔的总天数
    
    // 得到两个时间点相隔的总天数
    sumDays = sumDaysOfYear + sumDaysOfMonth + days;
    
    printf("两个时间点相隔%d天\n", sumDays);
    
    // 根据相隔的天数,判断小明遇到的人
    if((sumDays % 2 == 0) && (sumDays % 3 == 0))
    {
         printf("小明既结识了帅哥又结识了美女!\n");
    }
    else if(sumDays % 2 == 0)
    {
        printf("小明结识了帅哥!\n");
    }
    else if (sumDays % 3 == 0)
    {
        printf("小明结识了美女!\n");
    }
    else
    {
        printf("小明没有结识帅哥和美女\n");
    }
}


心得体会:

(1)利用for循环遍历,if条件来判断是平年还是闰年,求出相隔年数的累加的天数

(2)同理,利用第一步的方法,求出相隔月数的累加的天数,只是要注意每月的天数,根据平年和闰年的不同分别保存在两个不同的数组中,以便利于累加

(3)将输入的日减1,计算出当月相隔的天数,最后求出两个日期相隔的总天数。

(4)根据总天数取余2和3,判断出小明当天结识的是美女还是帅哥。

题目05:提示用户输入一个正整数n,利用while循环计算并输出:1-2+3-4+5-6+7…+n的和。

int main()
{
    // 1.定义变量存储用户输入的整数
    int n = 0;
    
    // 2.判断n是否为正整数
    while (n <= 0) {
        // 2.1 提示输入
        printf("输入一个正整数:\n");
        
        // 2.2 让用户输入
        scanf("%d", &n);
    }
    
    // 3.计算阶乘
    int sum = 0; // 存储计算结果
    int current = 0; // 当前要累加的数值
    while (current < n) {
        current++;
        
        // 如果是偶数,就减
        if (current % 2 == 0) {
            sum -= current;
        } else { // 如果是奇数,就加
            sum += current;
        }
    }
    
    // 4.输出结果
    printf("%d\n", sum);
    
    return 0;
}

心得体会:

(1)确保从键盘上输入的是一个整数(用while来判断);

(2)用while循环来遍历从1到n的值;

(3)通过奇偶性判断所要累加数值的正负性,奇数就累加,偶数就累减。


题目06:提示用户输入一个正整数n,计算并输出n的阶乘结果:1*2*3*…*n。

int main()
{
    // 1.定义变量存储用户输入的整数
    int n = 0;
    
    // 2.判断n是否为正整数
    while (n <= 0) {
        // 2.1 提示输入
        printf("输入一个正整数:\n");
        
        // 2.2 让用户输入
        scanf("%d", &n);
    }
    
    // 3.计算阶乘
    int result = 1; // 存储计算结果
    int current = 1; // 当前的乘数
    while (current <= n) {
        result *= current; // 累乘每次的乘数
        current++; // 乘完一次就++
    }
    
    // 4.输出阶乘结果
    printf("%d! = %d\n", n, result);
    
    return 0;
}


心得体会:

(1)可以利用for循环或者while循环进行遍历,利用累乘即可求出值。

(2)还可以利用递归来做,更简单。


题目07:编写一个函数,判断某个字符串是否为回文。回文就是从左边开始读 和 从右边开始读 都是一样的,比如"abcba"

int main()
{
    printf("%d\n", isHuiwen("a"));
    return 0;
}

/*
 返回1代表是回文
 返回0代表不是回文
 */
int isHuiwen(char *str)
{
    // 1.定义一个指向变量left指向字符串的首字符
    char *left = str;
    // 2.定义一个指向变量right指向字符串的末字符
    char *right = str + strlen(str) - 1;
    
    while (left < right)
    {
        // 如果左边和右边的字符不一样
        if (*left++ != *right--)
        {
            return 0;
        }
    }
    
    return 1;
}


心得体会:

(1)重点要知道得到字符串的首字符和末字符的地址,取出字符串两头的值来判断是否相等、

(2)保证while条件,只能循环到中间就可以了,利用(left < right)


题目08:编写一个函数void strlink(char s[], char t[]),将字符串t连接到字符串s的尾部。

int main()
{
    char s1[20] = "michael ";
    char s2[] = "jackson";
    
    strlink(s1, s2);
    
    printf("%s\n", s1);
    
    return 0;
}

void strlink(char s[], char t[])
{
    int i = 0;
    
    // 判断s[i]是否为字符串的尾部
    while ( s[i] != '\0' )
    {
        i++;
    }
    
    int j = 0;
    // 拷贝t的内容到s的后面
    while ( (s[i] = t[j]) != '\0' )
    {
        i++;
        j++;
    }
}

心得体会:

(1)通过while循环遍历,得到第一个字符串结束标记‘\0'的位置。

(2)利用第二个while循环,从字符串s结束位置开始,将字符串t依次赋值到s结束位置后面。


题目09:提示用户输入一个正整数n,求出并输出下列结果:1! + 2! + 3! + 4! + ... + n!       要求:用至少两种方式实现(函数名自拟,函数个数不限)

int pieAdd(int n);

int main()
{
    // 1.定义变量存储用户输入的整数
    int n = 0;
    
    // 2.判断n是否为正整数
    while (n <= 0)
    {
        // 2.1 提示输入
        printf("输入一个正整数:\n");
        
        // 2.2 让用户输入
        scanf("%d", &n);
    }
    
    // 3.计算结果
    int result = pieAdd(n);
    
    printf("结果是%d\n", result);
    
    return 0;
}

// 非递归的方式
int pieAdd(int n)
{
    // 1.定义变量保存总和
    int sum = 0;
    
    // 2.需要累加n次,每次累加的都是一个阶乘值
    for (int i = 1; i<=n; i++)
    {
        // 3.计算阶乘i!
        // 3.1 定义变量保存阶乘的结果
        int multi = 1;
        for (int j = 1; j<=i; j++)
        {
            multi *= j;
        }
        
        // 4.累加每次的阶乘结果
        sum += multi;
    }
    
    // 5.返回和
    return sum;
}

/*
// 递归的方式
int sum(int n)	// 定义一个sum函数,用于求出每一个阶乘的和。
{
	if(n == 1)	// 定义一个结束条件
		return 1;
	return sum(n - 1) + count(n);	// 求出每一个阶乘的累加和
}

// 定义和求出一个累加和
int count(int n)
{
	if(n == 1)
		return 1;
	return count(n - 1) * n;
}

心得体会:

(1)非递归的方式是采用循环累加的方式求出结果的,它是通过将累加和累乘结果求值的。

(2)递归的方式是通过递归函数count计算每一个阶乘的乘积,然后通过另一个递归函数返回值的累加,最后求出结果

(2)递归的方式求值的时候一定要注意定义一个结束条件。


题目10:设计一个函数:将一维整型数组中的元素逆序存放。比如本来是1,3,4,2,逆序存放就变成了:2,4,3,1

void reverse(int array[], int len);
int main()
{
    int ages[4] = {1, 3, 4, 2};	// 定义一个数组,并初始化
    
    reverse(ages, 4);
    
    for (int i = 0; i<4; i++)	// 循环遍历数组,并输出
    {
        printf("%d\n", ages[i]);
    }
    
    return 0;
}

void reverse(int array[], int len)
{
    // 左边元素的下标(默认是最左边)
    int left = 0;
    // 右边元素的下标(默认是最右边)
    int right = len - 1;
    
    // 如果左边元素的下标 < 右边元素的下标
    while (left < right)
    {
        // 利用中间变量交换两个元素的值
        int temp = array[left];
        array[left] = array[right];
        array[right] = temp;
        
        // 交换一次后,左边元素下标增加,右边元素下标减小
        
        left++;
        right--;
    }
}

心得体会:

(1)首先要明白一点,为什么不能通过sizeof(array) / sizeof(int) 来求出数组元素的个数?因为当数组作为参数传递的时候,函数的参数array实际上当做变量来存储传来的数组首元素的地址。而每一个指针变量占用8个字节。

(2)分别拿出数组首元素和数组尾元素,然后利用中间变量交换两个元素的值。

(3)利用while循环,遍历数组元素,并使left< right保证循环到中间即可,否则每个元素又进行一次交换,结果值没有改变。

(4)函数reverse不需要返回值,因为改变了形参数组也就改变了外面的实参数组,因为数组是按址传递的。