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

时间:2022-09-20 00:25:01
------- 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不需要返回值,因为改变了形参数组也就改变了外面的实参数组,因为数组是按址传递的。