编程注重实战练习,笔者将近期从头开始敲的C语言代码练习分享出来,打算作为将来自己回顾温习的宝典,同时也可以借互联网的平台为大家一起学习C语言献出绵薄之力。以C语言应试为重心的读者可以快速浏览例题代码并直接翻阅最后的C语言经典习题。
任何代码都是可以被优化的,每个问题也都可以用不同的解法。笔者确保每段源代码在C++环境下都可以运行。读者们有所思所想的,欢迎评论留言。
关于C语言语法知识点内容,笔者将会写在最新的笔记博客中。知识点和练习都会不断更新内容,力求逐步做到C语言入门的水准。
另外要说明的是,cpp文件兼容C语法,因此笔者的代码主要用C语法,有部分使用C++语法。简单的代码很快过,来回切中英文不方便,因此大部分简单的代码不做中文注释了,但是规范一点的观念还是应该一行代码一行注释。
各章分有案例习题分析和实战项目练习两个板块。例题也是习题,可以先自己写,再比对。
#include
#include
int main() {
printf("Hello C++World! I'm coming. \r\n\0");
system("pause");
return 0;
}
代码分析:首先,最重要的是main函数,也被称作主函数或入口函数,是一切代码执行的入口,一个项目必须有且只能有一个main。关于main,早期编程者使用void main()无需返回值,因安全性问题现在的编程规范要求使用int main(int argc,char const *argv[]),最后函数返回值为0,它可以被简写为int main(void),void可以省略。
其次,printf库函数的使用,print打印,f函数/功能(function)。注意格式使用,善用printf可以使控制台程序的交互性很好。注意我们要使用库函数时,需要和系统“打个招呼”,也就是声明使用到的头文件,这是很重要的一点。输出函数printf和读取函数scanf都 包含(include)在标准(standard)输入(input)输出(output)头文件(.header)中,即include
最后,为了让程序的结束由人来控制,笔者习惯加上system(“pause”);,当然也可以加getchar();。它应该需要用到标准静态链接库lib ,
其实单单一个printf库函数就包含C的很多知识点,笔者也刚入门,在这里就这样点一下,有兴趣的读者可以另外查阅资料深入了解。printf读入的字符串默认补’\0’(即字符串结束标志NULL,ASCII码值也为0),如果遇到’\0’,后面的字符均不再被输出。‘\n’是换行,即跳至下一行,一般用来替代’\r’‘\n’,'\r’是回车,这里头包含了计算机发展的历史,在UNIX和MAC系统中行末只有\n(前者)或\r(后者)而Windows系统行末是\r\n。
打断点,逐步运行代码,查看变量值变化,找出原因修改代码或优化代码。
华氏度转换成摄氏度
#include
#include
int main() {
int c, f;
printf("input f:\n");
scanf("%d", &f);
getchar();
c = 5 * (f - 32) / 9;
printf("c = %d\n", c);
system("pause");
return 0;
}
代码分析:顺序结构。从华氏度fahrenheit转换为摄氏度celsius,常规的思路是:用一个变量存放输入的华氏度,用第二个变量存放转换后的摄氏度,根据二者已被发现的转换关系建立等式计算,最后输出结果。
scanf后加getchar,是笔者的个人习惯,它的作用是接收scanf最后敲的回车符,让它不会留在缓存里当多次使用scanf时不这样会有漏洞。更好的方式:while(getchar() != ‘\n’)接收scanf未读取的所有留在缓存中的字符(包括回车);也可以使用fflush函数清空缓存区,但频繁使用fflush会损伤硬盘。
延伸1:华氏度转摄氏度对照表–利用循环
#include
#include
int main() {
int lower, upper;
printf("input lower:\n");
scanf("%d", &lower);
getchar();
printf("input upper:\n");
scanf("%d", &upper);
getchar();
if (upper < lower){
printf("error!\n");
}
else {
printf("the turning form is as below:\n");
printf(" f \t \t c\n");
for (int f =lower; f <= upper; f++) {
double c = (double)(5 * (f - 32)) / 9.0;
printf("%d \t|\t%.1f \t\n", f, c);
}
}
system("pause");
return 0;
}
代码分析:使用两个变量分别定义对照表的下限(lower)和上限(upper),并让其分先后输入并判断两数大小是否合理,避免漏洞。else包括的部分利用for循环开始计算相应的数据,默认步长为1。代码中’\t’相当于敲一下TAB键,作用是切至下一个空制表位首部可以拉开间距,使运行窗口内容展示更美观。不同编译器定义的制表位大小不同(4个或8个空格),因此编程时最好使用空格缩进,这样做的好处之一在于任何人用任何编辑器查看代码内容时代码都是对齐的,另一个好处是当需要压缩发布代码时有更好的压缩率(使用TAB的代码熵更高,压缩后反而会变大)。
延伸2:华氏度、摄氏度、开尔文(热力学温标)三者对照表
代码分析:
#include
#include
int main() {
double x, y;
printf("input water hausted : unit:t(ton)\n");
scanf("%lf", &x);
getchar();
if (x <= 15) {
y = x * 4 / 3;
}
else {
y = 2.5 * x - 10.5;
}
printf("cost is %.2f CNY(Chinese Yuan)\n", y);
system("pause");
return 0;
}
代码分析:梯度缴纳水费,关键在于使用分支结构(if……else)判断划分梯度的条件是否满足了。
延伸1:电费梯度缴纳
#include
#include
int main() {
double q, cost;
printf("input hausted electric quantity(kWh):\n");
scanf("%lf", &q);
getchar();
if (q < 0) {
printf("Invalid Value!\n");
}
else {
if (q <= 50) {
cost = q * 0.53;
}
else {
cost = q * 0.53 + (q - 50) * 0.05;
}
printf("cost = %.2f\n", cost);
}
system("pause");
return 0;
}
代码分析:更复杂的分支结构,if……else可以嵌套。
延伸2:出租车里程计价
#include
#include
int main() {
double way_bill, time_bill, distance;
int extra_time;
printf("input distance(km) and extra_time(min):");
scanf("%lf %d", &distance, &extra_time); //scanf%.nlf is wrong
getchar();
time_bill = (extra_time / 5) * 2;
if (distance <= 3) {
way_bill = 10;
}
else if (distance <= 10) {
way_bill += 10 + (distance - 3) * 2;
}
else {
way_bill += 10 + 7 * 2 + (distance - 10) * 2 * (1 + 0.5);
}
printf("%.0fYuan\n", way_bill + time_bill);
system("pause");
return 0;
}
代码分析:多分支结构if……else if……else。另一种多分支结构语句switch (choose) {case:break; default:break;}。
要求:计算输入的整数的位数并打印出各位数字(即逆序输出)。
#include
#include
int main() {
int count = 0, num;
printf("input an integer:\n"); //upper limit value
scanf("%d", &num);
getchar();
if (num < 0) { //print figure's numbers has meaning, only figure no meaning
num = -num; //C++
}
printf("figure's(low to high) numbers are:");
do {
printf("%d", num%10);
num /= 10; //num = num / 10; +-int turn->0
count++;
} while (num);
printf("\nthe number includes %d figure\n", count);
system("pause");
return 0;
}
代码分析:
最基础版:sum = 1+2+……+n
#include
#include
int main() {
int n, sum = 0, i;
printf("input n:\n");
scanf("%d", &n);
getchar();
for (i = 1; i <= n; i++) {
sum += i;
}
printf("sum = %d\n", sum);
system("pause");
return 0;
}
代码分析:
延伸:sum = S(i^2 + 1/i) , ( i 的范围:[m, n])
#include
#include
int main() {
int m, n;
double S = 0;
printf("input m and n:\n");
scanf("%d %d", &m, &n);
while (getchar() != '\n') {;}
for (int i = m; i <= n; i++) {
S += i * i + 1.0 / i;
}
printf("sum = %.6f\n", S);
system("pause");
return 0;
}
代码分析:
求非负整数数列的奇数项和
#include
#include
int main() {
int n, sum_odd = 0;
printf("input some >=0 interger:\n"); //odd even = Z
while (1) {
scanf("%d", &n);
getchar();
if (n < 0) {
break;
}
else if (n % 2 == 0) {
continue;
}
else {
sum_odd += n;
}
}
printf("odd's sum = %d\n", sum_odd);
system("pause");
return 0;
}
计算a+aa+aaa+a……a(n个a)的值
#include
#include
int main() {
int a, n, s = 0, item = 0;
printf("input a(>0&&<10) and n(>0&&<10) : calculate a + aa + ... + aa..a(n)\n");
scanf("%d %d", &a, &n);
getchar();
for (int i = 1; i <= n; i++) {
item = item*10 + a;
s += item;
}
printf("s = %d\n", s);
system("pause");
return 0;
}
代码分析:aa = a*10 + a
高空坠下一小球,每次触底反弹高度是原高度的一半,第n次反弹时总共经过多少距离,并给出这次反弹后返回的高度。
#include
#include
int main() {
float h, d;
int n;
printf("input h0 and touchtimes: \n");
scanf("%f %d", &h, &n);
getchar();
if (n <= 0) {
printf(" the ball totally run 0,and its next height %.1f\n", h / 2);
}
else {
printf("after %d touch ,\n", n);
d = h;
while (n - 1) {
n--;
h = h / 2;
d += 2 * h;
}
printf(" the ball totally run %.1f ,and its next height %.1f\n", d, h / 2);
}
system("pause");
return 0;
}
#include
#include
int main() {
int letter = 0, number = 0, others = 0;
char ch;
printf("input a 10 char string:\n\0");
for (int i = 1; i <= 10; i++) {
ch = getchar();
if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) { //65 97 10 32 EOF
letter++;
}
else if (ch >=48 && ch <= 57) { //'0'~'9' ASCII
number++;
}
else {
others++;
}
}
printf("char %d\tnum %d\tother %d\n",
letter, number, others);
system("pause");
return 0;
}
代码分析:
作业:统计学生成绩,求平均值及不及格人数
#include
#include
int main() {
int n, n_fail = 0;
float grade, total = 0;
printf("input how many students:\n");
scanf("%d", &n);
getchar();
if (n <= 0) {
printf("average score is 0\n");
}
else {
for (int i = 1; i <= n; i++) { //change to while
printf("input student%d's grade\n", i);
scanf("%f", &grade);
getchar();
total += grade;
if (grade < 60) {
n_fail++;
}
}
printf("average score is %.1f; fail numbers are %d\n", (total / n), n_fail);
}
system("pause");
return 0;
}
//another view think-we don't kown students numbers & use while grade>=0
/*
int n = 0, n_fail = 0;
float grade, total = 0;
printf("input grade:if you want to end input , input grade<0\n");
scanf("%f", &grade);
getchar();
while (grade >= 0) {
total += grade;
n++;
if (grade < 60) {
n_fail++;
}
printf("input grade:if you want to end input , input grade<0\n");
scanf("%f", &grade);
getchar();
}
if (n) {
printf("average score is %.1f; fail numbers are %d\n", (total / n), n_fail);
} else {
printf("average score is 0\n");
}
system("pause");
*/
代码分析:
补充作业:找出学生最高分
#include
#include
int main() {
int n, grade, i, max = 0;
printf("input students number :\n");
scanf("%d", &n);
getchar();
printf("output %d students' grade:\n", n);
while (n--) {
scanf("%d", &grade);
getchar();
if (max < grade) {
max = grade;
}
}
printf("the highest grade is %d :\n", max);
system("pause");
return 0;
}
while循环改成for循环?
猜数字初版
#include
#include
int main() {
int target = 37, n;
printf("input guess number(1~100):\n");
do {
scanf("%d", &n);
getchar();
if (n == target) {
printf("bingo!\n");
break;
}
else if (n > target) {
printf("guess a smaller number again\n");
}
else {
printf("guess a bigger number again\n");
}
}while (1);
system("pause");
return 0;
}
代码分析:
猜数字进阶
#include
#include
#include
int main() {
srand(time(NULL) * 1); //unsigned int time(0/NULL)*m~flexible & ?getpid~fixed
int target = rand() % 100 + 1; //rand()%b+a: range=[a,b)
int n, cnt = 0;
char choice;
while (1) { //do...while is the same
do {
printf("input guess number(1~100):");
scanf("%d", &n);
getchar();
cnt++;
if (n == target) {
printf("bingo! you used %d times\n", cnt);
break;
}
else if (n > target) {
printf("guess a smaller number again\n");
}
else {
printf("guess a bigger number again\n");
}
}while (1);
printf("do you want again?N/n:no,else yes input: \n");
scanf("%c", &choice);
getchar();
if (choice == 'n' || choice == 'N') {
break;
}
else { //reset
target = rand() % 100 + 1; //
cnt = 0;
}
}
system("pause");
return 0;
}
代码分析:srand随机种子,rand本质上仍不是真正的随机,当需要随机的数据量达到一定规模时会发现数据分布符合正态分布。
猜数字改版
#include
#include
//#include //getch
int main() {
int target = 0, n, cnt = 0, times, flag = 0;
printf("input target number(>=0):");
scanf("%d", &target);
getchar();
/*while (1) { //hide target number has bugs
target = getch();
if (target == '\r') {
break;
}
putchar('*'); // \b back
}*/
printf("input permit guess times(>0):");
scanf("%d", ×);
getchar();
do {
printf("please input guess number(>=0):\n");
scanf("%d", &n);
getchar();
cnt++;
if (n < 0) {
printf("End\n");
flag = 1;
}
else if (n > target) {
printf("You guessed bigger than the target.\n");
}
else if (n < target) {
printf("You guessed smaller than the target.\n");
}
else {
if (cnt == 1) {
printf("eye to eye\n");
}
else if (cnt <=3) {
printf("good luck\n");
}
else {
printf("bingo\n");
}
flag = 1;
}
if (cnt == times) {
if (!flag) {
printf("Game Over\n");
flag = 1;
}
}
}while (!flag);
system("pause");
return 0;
}
代码分析:由人输入数字(人想数字是相对真正随机的),再由另一人猜。
#include
#include
int main() {
int option;
double price;
printf("******** Auto Purchase Machine ********\n");
for (int i = 0; i < 5; i++) {
printf("*1.Crips*\t*2.PopCorn*\t*3.Chocolate*\t*4.Cola*\n");
printf("******** \t*0.exit*\t ********\n\n");
printf("choose a number above:");
scanf("%d", &option);
getchar();
if (option == 0) {
break;
}
switch (option) {
case 1: {
printf("Crips~");
price = 4.0;
break;
}
case 2: {
printf("PopCorn~");
price = 4.5;
break;
}
case 3: {
printf("Chocolate~");
price = 6.5;
break;
}
case 4: {
printf("Cola~");
price = 3.0;
break;
}
default: {
price = 0;
break;
}
}
printf("price is %.2f\n\n", price);
}
printf("\n***look forward to your next visit!***\n");
system("pause");
return 0;
}
代码分析:
#include
#include
int main() {
double num1, num2;
char ope; //ope = getchar(); putchar('')
printf("input a formula like : num1+num2\n");
scanf("%lf%c%lf", &num1, &ope, &num2);
getchar();
if (ope == '+') { //switch (int char short /long bool string) no arr[](javascript?) or function
printf("=%.2f\n", (num1 + num2));
}
else if (ope == '-') {
printf("=%.2f\n", (num1 - num2));
}
else if (ope == '*') {
printf("=%.2f\n", (num1 * num2));
}
else if (ope == '/') {
if (!num2) {
printf("/0 err\n");
}
else {
printf("=%.2f\n", (num1 / num2));
}
}
else {
printf("unkown character\n");
}
system("pause");
return 0;
}
代码分析:笔者之前的一篇博客写了简易计算器的多个版本,大家可以参考。
求出四个数的和与均值
#include
#include
#define LEN 4
int main() {
int num[LEN] = {0}, Sum = 0;
float Average = 0;
printf("input four numbers like: num1 num2 num3 num4\n");
scanf("%d %d %d %d", &num[0], &num[1], &num[2], &num[3]);
getchar();
for (int i = 0; i < LEN; i++) {
Sum = Sum + num[i];
}
Average = (float)Sum / LEN;
printf("Sum = %d;Average = %.1f\n", Sum, Average);
system("pause");
return 0;
}
三个数从小到大输出(三数比大小)
#include
#include
#define LEN 4
int main() {
int num[LEN] = {0}; //ex1 LEN invalid
printf("input three numbers:\n");
scanf("%d %d %d", &num[1], &num[2], &num[3]);
getchar();
for (int i = 1; i <= (LEN - 1) - 1; i++) { //basic bubble sort small->big int i only
for (int j = 1; j <= (LEN - 1) - i; j++) {
if (num[j] > num[j + 1]) {
num[0] = num[j];
num[j] = num[j + 1];
num[j + 1] = num[0];
}
}
}
for (int i = 1; i <= (LEN - 1); i++) { //printf("%d->%d->%d\n", num[1], num[2], num[3]);
if (i == LEN - 1) {
printf("%d\n", num[i]);
}
else {
printf("%d->", num[i]);
}
}
system("pause");
return 0;
}
代码分析:冒泡法排序
案例引入1:判断素数
#include
#include
int main() {
int m, i = 2;
printf("input a interger :\n");
scanf("%d", &m);
getchar();
for (i; i <= m / 2; i++) { //
if (m % i == 0) {
break;
}
}
if (i > m / 2 && m > 1) { //
printf("it is a primer\n");
}
else {
printf("not a primer\n");
}
system("pause");
return 0;
}
代码分析:
案例引入2:输出素数(要求有换行)
#include
#include
#include
int main() {
int cnt = 0, i, m;
printf("primer numbers are:\n");
for (m = 2; m <= 10000; m++) {
for (i = 2; i <= sqrt(m); i++) { //squared root
if (m % i == 0) {
break;
}
}
if (i > sqrt(m)) {
printf("%6d", m);
cnt++;
if (cnt % 10 == 0) {
putchar(10); //printf("\n")
}
}
}
putchar('\n');
system("pause");
return 0;
}
代码分析:
埃式筛选法-素数表
#include
#include
int main() {
int i, k;
double sum = 0, ans;
for (i = 1; i <= 100; i++) {
ans = 1;
for (k = 1; k <= i; k++) {
ans *= k;
}
sum += ans;
}
printf("%e\n", sum);
system("pause");
return 0;
}
运用函数封装
#include
#include
double fact(int n);
int main() {
int i;
double sum = 0;
for (i = 1; i <= 100; i++) {
sum += fact(i); //factorial n!
}
printf("%e\n", sum);
system("pause");
return 0;
}
double fact(int n) {
int i;
double ans = 1;
for (i = 2; i <= n; i++) {
ans *= i;
}
return ans;
}
代码分析:
作业:统计学生成绩,按等第求出分布人数
#include
#include
#define LEN 50
int main() {
int N = 0;
int A_cnt = 0, B_cnt = 0, C_cnt = 0, D_cnt = 0, F_cnt = 0;
printf("input students number:\n");
scanf("%d", &N);
getchar();
int N_arr[N]; //must define here
printf("input their scores:\n");
for (int i = 0; i < N; i++) {
scanf("%d", &N_arr[i]); //use space is ok
}
for (int i = 0; i < N; i++) {
if (N_arr[i] >= 90) { //switch?
A_cnt++;
}
else if (N_arr[i] >= 80) {
B_cnt++;
}
else if (N_arr[i] >= 70) {
C_cnt++;
}
else if (N_arr[i] >= 60) {
D_cnt++;
}
else {
F_cnt++;
}
}
printf("students numbers distribution: \nA >=90> B >=80> C >=70> D >=60> F\n");
printf("%d\t%d\t%d\t%d\t%d\n", A_cnt, B_cnt, C_cnt, D_cnt, F_cnt);
system("pause");
return 0;
}
代码分析:
要求:输入三点坐标判断三角形是否成立,并计算三角形的周长和面积
#include
#include
#include
#define LEN 4
int main() {
double Lenth = 0, Area = 0;
int xy[3][2] = {0}; //memset string.h||memory.h if define int xy[][2], devcpp will make bug but is right
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
scanf("%d", &xy[i][j]);
}
}
while (getchar() != '\n'){;}
/*for (int i = 0; i < 3; i++) { //better printf test like printf("%d", xy[i][:])?
for (int j = 0; j < 2; j++) {
printf("%d ", xy[i][j]);
}
}*/
double side[LEN] = {0,
sqrt(pow((xy[0][0] - xy[1][0]), 2) + pow((xy[0][1] - xy[1][1]), 2)),
sqrt(pow((xy[0][0] - xy[2][0]), 2) + pow((xy[0][1] - xy[2][1]), 2)),
sqrt(pow((xy[1][0] - xy[2][0]), 2) + pow((xy[1][1] - xy[2][1]), 2))};
int min = 0;
for (int i = 1; i <= (LEN - 1) - 1; i++) { //basic select sort small->big
min = i;
for (int j = i + 1; j <= (LEN -1); j++) {
if (side[min] > side[j]) { //min = i||j' is the minposition
min = j;
}
}
if (min != i) {
side[0] = side[min]; //min = j is really minnumber
side[min] = side[i];
side[i] = side[0];
}
}
if (side[3] < side[1] + side[2]) { //triangle exist if unkown longest side,we need six conditions 'fabs',shortest>0
for (int i = 1; i <= 3; i++) {
Lenth += side[i];
}
Area = sqrt(0.5 * Lenth * (0.5 * Lenth - side[1]) * (0.5 * Lenth - side[2]) * (0.5 * Lenth - side[3])); //Heron's formular
printf("L = %.2f, A = %.2f\n", Lenth, Area);
}
else {
printf("Impossible\n");
}
system("pause");
return 0;
}
代码分析:选择法排序
补充作业:几何图形相关计算与打印
打印菱形钻石图案
#include
#include
int main() {
int n, a, b; //n是总行数,a是当前行,b是列
printf("please input n(奇数/偶数):\n");
scanf("%d", &n);
getchar();
if (n % 2 != 0) {
for(a = 1; a <= (n + 1) / 2; a++) {
for(b = 1; b <= (n + 1) / 2 - a; b++) { //公式均是由以中间行为x轴,左边第一个为原点建直角坐标系找函数关系得到的
printf(" ");
}
for(b = b; b <= (n - 1) / 2 + a; b++) {
printf("*");
}
printf("\n");
}
for(a = a; a <= n; a++) {
for(b = 1; b <= a - (n + 1) / 2; b++) {
printf(" ");
}
for(b = b; b <= (n - 1) /2 + (n + 1 - a); b++) {
printf("*");
}
printf("\n");
}
}
else {
for (a = 1; a <= n; a ++) {
if (a <= n / 2) {
for (b = 1; b <= n / 2 - a; b++) {
printf(" ");
}
for (b = b; b <= n / 2 - 1 + a; b++) {
printf("*");
}
printf("\n");
}
else {
for (b = 1; b <= a - n / 2 - 1; b++) {
printf(" ");
}
for (b = b; b <= 3 * n / 2 - a; b++) {
printf("*");
}
printf("\n");
}
}
}
system("pause");
return 0;
}
#include
#include
int main() { //Fibonacci
int n1 = 1, n2 = 1, next, n;
printf("input need fibonacci items number:");
scanf("%d", &n);
getchar();
printf("%6d%6d", n1, n2);
for (int i = 1; i <= n - 2; i++) {
next = n1 + n2;
printf("%6d", next);
n1 = n2;
n2 = next;
}
printf("\n");
system("pause");
return 0;
}
格雷戈里公式求圆周率
#include
#include
#include
int main() { //Gregory pi/4 = 1 - 1/3 + 1/5 - 1/7 +...
double sum = 0, item = 1;
int sign = 1, deno = 1;
while (fabs(item) >= 1e-4) { //float absolute abs~common int absolute 0.0001=1e-4
item = sign * 1.0 / deno;
sum = sum + item;
sign = (-1) * sign;
deno = deno + 2;
}
printf("pi = %.4f\n", sum * 4);
system("pause");
return 0;
}
计算圆周率公式二:pi/2 = 2/1 * 2/3 * 4/3 * 4/5 * 6/5 * 6/7…
#include
#include
int main() { //pi/2 = 2/1 * 2/3 * 4/3 * 4/5 * 6/5 * 6/7....
double product = 1, deno = 1;
int upn = 2; //upnumber
while (deno < 10000) {
product *= (upn / deno) * (upn / (deno + 2));
upn += 2;
deno += 2;
}
printf("pi = %.4f\n", product * 2);
system("pause");
return 0;
}
使用了观察分子分母法,也可以通过累乘法求解
后续更新中……