C语言中级demo

导语

这是C语言中级demo,它的难度会依次递增,但也不会用到复杂的算法。想对C语言语法更深入学习的朋友可以阅读,这次demo有一些经典的例子,比如:递归实现汉诺塔贪吃蛇小游戏指针的运用文件的运用(本来有数据库的demo的,但是一些原因,数据库没了),这些例子有一定难度,但不要怕,建议先自己思考,再看我的解法。总的来说,这次的demo的覆盖十分全面。需要源码的同学,我也在结语中给出了下载地址。

测试平台:Visual Studio 2017。(随着它版本更新,会出现有些库找不到的情况,可以自行百度解决

序章

首先简单说明以下,所有的demo分布在不同的文件中,最后是用一个字符界面的菜单通过输入数字来选择想使用的demo,同时有些demo使用到了外部库文件,这对于新手来说调试起来比较麻烦,但是可以当作一个挑战尝试正确运行出demo。具体的结构如下:
一级菜单示意图
二级菜单示意图
演示进入一次菜单:
演示进入一次菜单
演示进入二级菜单:
演示进入二级菜单

实战一:程序流程

本实战主要练习C语言的基本语法、变量使用等基础知识。有基础的可以跳过此实战。
导航菜单设计:

int Practice1DisplayMenu()
{
	system("cls");
	int key;
	printf("******************实战1功能菜单****************\n");
	printf("*****        1. 项目1->三角形相关判断     *****\n");
	printf("*****        2. 项目2->简单四则运算       *****\n");
	printf("*****        3. 项目3->猴子吃桃           *****\n");
	printf("*****        4. 项目4->其他拓展项目       *****\n");
	printf("*****        5.  返回上一级菜单           *****\n");
	printf("请输入功能号:");
	scanf("%d", &key);
	return key;
}

练习一:输入三个实数,判能否构成三角形

要求:

  1. 判断是否是三角形
  2. 判断是否是等腰三角形
  3. 判断断是否是等边三角形
  4. 计算三角形的面积
    实现:
#include "stdio.h"
#include "math.h"
#include "stdlib.h"
#include "conio.h"

int TriangleJudgmentDisplayMnue();

void practice1project1()
{
	    float a, b, c;
		printf("请输入三条边(以空格隔开):");
		scanf("%f%f%f", &a, &b, &c);
		if ((a + b) < c || (a + c) < b || (b + c) < a)
		{
			printf("不能构成三角形,,按任意键继续...\n");
			getch();
		}
	    else
		{
			printf("能构成三角形\n");
			//让c最大
			float temp;
			if (a>b)//找到a b中最大的
			{
				temp = b;
				b = a;
				a = temp;
			}
			if (b > c)//再找到b c中最大的
			{
				temp = c;
				c = b;
				b = temp;
			}
			int key;
			for (;;)
			{
				key = TriangleJudgmentDisplayMnue();
				switch (key)
				{
				case 1:
					if ((a*a + b * b) == c * c)
						printf("直角三角形,按任意键继续...\n");
					else
						printf("不是直角三角形,按任意键继续...\n");
					getch();
					break;
				case 2:
					if (a == b)
						printf("等腰三角形,按任意键继续...\n");
					else
						printf("不是等腰三角形,按任意键继续...\n");
					getch();
					break;
				case 3:
					if (a == b && a == c && b == c)
						printf("等边三角形,按任意键继续...\n");
					else
						printf("不是等边三角形,按任意键继续...\n");
					getch();
					break;
				case 4:
					temp = (a + b + c) / 2;
					printf("面积为:%f,按任意键继续...", sqrt(temp*(temp - a)*(temp - b)*(temp - c)));
					getch();
					break;
				case 5:
					key = 0;
					break;
				default:
					printf("输入错误!请按任意键继续.....");
					getch();
					break;
				}
				if (key == 0)
					break;
			}
		}
}
int TriangleJudgmentDisplayMnue()
{
	system("cls");
	int key;
	printf("******************实战1->项目1*****************\n");
	printf("*****        1. 判断是否是直角三角形      *****\n");
	printf("*****        2. 判断是否是等腰三角形      *****\n");
	printf("*****        3. 判断是否是等边三角形      *****\n");
	printf("*****        4. 计算三角形的面积          *****\n");
	printf("*****        5.  返回上一级菜单           *****\n");
	printf("请输入功能号:");
	scanf("%d", &key);
	return key;
}

练习二:简单四则运算

要求:

  1. 用程序实现一个简单的四则运算的功能,要求驶入类似a+b然后回车输出a+c=c的形式,a,b,c都是整数。
    实现:
#include "stdio.h"
#include "conio.h"
#include "stdlib.h"
#include "math.h"

void practice1project2()
{
	float a, b;
	char mm, y;
	printf("--------简单计算器-----------\n");
	do
	{
		setbuf(stdin, NULL);//使stdin输入流由默认缓冲区转为无缓冲区  
		printf("是否进行高级运算(y/n)");
		char x = getchar();
		if (x == 'n')
		{
			printf("请输入两个操作数和运算符:");
			scanf("%f%c%f", &a, &mm, &b);
			switch (mm)
			{
			case '+':
				printf("%f+%f=%.2f\n", a, b, a + b);
				break;
			case '-':
				printf("%f-%f=%.2f\n", a, b, a - b);
				break;
			case '*':
				printf("%f*%f=%.2f\n", a, b, a*b);
				break;
			case '/':
				if (b == 0)
				{
					printf("被除数不能为零\n");
					break;
				}
				printf("%f/%f=%.2f\n", a, b, a / b);
				break;
			default:
				printf("输入有错");
			}
			getchar();
			printf("按“y”继续,按其他键结束");
			scanf("%c", &y);
		}
		else
		{
			setbuf(stdin, NULL);//使stdin输入流由默认缓冲区转为无缓冲区
			printf("请选择你要进行的运算:");
			printf("开平方根按:s ;求倒:d ;幂次方:f ;");
			char xx = getchar();

			switch (xx)
			{
			case 's':
				printf("请输入被开方数:");
				scanf("答案为:%f", &a);
				b = sqrt(a);
				printf("%.4f", b);
				break;
			case 'd':
				printf("请输入要求倒的数:");
				scanf("答案为:%f", &a);
				if (0 == a)
				{
					printf("输入错误!");
					break;
				}
				b = 1 / a;
				printf("%.4f", b);
				break;
			case 'f':
				printf("请输入底和幂:");
				scanf("%f%f", &a, &b);
				printf("答案为:%.4f", pow(a, b));
				break;
			default:
				printf("输入错误!");
			}
			setbuf(stdin, NULL);//使stdin输入流由默认缓冲区转为无缓冲区  
			printf("按“y”继续,按其他键结束");
			y = getch();
			//setbuf(stdin, NULL);//使stdin输入流由默认缓冲区转为无缓冲区  
		}
	} while (y == 'y');
}

练习三:猴子吃桃问题

要求:

  1. 有一只猴子第一天摘下了若干个桃子,当即吃掉了一半,觉得不过瘾又多吃了一个;第二天又将剩下的桃子吃了一半,还不过瘾又多吃了一个;按照这个吃法每天都会吃掉前一天剩下的一半多一个。到了第10天,就剩下一个桃子了。问:这只猴子第一天摘了多少个桃子?

实现:

#include "stdio.h"
#include "conio.h"
#include "stdlib.h"
#include "math.h"


//猴子吃桃
void practice1project3()
{
	int mun=1;
	int day;
	printf("请输入第几天剩下一个桃子:");
	scanf("%d", &day);
	day--;
	for (; day > 0; day--)
	{
		mun = (mun + 1) * 2;
		printf("第%d天剩下%d个桃子\n", day, mun);
	}
	getch();
}

练习四:猴子吃桃拓展

要求

  1. 如果改变游戏玩法:猴子第一天摘了   x \ x  x个桃子,当即吃掉了些桃子,剩下 x \sqrt{x} x 个桃子还不过瘾,又多吃了一个,剩下   y \ y  y个;第二天又吃掉了一些,剩下 y \sqrt{y} y 个桃子,又多吃一个;按照这吃法,到了第十天只剩下了一个桃子。问:猴子第一天摘下了几个桃子?

实现:

#include "stdio.h"
#include "conio.h"
#include "stdlib.h"
#include "math.h"

int mc(long n, long i)
{
	if (n == i)
		return 1;
	else
		return (mc(n + 1, i) + 1)*(mc(n + 1, i) + 1);
}

void practice1project4()
{
	int i;
	printf("请输入吃完的时间:");
	scanf("%ld", &i);
	printf("猴子摘了%d个", mc(0, i));
	getch();
}

实战二:递归及应用

本实战主要让大家了解递归的思想刚开始可能会比较难,但是多练习就可以更加深入的理解。
这里给大家推荐一个我当时理解递归用到的视频。点这里(如果链接失效,请百度关键字:C程序设计进阶 北京大学)

导航菜单设计:

#include "stdio.h"
#include "stdlib.h"
#include "conio.h"

#include "practice2project1.h"
#include "practice2project2.h"
#include "practice2project3.h"
int Practice2DisplayMenu();
void practice2()
{
	int key;
	for (;;)
	{
		key = Practice2DisplayMenu();//打开实战1的额功能菜单
		switch (key)
		{
		case 1:
			practice2project1();
			break;
		case 2:
			practice2project2();
			break;
		case 3:
			practice2project3();
			break;
		case 4:
			key = 0;
			break;		
		default:
			printf("输入错误!请按任意键继续.....");
			getch();
			break;
		}
		if (key == 0)
			break;
	}

}
int Practice2DisplayMenu()
{
	system("cls");
	int key;
	printf("******************实战2功能菜单****************\n");
	printf("*****        1. 项目1->猴子吃桃问题       *****\n");
	printf("*****        2. 项目2->汉诺塔问题         *****\n");
	printf("*****        3. 项目3->拓展项目猴子吃桃   *****\n");
	printf("*****        4.  返回上一级菜单           *****\n");
	printf("请输入功能号:");
	scanf("%d", &key);
	return key;
}

练习一:递归猴子吃桃问题

要求

  1. 有一只猴子第一天摘下了若干个桃子,当即吃掉了一半,觉得不过瘾又多吃了一个;第二天又将剩下的桃子吃了一半,还不过瘾又多吃了一个;按照这个吃法每天都会吃掉前一天剩下的一半多一个。到了第10天,就剩下一个桃子了。问:这只猴子第一天摘了多少个桃子?(用递归编程思想实现)

实现:

#include "stdio.h"
#include "math.h"
#include "stdlib.h"
#include "conio.h"

int moeat(int n, int k)
{
	int sum;
	if (n == k)
		sum = 1;
	else
		sum = 2 * (moeat(n + 1, k) + 1);
	return sum;
}


int moeat2(int n, int k)
{
	if (n == k)
		return 1;
	else
		return (moeat2(n + 1, k) + 1)*(moeat2(n + 1, k) + 1);
}

void practice2project1()
{
	//猴子吃桃问题
	int k = 10, sum = 0;
	printf("请输入猴子吃桃的天数k=");
	scanf("%d", &k);
	sum = moeat(1, k);
	printf("猴子第一天摘桃子为=%d", sum);
	getch();
}

练习二:汉诺塔问题

tips:第一次看不懂没关系,代码记下来,回过头再看。
要求:

  1. 普通版:古代有个梵塔,塔内有A,B,C共三座,座A上有64个大小不等的盘子,大的在下面,小的在上面,有一个和尚想把这64个盘子从座A移动到座C,在移动过程中可以借用座A,座B,座C,但每次移动只允许移动一个盘子,并且不允许大盘放在小盘的上面。问:每一步改如何移动?总共要移动多少不?
  2. 加强版:如果改变游戏的玩法:不允许直接从最左(右)移动到最右(左),即每次移动一定是移动到中间或者从中间移除,也不允许大盘放到小盘上面。问题与普通版相同。

实现:

#include "stdio.h"
#include "math.h"
#include "stdlib.h"
#include "conio.h"

int n = 0;
//汉诺塔问题
void hanoi(int mun, char a, char b, char c)
{
	if (mun == 1)
		printf("step %3d:%c-->%c\n", ++n, a, c);
	else
	{
		hanoi(mun - 1, a, c, b);
		printf("Step %3d: %c--> %c\n", ++n, a, c);
		hanoi(mun - 1, b, a, c);
	}
}
void hanoi2(int m, char a, char b, char c)
{
	if (m == 1)
	{
		if (abs(a - c) == 1)
		{
			n++;
			printf("step %-3d:%c-->%c\n", n, a, c);
		}
		if ((abs(a - c) == 2))
		{
			n++;
			printf("step %-3d:%c-->%c\n", n, a, b);
			n++;
			printf("Step %-3d:%c-->%c\n", n, b, c);
		}
	}
	else
	{
		hanoi2(m - 1, a, b, c);
		hanoi2(1, a, c, b);
		hanoi2(m - 1, c, b, a);
		hanoi2(1, b, a, c);
		hanoi2(m - 1, a, b, c);
	}
}
void practice2project2()
{
	n = 0;
	printf("请输入盘子数:");
	int mun;
	scanf("%d", &mun);
	printf("请选择要解决那种汉诺塔问题?\n");
	printf("1.普通汉诺塔\n");
	printf("2.加强汉诺塔(每次只能移动到相邻的柱上)");
	int key;
	scanf("%d", &key);
	if (key == 1)
		hanoi(mun, 'A', 'B', 'C');
	else if (key == 2)
		hanoi2(mun, 'A', 'B', 'C');
	else
		printf("输入错误!");
	printf("请按任意键继续...");
	getch();
}

实战三:项目组织

将所有的这demo组织成一个菜单。

实战四:数组及应用

本实战主要练习语言的数组使用。有:约瑟夫环、字符串处理等。

导航菜单设计:

#include "stdio.h"
#include "stdlib.h"
#include "conio.h"

#include "practice4project1.h"
#include "practice4project2.h"
#include "practice4project3.h"
#include "practice4project4.h"
int Practice4DisplayMenu();
void practice4()
{
	int key;
	for (;;)
	{
		key = Practice4DisplayMenu();//打开实战4的额功能菜单
		switch (key)
		{
		case 1:
			practice4project1();
			break;
		case 2:
			practice4project2();
			break;
		case 3:
			practice4project3();
			break;
		case 4:
			practice4project4();
			getch();
			break;
		case 5:
			key = 0;
			break;
		default:
			printf("输入错误!请按任意键继续.....");
			getch();
			break;
		}
		if (key == 0)
			break;
	}

}
int Practice4DisplayMenu()
{
	system("cls");
	int key;
	printf("******************实战4功能菜单****************\n");
	printf("*****        1. 项目1->约瑟夫问题         *****\n");
	printf("*****        2. 项目2->字符串排序问题     *****\n");
	printf("*****        3. 项目3->字符串分类统计     *****\n");
	printf("*****        4. 项目4->拓展项目           *****\n");
	printf("*****        5.  返回上一级菜单           *****\n");
	printf("请输入功能号:");
	scanf("%d", &key);
	return key;
}

练习一:约瑟夫问题(数组)

(这个问题的来源很有趣,这里就不谈故事了,直接上题)
问题:N个人围成一圈,从第一个人开始报数,数到第k个人时那个人出队;下一个人再从1开始报数,依次循环,直到最后一个人。
实现:

#include "stdio.h"
#include "stdlib.h"
#include "conio.h"
#include "string.h"
#define N 5
#define LEN 10
 struct List
{
	char name[10];
	struct List *next;
};
 struct List2
 {
	 int num;
	 struct List2 *next;
 };

void JosephProblem1(char ary[][LEN], int);
void JosephProblem2();
void JosephProblem3();
int Practice4project1DisplayMenu();

void practice4project1()
{
	int key;
	for (;;)
	{
		system("cls");
		key = Practice4project1DisplayMenu();
		switch (key)
		{
		case 1:
			char name[N][LEN];
			int i, k;//k表示数到第K个人是即出队
			printf("请依次输入%d个人名(每个人名不超过10个字):\n", N);
			for (i = 0; i < N; i++)
				scanf("%s", &name[i]);
			printf("\n请输入数到第几个人退出:");
			scanf("%d", &k);
			JosephProblem1(name, k);
			getch();
			break;
		case 2:
			JosephProblem2();
			getch();
			break;
		case 3:
			JosephProblem3();
			getch();
			break;
		case 4:
			break;
		default:
			printf("输入错误!");
			break;
		}
		if (key == 4)
			break;
	}
}
int Practice4project1DisplayMenu()
{
	system("cls");
	int key;
	printf("******************实战4项目1功能菜单***********\n");
	printf("*****        1. 功能1->普通约瑟夫问题     *****\n");
	printf("*****        2. 功能2->链表约瑟夫问题     *****\n");
	printf("*****        3. 功能3->约瑟夫“密码问题” *****\n");
	printf("*****        4.  返回上一级菜单           *****\n");
	printf("请输入功能号:");
	scanf("%d", &key);
	return key;
}
void JosephProblem1(char ary[][LEN], int k)
{
	//普通约瑟夫
	int out = 0;//第几个人出局
	int couter = 0;//数到conter==n时退出
	int idx = -1;
	while (out < N)
	{
		idx++;
		if (idx == N)
			idx = 0;
		if (strcmp(ary[idx], "\0") == 0)
			continue;
		else
		{
			couter++;
			if (couter == k)
			{
				out++;
				printf("第个%d人退出:%s\n", out, ary[idx]);
				strcpy(ary[idx], "\0");
				couter = 0;
			}
		}
	}
}
void JosephProblem2()
{
		char k;
		int num = 0;
		struct List *p = NULL;
		struct List *q = NULL;
		struct List *head = NULL;
		do
		{
			if (head == NULL)
			{
				num++;
				head = (struct List*)malloc(sizeof(struct List));//初始化链表				
				printf("请输入人名:");
				fflush(stdin);
				scanf("%s", head->name);
				head->next = NULL;
				q = head;
			}
			else
			{
				num++;
				p= (struct List*)malloc(sizeof(struct List));
				p->next = NULL;
				q->next= p;//上一个节点连接到这个节点				
				printf("\n请输入人名:");
				fflush(stdin);
				scanf("%s", p->name);
				q = p;
			}
			printf("添加成功,现在有%d个人。按y/Y继续添加,按其他键完成:",num);
			k = getch();
		} while (k=='y'||k=='Y');
		q->next = head;
		struct List *star;
		star = head;
		int key = 0;
		printf("\n游戏开始:\n");
		while (num!=0)
		{
			if (star->name != "\0")
			{
				key++;
				if (key == 3)
				{
					num--;
					printf("\n%s被杀死了", star->name);
					strcpy(star->name, "\0");
					key = 0;
				}
				star = star->next;
			}
			else
				star = star->next;				
		}
}

void JosephProblem3()
{
	char k;
	int num = 0;
	struct List2 *p = NULL;
	struct List2 *q = NULL;
	struct List2 *head = NULL;
	do
	{
		if (head == NULL)
		{
			num++;
			head = (struct List2*)malloc(sizeof(struct List2));//初始化链表				
			printf("请输入数字:");
			fflush(stdin);
			scanf("%d", &head->num);
			head->next = NULL;
			q = head;
		}
		else
		{
			num++;
			p = (struct List2*)malloc(sizeof(struct List2));
			p->next = NULL;
			q->next = p;//上一个节点连接到这个节点				
			printf("\n请输入数字:");
			fflush(stdin);
			scanf("%d", &p->num);
			q = p;
		}
		printf("添加成功,现在有%d个数字。按y/Y继续添加,按其他键完成:", num);
		k = getch();
	} while (k == 'y' || k == 'Y');

	q->next = head;//循环链表
	struct List2 *star;
	star = head;
	int key = 0;
	int target = star->num;


	printf("\n密码是:\n");
	while (num != 0)
	{
		if (star->num !=-1)
		{
			key++;
			if (key == target)
			{
				num--;
				printf("%d  ", star->num);
				target = star->num;
				key = 0;
				star->num = -1;
				
			}
			star = star->next;
		}
		else
			star = star->next;
	}
}

练习二:字符串排序问题

要求:

  1. 任意输入N个单词,对这些单词进行排序

实现:

#include "stdio.h"
#include "stdlib.h"
#include "conio.h"
#include "string"

#define N 50 //单词数上限
#define M 26 //单词长度上限

int Practice4project2DisplayMenu();
void print(const char word[][M], int);
void stringsort1(char word[][M], int n);
void stringsort2(char word[][M], int n);
void stringsort3(char word[][M], int n);
void practice4project2()
{
	int key;
	for (;;)
	{
		system("cls");
		key = Practice4project2DisplayMenu();
		     
		char word[N][M];
		int m = M - 1;
		int count = N;
		int n = 0, i;
		switch (key)
		{
		case 1:
			//控制输入的单词数在1-50之间
			while (n < 1 || n>50)
			{
				printf("请输入你将要输入的单词数:(1-%d)\n", count);
				scanf("%d", &n);
			}
			printf("请输入%d个单词,以空格分开\n(单词长度不超过%d,若超出,程序会自动忽略超出部分)\n", n, m);
			for (i = 0; i < n; i++)
			{
				scanf("%s", &word[i]);
				word[i][M - 1] = '\0';
			}
			stringsort1(word, n);
			printf("排序结果为:\n");
			print(word, n);
			getch();
			break;
		case 2:
			//控制输入的单词数在1-50之间
			while (n < 1 || n>50)
			{
				printf("请输入你将要输入的单词数:(1-%d)\n", count);
				scanf("%d", &n);
			}
			printf("请输入%d个单词,以空格分开\n(单词长度不超过%d,若超出,程序会自动忽略超出部分)\n", n, m);
			for (i = 0; i < n; i++)
			{
				scanf("%s", &word[i]);
				word[i][M - 1] = '\0';
			}
			stringsort2(word, n);
			stringsort1(word, n);
			printf("排序结果为:\n");
			print(word, n);
			getch();
			break;
		case 3:
			//控制输入的单词数在1-50之间
			while (n < 1 || n>50)
			{
				printf("请输入你将要输入的单词数:(1-%d)\n", count);
				scanf("%d", &n);
			}
			printf("请输入%d个单词,以空格分开\n(单词长度不超过%d,若超出,程序会自动忽略超出部分)\n", n, m);
			for (i = 0; i < n; i++)
			{
				scanf("%s", &word[i]);
				word[i][M - 1] = '\0';
			}
			stringsort3(word, n);
			printf("排序结果为:\n");
			print(word, n);
			getch();
			break;
		case 4:
			;
		default:
			printf("输入错误!");
			break;

		}
		if (key == 4)
			break;
	}
}

int Practice4project2DisplayMenu()
{
	system("cls");
	int key;
	printf("******************实战4项目2功能菜单*************\n");
	printf("*****        1. 功能1->字符串排序问题       *****\n");
	printf("*****        2. 功能2->大小写不敏感字符排序 *****\n");
	printf("*****        3. 功能3->单词进行排序(非插入) *****\n");
	printf("*****        4.  返回上一级菜单             *****\n");
	printf("请输入功能号:");
	scanf("%d", &key);
	return key;
}

void stringsort1(char word[][M], int n)
{
	char key[M];
	int i, j;
	for (i = 1; i < n; i++)
	{
		strcpy(key, word[i]);
		j = i;
		while (j >= 1 && 1 == strcmp(word[j - 1], key))
		{
			strcpy(word[j], word[j - 1]);
			j--;
		}
		strcpy(word[j], key);
	}
}

void stringsort2(char word[][M],int n)
{
	char key[M];
	//大写换成小写
	for (int i = 0; i < n; i++) 
	{
		strcpy(key, word[i]);	
			for (int k = 0; word[i][k] != '\0'; k++)
				if (word[i][k] >= 'A'&&word[i][k] <= 'Z')
			                word[i][k] += 32;
	}
	int len;
	for (int i=0; i < n; i++)
	{
		len = strlen(word[i]);
		if (!(word[i][len - 1] >= 'a'&&word[i][len - 1] <= 'z'))
			word[i][len - 1] = '\0';
	}
}

void stringsort3(char word[][M], int n)
{
	char key[M];
	int i, j,c;
	for (i = 0; i < n - 1; i++)
	{
		strcpy(key, word[i]);
		for(j=i;j<n;j++)
			if (strcmp(key, word[j])>0)//key 大
			{
				c = j;
				strcpy(key, word[j]);
			}
		strcpy(word[c], word[i]);
		strcpy(word[i], key);
		
	}
}
void print(const char word[][M], int n)
{
	int i;
	for (i = 0; i < n; i++)
		printf("%s\n", word[i]);	
}

练习三:字符串分类统计

要求:

  1. 输入一字符串,统计其中的大写字母、小写字母、数字、空格和其他字符各多少个。

实现:

#include "stdio.h"
#include "stdlib.h"
#include "conio.h"
#include "string.h"

#define LEN 100
int lc = 0,uc = 0,d = 0, s = 0, o = 0;
void count(char ary[]);
//字符串统计
void practice4project3()
{
	char ary[LEN + 1];
	printf("请输入100个以内的任意字符\n");
	printf("程序将按大小写字母、数字、空格和其他字符进行统计。\n");
	printf("如果超出100个字符,程序将只对前100个字符进行统计:\n");
	char ch;
	while ((ch = getchar()) != EOF && ch != '\n')
	{
		;
	}
	gets_s(ary);
	puts(ary);
	count(ary);
	printf("小写字母:%d\n", lc);
	printf("大写字母:%d\n", uc);
	printf("0-9数字:%d\n", d);
	printf("空格:%d\n", s);
	printf("其他字符:%d\n", o);
	printf("按任意键退出...");
	getchar();

}
void count(char ary[])
{
	int i = 0;
	char c;
	while (ary[i])
	{
		c = ary[i];
		if (c >= '0'&& c <= '9')
			d++;
		else if (c >= 'a' && c <= 'z')
			lc++;
		else if (c >= 'A' &&c <= 'Z')
			uc++;
		else if (c == ' ')
			s++;
		else
			o++;
		i++;
	}
}

实战五:结构体及应用

本实战,你将学会如何使用结构体,构建复杂的数据类型。
(以后就不在添上导航菜单的代码,具体的可以在我的github上下载完成demo集合)

练习一:学生信息登记管理(数组结构体)

要求:
有学生成绩登记表如图:

学号姓名年龄年龄C语言英语高数平均成绩
201210409601刘子栋1992858687.7
201210409602童雨嘉1988728280.7
201210409603杨欣悦1978937481.7
201210409604王子豪1967777573
························

其中:学号是长度12的数字字符组成:姓名最大长度为10字符:性别最多允许4个字符:年龄为整数:成绩包含(C语言、英语、高数),均为整数,平均分允许一位小数。

  1. 现某班有N名学生(程序运行时N为确定的值)。
  2. 用户分别输入N个学生的信息。
  3. “平均成绩”项应该通过计算获得,不从键盘输入。
  4. 输入完成后,给出操作菜单让用户选择操作,菜单如下:
请选择排序字段
--------------------------------------------------------------
1.学号		2.姓名		3.性别		4.年龄
5.C语言		6.英语		7.高数		8.平均分
9.显示全部信息		0.退出程序
--------------------------------------------------------------
  1. 当用户正确选择排序字段后,进一步请用户选择排序方向,如下:
请选择排序方向:
--------------------------------------------------------------
1.升序		2.降序		0.退出程序
--------------------------------------------------------------
  1. 排序操作可以反复进行直到用户选择“退出程序”

实现:

#include "stdio.h"
#include "stdlib.h"
#include "conio.h"
#include "string.h"

#define N 3

typedef struct Subject
{
	float C_langeuage;
	float Engelish;
	float Math;

};

typedef struct Student
{
	int id;
	char name[10];
	char sex[4];
	int age;
	Subject subject;
	float averagescore;

};

int DisplayMenu(int n);
void InputStudent(Student stu[], Student stucpy[]);
void SortStudnet(Student stu[], Student stucpy[],int k ,int n);//k是按什么排序,n=1升序,n=0降序
void OutputStudent(Student stu[]);
void copy(Student *stu, Student *stucpy,int c,int num);
//子入口
void practice5project1()
{
	Student stu[N],stucpy[N];
	InputStudent(stu, stucpy);
	int key;
	int key2;
	while (true)
	{
		key = DisplayMenu(1);//那种排序
		if(key!=0&&key!=9)
		   key2 = DisplayMenu(2);//怎么排序
		switch (key)
		{
		case 1://学号
			Student temp;
			SortStudnet(stu, stucpy, key, key2);
			getch();
			break;
		case 2://姓名
			SortStudnet(stu, stucpy, key, key2);
			getch();
			break;
		case 3://性别
			SortStudnet(stu, stucpy, key, key2);
			getch();
			break;
		case 4://年龄
			SortStudnet(stu, stucpy, key, key2);
			getch();
			break;
		case 5://C语言
			SortStudnet(stu, stucpy, key, key2);
			getch();
			break;
		case 6://英语
			SortStudnet(stu, stucpy, key, key2);
			getch();
			break;
		case 7://高数
			SortStudnet(stu, stucpy, key, key2);
			getch();
			break;
		case 8://平均分
			break;
		case 9:
			OutputStudent(stu);
		case 0:
			break;
		default:
				printf("输入错误!");
		}
		if (key == 0)
			break;
	}
}

//显示菜单
int DisplayMenu(int n)
{
	system("cls");
	switch (n)
	{
	case 1:
		printf("-----------------------------------------------------------------\n");
		printf("请选择排序字段:\n");
		printf("1.学号             2.姓名                3.性别              4年龄\n");
		printf("5.C语言            6.英语                7.高数              8.平均分\n");
		printf("9.显示全部原始信息                       0.退出程序\n");
		printf("-----------------------------------------------------------------\n");
		break;
	case 2:
		printf("-----------------------------------------------------------------\n");
		printf("1.升序                   2.降序                     0.退出程序   \n");
		printf("-----------------------------------------------------------------\n");
		break;
	default:
		printf("输入错误!\n");
		break;
	}
	int k;
	scanf("%d", &k);
	return k;
}
//输入学生的信息
void InputStudent(Student stu[], Student stucpy[]){
	for (int i = 0; i < N; i++)
	{
		printf("请输入第%d/%d个学生信息:\n",i+1,N);
		printf("------------------------------------------------------------\n");
		printf("学号:");
		scanf("%d", &stu[i].id);
		printf("姓名(10个字符内):");
		scanf("%s", &stu[i].name);
		printf("性别(四个字符内):");
		scanf("%s",&stu[i].sex);
		printf("年龄(整数):");
		scanf("%d", &stu[i].age);
		printf("《C语言》成绩(整数):");
		scanf("%f", &stu[i].subject.C_langeuage);
		printf("《英语》成绩(整数):");
		scanf("%f", &stu[i].subject.Engelish);
		printf("《高数》成绩(整数):");
		scanf("%f", &stu[i].subject.Math);
		printf("------------------------------------------------------------\n");
		stu[i].averagescore = (stu[i].subject.C_langeuage + stu[i].subject.Engelish + stu[i].subject.Math) / 2;
	}
	stucpy = stu;
}
//输出学生的信息
void OutputStudent(Student stu[])
{
	printf("====================================================================================\n");
	printf("学生全部信息:\n");
	printf("学号      姓名    性别       年龄       C语言     英语      数学      平均分\n");
	for (int i = 0; i < N; i++)
	{
		printf("%-10d", stu[i].id);
		printf("%-10s", stu[i].name);
		printf("%-10s",stu[i].sex);
		printf("%-10d", stu[i].age);
		printf("%-10.2f", stu[i].subject.C_langeuage);
		printf("%-10.2f", stu[i].subject.Engelish);
		printf("%-10.2f", stu[i].subject.Math);
		printf("%-10.2f", stu[i].averagescore);
		putchar('\n');
	}
	getch();
}
//两个结构体复制
void copy(Student *stu, Student *stucpy,int c,int num)
{
	/*int id;
	char name[10];
	char sex[4];
	int age;
	Subject subject;
	float averagescore;*/

	stucpy[c].id = stucpy[num].id;
	stucpy[c].age = stu[num].age;
	stucpy[c].averagescore = stu[num].averagescore;
	
	stucpy[c].subject.C_langeuage = stu[num].subject.C_langeuage;
	stucpy[c].subject.Engelish = stu[num].subject.Engelish;
	stucpy[c].subject.Math = stu[num].subject.Math;
	
	strcpy(stucpy[c].name, stu[num].name);
	strcpy(stucpy[c].sex, stu[num].sex);

}
//根据选择排序
void SortStudnet(Student stu[], Student stucpy[],int k,int n)
{
	//注意排序方式n==1是升序,==0是降序
	Student temp;
	switch (k)
	{
	case 1://学号
	{
		//冒泡排序
		if (n == 1)
		{
			for (int i = 0; i<N; i++)
				for (int j = 0; j < N - 1 - i; j++)
					if (stu[j].id > stu[j + 1].id)
					{
						temp = stu[j];
						stu[j] = stu[j + 1];
						stu[j + 1] = temp;
					}
		}
		else//降序
		{
			for (int i = 0; i<N; i++)
				for (int j = 0; j < N - 1 - i; j++)
					if (stu[j].id < stu[j + 1].id)
					{
						temp = stu[j];
						stu[j] = stu[j + 1];
						stu[j + 1] = temp;
					}
		}
		//显示排序结果:
		OutputStudent(stu);
		break;
	}
	case 2://姓名
		if (n == 1)
		{
			for (int i = 0; i<N; i++)
				for (int j = 0; j < N - 1 - i; j++)
					if (strcmp(stu[j].name,stu[j+1].name)>0)
					{
						temp = stu[j];
						stu[j] = stu[j + 1];
						stu[j + 1] = temp;
					}
		}
		else

		{
			for (int i = 0; i<N; i++)
				for (int j = 0; j < N - 1 - i; j++)
					if (strcmp(stu[j].name, stu[j + 1].name)<0)
					{
						temp = stu[j];
						stu[j] = stu[j + 1];
						stu[j + 1] = temp;
					}
		}
		//显示排序结果:
		OutputStudent(stu);
		break;
	case 3://性别
		if (n == 1)
		{
			for (int i = 0; i<N; i++)
				for (int j = 0; j < N - 1 - i; j++)
					if (strcmp(stu[j].sex, stu[j + 1].sex)>0)
					{
						temp = stu[j];
						stu[j] = stu[j + 1];
						stu[j + 1] = temp;
					}
		}
		else

		{
			for (int i = 0; i<N; i++)
				for (int j = 0; j < N - 1 - i; j++)
					if (strcmp(stu[j].sex, stu[j + 1].sex)<0)
					{
						temp = stu[j];
						stu[j] = stu[j + 1];
						stu[j + 1] = temp;
					}
		}
		//显示排序结果:
		OutputStudent(stu);
		break;
	case 4://年龄
		if (n == 1)
		{
			for (int i = 0; i<N; i++)
				for (int j = 0; j < N - 1 - i; j++)
					if (stu[j].age > stu[j + 1].age)
					{
						temp = stu[j];
						stu[j] = stu[j + 1];
						stu[j + 1] = temp;
					}
		}
		else

		{
			for (int i = 0; i<N; i++)
				for (int j = 0; j < N - 1 - i; j++)
					if (stu[j].age < stu[j + 1].age)
					{
						temp = stu[j];
						stu[j] = stu[j + 1];
						stu[j + 1] = temp;
					}
		}
		//显示排序结果:
		OutputStudent(stu);
		break;
	case 5://C语言
		if (n == 1)
		{
			for (int i = 0; i<N; i++)
				for (int j = 0; j < N - 1 - i; j++)
					if (stu[j].subject.C_langeuage > stu[j + 1].subject.C_langeuage)
					{
						temp = stu[j];
						stu[j] = stu[j + 1];
						stu[j + 1] = temp;
					}
		}
		else
		{
			for (int i = 0; i<N; i++)
				for (int j = 0; j < N - 1 - i; j++)
					if (stu[j].subject.C_langeuage < stu[j + 1].subject.C_langeuage)
					{
						temp = stu[j];
						stu[j] = stu[j + 1];
						stu[j + 1] = temp;
					}
		}
		//显示排序结果:
		OutputStudent(stu);
		break;
	case 6://英语
		if (n == 1)
		{
			for (int i = 0; i<N; i++)
				for (int j = 0; j < N - 1 - i; j++)
					if (stu[j].subject.Engelish > stu[j + 1].subject.Engelish)
					{
						temp = stu[j];
						stu[j] = stu[j + 1];
						stu[j + 1] = temp;
					}
		}
		else
		{
			for (int i = 0; i<N; i++)
				for (int j = 0; j < N - 1 - i; j++)
					if (stu[j].subject.Engelish < stu[j + 1].subject.Engelish)
					{
						temp = stu[j];
						stu[j] = stu[j + 1];
						stu[j + 1] = temp;
					}
		}
		//显示排序结果:
		OutputStudent(stu);
		break;
	case 7://数学
		if (n == 1)
		{
			for (int i = 0; i<N; i++)
				for (int j = 0; j < N - 1 - i; j++)
					if (stu[j].subject.Engelish > stu[j + 1].subject.Engelish)
					{
						temp = stu[j];
						stu[j] = stu[j + 1];
						stu[j + 1] = temp;
					}
		}
		else
		{
			for (int i = 0; i<N; i++)
				for (int j = 0; j < N - 1 - i; j++)
					if (stu[j].subject.Math < stu[j + 1].subject.Math)
					{
						temp = stu[j];
						stu[j] = stu[j + 1];
						stu[j + 1] = temp;
					}
		}
		//显示排序结果:
		OutputStudent(stu);
		break;
	case 8://平均分
		if (n == 1)
		{
			for (int i = 0; i<N; i++)
				for (int j = 0; j < N - 1 - i; j++)
					if (stu[j].averagescore > stu[j + 1].averagescore)
					{
						temp = stu[j];
						stu[j] = stu[j + 1];
						stu[j + 1] = temp;
					}
		}
		else
		{
			for (int i = 0; i<N; i++)
				for (int j = 0; j < N - 1 - i; j++)
					if (stu[j].averagescore < stu[j + 1].averagescore)
					{
						temp = stu[j];
						stu[j] = stu[j + 1];
						stu[j + 1] = temp;
					}
		}
		//显示排序结果:
		OutputStudent(stu);
		break;
	default:
		break;
	}
}

练习二:火车订票系统

火车订票系统功能需求如下:

  1. 查询功能:查询车票信息、包括起始地、车次、余票和票价。
  2. 订票功能:车票预定。
  3. 修改功能:修改订票信息。
  4. 录入管理功能:输入车票的基本信息。
  5. 显示功能:将查询到的信息显示出来,供用户查看。

实现:
因为这个练习本身难度在于系统的逻辑结构,结构体运用在练习一已经展示了,避免冗余,就不再附上代码了,如果你想参考我的实现,建议下载源码自行查看。

实战六:指针及其应用

由于指针与内存、地址密切相关,所以也给很多初学者带来了很大的困难。这个实战通过几个简单例子,帮助你们理解和掌握C语言指针的基本应用。

练习一:约瑟夫问题(指针版)

在前面的实战中,已经涉及到了与瑟夫问题,这次我们用指针来解决它

实现:

#include "stdio.h"
#include "stdlib.h"
#include "conio.h"

struct List2
{
	int num;
	char name[11];
	struct List2 *next;
};

void JosephProblem3();
int p6p1Display();
void look(List2 *head,int num);//遍历
void restar(List2 *head,int num);//重新输入
void play(List2 *head,int num);
void practice6project1()
{
	char k;
	int num = 0;
	struct List2 *p = NULL;
	struct List2 *q = NULL;
	struct List2 *head = NULL;

	printf("开始:\n");
	do
	{
		if (head == NULL)
		{
			num++;
			head = (struct List2*)malloc(sizeof(struct List2));//初始化链表				
			printf("名字和密码:");
			fflush(stdin);
			scanf("%s%d", &head->name, &head->num);
			head->next = NULL;
			q = head;
		}
		else
		{
			num++;
			p = (struct List2*)malloc(sizeof(struct List2));
			p->next = NULL;
			q->next = p;//上一个节点连接到这个节点		
			printf("\n名字和密码:");
			fflush(stdin);
			scanf("%s%d", &p->name, &p->num);
			q = p;
		}
		printf("添加成功,现在有%d个人。按y/Y继续添加,按其他键完成:", num);
		k = getch();
	} while (k == 'y' || k == 'Y');
	q->next = head;//循环链表
	fflush(stdin);
	List2 * h1 = head;
	List2 * h2 = head;
	List2 * h3 = head;
	int key;
	while (true)
	{
		system("cls");
		key = p6p1Display();
		switch (key)
		{
		case 1:
			
			look(h1, num);
			break;
		case 2:
			
			restar(h2,num);
			break;
		case 3:
			
			play(h3,num);
			break;
		case 4:
			break;
		default:
			printf("输入错误!");
			getch();
			break;
		}
		if (key == 4)
			break;
	}
}


int p6p1Display()
{
	int k;
	printf("==========================================\n");
	printf("1.显示信息\n");
	printf("2.重新输入密码\n");
	printf("3.开始“数N退出”\n");
	printf("4.返回上一级菜单\n");
	printf("==========================================\n");
	printf("请选择:");
	scanf("%d", &k);
	return k;
}

void look(List2 *head,int num)//显示数据
{
	printf("数据如下:\n");
	for (int i = 0; i < num; i++)
	{
		printf("%s\t%d\n", head->name, head->num);
		head = head->next;
	}
	getch();
}

void restar(List2 *head,int num)//重新输入密码
{
	printf("开始重新输入:\n");
	printf("===============================================\n");
	for (int i = 0; i < num; i++)
	{
		printf("%s\t", head->name);
		scanf("%d", &head->num);
		head = head->next;
	}
	printf("输入完成!");
	getch();
}



void play(List2 *head,int num)//开始游戏
{
	char k;
	struct List2 *star;
	star = head;
	int key = 0;
	int target = star->num;


	printf("\n游戏开始:\n");
	while (num != 0)
	{
		if (star->num != -1)
		{
			key++;
			if (key == target)
			{
				num--;
				printf("%s\t%d\n", star->name, star->num);
				target = star->num;
				key = 0;
				star->num = -1;

			}
			star = star->next;
		}
		else
			star = star->next;
	}
	getch();
}

练习二:学生信息登记管理(结构体+链表)

在前面我们已经讨论了这问题,现在我们用更加符合现实的情况来实现这个练习,也就是:在程序运行前学生人数时不确定的,所以数组这个方法就不再适用了。通过这个练习你可以知道指针的强大之处。
实现:

#include "stdio.h"
#include "stdlib.h"
#include "conio.h"
#include "string.h"
int num=0;
int key2;//怎么排序
//数据定义
typedef struct data
{
	char id[13];
	char name[11];
	char sex[5];
	int old;
	int C_Language;
	int English;
	int Math;
	float average;
};
typedef struct Student
{
	data student;
	Student *prev;
	Student *next;
};

Student *start();//初始化链表
int p6Display(int n);//菜单
void show1(Student *head);//原始数据展示
void show2(data target[]);//排序顺序显示

void sort1(Student *head);
void sort2(Student *head);
void sort3(Student *head);
void sort4(Student *head);
void sort5(Student *head);
void sort6(Student *head);
void sort7(Student *head);
void sort8(Student *head);


void practice6project2()
{
	Student  *head=start();
	int key1;//1是一级菜单  2是二级菜单
	while (true)
	{
		key1= p6Display(1);
		if(key1!=9&&key1!=0)
		    key2= p6Display(2);
		switch (key1)
		{
		case 1:
			sort1(head);
			break;
		case 2:
			sort2(head);
			break;
		case 3:
			sort3(head);
			break;
		case 4:
			sort4(head);
			getch();
			break;
		case 5:
			sort5(head);
			break;
		case 6:
			sort6(head);
			break;
		case 7:
			sort7(head);
			break;
		case 8:
			sort8(head);
			break;
		case 9:
			show1(head);
			break;
		case 0:
			break;
		default:
			printf("输入错误!");
			break;
		}
		if (key1 == 0)
			break;
	}
}

//初始化链表
Student *start()
{
	Student *head=NULL;
	Student *p = NULL;
	Student *q = NULL;
	char k;
	printf("请输入学生信息:");
	do
	{
		if (head == NULL)
		{
			num++;
			head = (Student*)malloc(sizeof(Student));
			printf("请添加一下信息:");
			printf("学号:");
			scanf("%s", &head->student.id);
			printf("姓名:");
			scanf("%s", &head->student.name);
			printf("性别:");
			scanf("%s", &head->student.sex);
			printf("年龄:");
			scanf("%d", &head->student.old);
			printf("C语言:");
			scanf("%d", &head->student.C_Language);
			printf("英语:");
			scanf("%d", &head->student.English);
			printf("数学:");
			scanf("%d", &head->student.Math);
			head->student.average = (head->student.Math + head->student.English + head->student.C_Language)/3;
			head->next = NULL;
			head->prev = NULL;
			q = head;
		}
		else
		{
			num++;
			p= (Student*)malloc(sizeof(Student));
			printf("\n请添加一下信息:");
			printf("学号:");
			scanf("%s", &p->student.id);
			printf("姓名:");
			scanf("%s", &p->student.name);
			printf("性别:");
			scanf("%s", &p->student.sex);
			printf("年龄:");
			scanf("%d", &p->student.old);
			printf("C语言:");
			scanf("%d", &p->student.C_Language);
			printf("英语:");
			scanf("%d", &p->student.English);
			printf("数学:");
			scanf("%d", &p->student.Math);
			p->student.average = (p->student.Math + p->student.English + p->student.C_Language)/3;
			//完成节点链接
			p->prev = q;//这个节点指向上个节点
			q->next = p;//上个节点指向这个节点
			q = p;
		}
		fflush(stdin);
		printf("添加成功!现在有%d个人。按y/Y继续添加,按其他键完成:",num);
		k = getch();
	} while (k == 'y' || k == 'Y');
	return head;
}

//菜单
int p6Display(int n)
{
	int key;
	system("cls");
	switch (n)
	{
	case 1:
	{
		printf("\n");
		printf("选择排序方式:\n");
		printf("-----------------------------------------------------------------\n");
		printf("1.学号\t2.姓名\t3.性别\t4.年龄\n");
		printf("5.C语言\t6.英语\t7.高数\t8.平均分\n");
		printf("9.显示原始数据\t0.返回上一级菜单\n");
		printf("-----------------------------------------------------------------\n");
		break;
	}
	case 2:
	{
		printf("\n");
		printf("-----------------------------------------------------------------\n");
		printf("1.升序\t\t2.降序\t\t0.返回上一级菜单\n");
		printf("-----------------------------------------------------------------\n");
	}
	default:
		break;
	}
	scanf("%d", &key);
	return key;
}

//显示原始数据
void show1(Student *head)
{
	Student * start = head;
	printf("学号\t姓名\t性别\t年龄\tC语言\t英语\t高数\t平均分\n");
		for (int i = 0; i <num; i++)
		{
			printf("%-8s%-8s%-8s%-8d%-8d%-8d%-8d%-8f\n", start->student.id, start->student.name,
				start->student.sex, start->student.old, start->student.C_Language,
				start->student.English, start->student.Math, start->student.average);
			start = start->next;
		}
	getch();
}

//显示排序后的数据
void show2(data target[])
{
	printf("学号\t姓名\t性别\t年龄\tC语言\t英语\t高数\t平均分\n");
	if (key2 == 1)
		for (int i = 0; i < num; i++)
		{
			printf("%-8s%-8s%-8s%-8d%-8d%-8d%-8d%-8f\n", target[i].id, target[i].name,
				target[i].sex, target[i].old, target[i].C_Language, target[i].English,
				target[i].Math, target[i].average);
		}
	else
		for (int i = num-1; i >=0; i--)
		{
			printf("%-8s%-8s%-8s%-8d%-8d%-8d%-8d%-8f\n", target[i].id, target[i].name,
				target[i].sex, target[i].old, target[i].C_Language, target[i].English,
				target[i].Math, target[i].average);
		}
	getch();
}

//学号
void sort1(Student *head)
{
	Student * start = head;
	data *target = (data*)malloc(sizeof(data)*num);
	data temp;
	for (int i = 0; i < num; i++)
	{
		target[i] = start->student;
		start = start->next;
	}
	for(int i=0;i<num;i++)
		for (int j = 0; j < num - 1 - i; j++)
			if (target[j].id > target[j + 1].id)
			{
				temp = target[j];
				target[j] = target[j + 1];
				target[j + 1] = temp;
			}
	show2(target);//显示数据	
	free(target);
}

//姓名
void sort2(Student *head)
{
	Student * start = head;
	data *target = (data*)malloc(sizeof(data)*num);
	data temp;
	for (int i = 0; i < num; i++)
	{
		target[i] = start->student;
		start = start->next;
	}
	for (int i = 0; i<num; i++)
		for (int j = 0; j < num - 1 - i; j++)
			if (strcmp(target[j].name,target[j + 1].name)>0)
			{
				temp = target[j];
				target[j] = target[j + 1];
				target[j + 1] = temp;
			}
	show2(target);//显示数据
	free(target);
}
void sort3(Student *head)//性别
{
	Student * start = head;
	data *target = (data*)malloc(sizeof(data)*num);
	data temp;
	for (int i = 0; i < num; i++)
	{
		target[i] = start->student;
		start = start->next;
	}
	for (int i = 0; i<num; i++)
		for (int j = 0; j < num - 1 - i; j++)
			if (strcmp(target[j].sex, target[j + 1].sex)>0)
			{
				temp = target[j];
				target[j] = target[j + 1];
				target[j + 1] = temp;
			}
	show2(target);//显示数据
	free(target);
}
void sort4(Student *head)//年龄
{
	Student * start = head;
	data *target = (data*)malloc(sizeof(data)*num);
	data temp;
	for (int i = 0; i <num; i++)
	{
		target[i] = start->student;
		start = start->next;
	}
	for (int i = 0; i<num; i++)
		for (int j = 0; j < num - 1 - i; j++)
			if (target[j].old > target[j + 1].old)
			{
				temp = target[j];
				target[j] = target[j + 1];
				target[j + 1] = temp;
			}
	show2(target);//显示数据
	free(target);
}
void sort5(Student *head)//C语言
{
	Student * start = head;
	data *target = (data*)malloc(sizeof(data)*num);
	data temp;
	for (int i = 0; i <num; i++)
	{
		target[i] = start->student;
		start = start->next;
	}
	for (int i = 0; i<num; i++)
		for (int j = 0; j < num - 1 - i; j++)
			if (target[j].C_Language> target[j + 1].C_Language)
			{
				temp = target[j];
				target[j] = target[j + 1];
				target[j + 1] = temp;
			}
	show2(target);//显示数据
	free(target);
}
void sort6(Student *head)//英语
{
	Student * start = head;
	data *target = (data*)malloc(sizeof(data)*num);
	data temp;
	for (int i = 0; i <num; i++)
	{
		target[i] = start->student;
		start = start->next;
	}
	for (int i = 0; i<num; i++)
		for (int j = 0; j < num - 1 - i; j++)
			if (target[j].C_Language > target[j + 1].C_Language)
			{
				temp = target[j];
				target[j] = target[j + 1];
				target[j + 1] = temp;
			}
	show2(target);//显示数据
	free(target);
}
void sort7(Student *head)//高数
{
	Student * start = head;
	data *target = (data*)malloc(sizeof(data)*num);
	data temp;
	for (int i = 0; i <num; i++)
	{
		target[i] = start->student;
		start = start->next;
	}
	for (int i = 0; i<num; i++)
		for (int j = 0; j < num - 1 - i; j++)
			if (target[j].Math > target[j + 1].Math)
			{
				temp = target[j];
				target[j] = target[j + 1];
				target[j + 1] = temp;
			}
	show2(target);//显示数据
	free(target);
}
void sort8(Student *head)//平均分
{
	Student * start = head;
	data *target = (data*)malloc(sizeof(data)*num);
	data temp;
	for (int i = 0; i <num; i++)
	{
		target[i] = start->student;
		start = start->next;
	}
	for (int i = 0; i<num; i++)
		for (int j = 0; j < num - 1 - i; j++)
			if (target[j].average > target[j + 1].average)
			{
				temp = target[j];
				target[j] = target[j + 1];
				target[j + 1] = temp;
			}
	show2(target);//显示数据
	free(target);
}

练习三:贪吃蛇游戏

是不是有点激动?当时我看到这题目时我真的激动了,我终于可以自己写游戏了,真的很有成就感!
tips:这里我使用了easyx库,具体请访问它们们的官网:点这里.
实现:

#include "stdio.h"
#include "stdlib.h"
#include "conio.h"
#include "string.h"
#include <time.h>
#include "math.h"
#include <graphics.h>      // 引用图形库头文件

#define SNAKEADD 15
#define SIDE 15

TCHAR snakehead[] = _T("■");
TCHAR snakebody[] = _T("□");
TCHAR snakfood[] = _T("@");
typedef struct Snake
{
	int x;
	int y;
	Snake *prev;
	Snake *next;
};

typedef struct Food
{
	int x;
	int y;
};
void food(int num[]);//重新食物
void addlength(Snake *head);//添加蛇身

void practice6project3()
{
	initgraph(600, 600);//初始化图形界面
	//画出边框
	POINT pts[] = { { 4, 4 },{ 591, 4 },{ 591,591 },{ 4, 591 } };
	polygon(pts, 4);
	//初始化链表
	//*****************************************************
	Snake *head = NULL;
	Snake *p = NULL;
	Snake *q = NULL;
	head = (Snake*)malloc(sizeof(Snake));
	head->x = 300;
	head->y = 300;
	head->next = NULL;
	head->prev = NULL;
	q = head;
	//*********************************************************

	Snake *start = head;
	char c = 'a',c2='a';//蛇的移动方向控制
	int key1 = 0;//判断蛇撞墙
	int key2 = 0;//判断蛇撞到自己
	int hx, hy;//收集蛇头移动后的位置,判断是否撞到自己
	int prex, prey;//收集蛇头移动前的位置
	int temp[4];//收收集蛇身位置
	int eat = 1;//蛇是否吃到食物
	int eat2 = 0;
	int num[2];//食物的位置
	int distamce1;//蛇头吃到自己
	int distamce2;//蛇头与食物的距离

				 //food(num);//第一次出现食物

				 //主循环
	while (true)
	{
		clearrectangle(5, 5, 590, 590);//清空

		if (eat == 1)
		{
			if (eat2 == 1)
				addlength(head);
			food(num);
			eat = 0;
			eat2 = 0;
		}
		//画出食物
		outtextxy(num[0], num[1], snakfood);
		//蛇移动
		start = head;//找到头指针

	  //蛇没有撞墙
		if (start->x <585 && start->x>5 && start->y<585 && start->y>5)
		{
			//记录蛇头旧位置
			prex = start->x;
			prey = start->y;
			//**************************************************************************************
			//接收键盘消息并处理
			{
				if (kbhit())//是否换方向
					c2 = getch();
				//去掉错误的行走放向
				switch (c2)
				{
				case 'w':
					if (c == 's')
						;
					else
						c = c2;
					break;
				case 'a':
					if (c == 'd')
						;
					else
						c = c2;
					break;
				case 's':
					if (c == 'w')
						;
					else
						c = c2;
					break;
				case 'd':
					if (c == 'a')
						;
					else
						c = c2;
					break;
				}
				//改变方向
				switch (c)
				{
				case 'w':
					head->y -= SNAKEADD;
					break;
				case 'a':
					head->x -= SNAKEADD;
					break;
				case 's':
					head->y += SNAKEADD;
					break;
				case 'd':
					head->x += SNAKEADD;
					break;
				default:
					break;
				}
			}
			//**************************************************************************************
			
			hx = start->x;
			hy = start->y;
			//******************************************************
			//在这里判断蛇吃到自己			
			//while (start->next != NULL)
			//{
			//	if (hx == start->x& hy == start->y)
			//	{
			//		TCHAR bb[] = _T("游戏结束!");
			//		outtextxy(300, 300, bb);
			//		key2 = -1;
			//	}
			//	start = start->next;
			//}
			//******************************************************
			distamce2 = (int)sqrt(((int)pow(((num[0] * 2 + 15) / 2 - (head->x * 2 + 15) / 2), 2)) + ((int)pow(((num[1] * 2 + 15) / 2 - (head->y * 2 + 15) / 2), 2)));
			//是否吃到食物
			if (distamce2 <= 15)
			{
				eat = 1;
				eat2 = 1;
			}
			//*****************************************************************
			//蛇没有撞墙且蛇没有撞到自己的情况下移动蛇身
			if (key2 != -1)
			{
				start->x = prex;//让蛇头还原到上一个位置
				start->y = prey;
				temp[0] = start->x;
				temp[1] = start->y;
				start = start->next;
				while (start != NULL)//有蛇身 就换数据
				{
					//先把自己的数据存好
					temp[2] = start->x;
					temp[3] = start->y;

					//把上个节点数据下放
					start->x = temp[0];
					start->y = temp[1];

					temp[0] = temp[2];
					temp[1] = temp[3];
					start = start->next;
				}
				//回复蛇头到移动后的位置
				start = head;
				start->x = hx;
				start->y = hy;
			}

			//*****************************************************************
			//画出蛇
			if (key2 != -1)
			{
				outtextxy(start->x, start->y, snakehead);
				start = start->next;
				while (start != NULL)
				{
					outtextxy(start->x, start->y, snakebody);
					start = start->next;
				}
			}
			//*****************************************************************
		}
		//蛇撞墙
		else
		{
			TCHAR aa[] = _T("游戏结束!");
			outtextxy(300, 300, aa);
			key1 = -1;
		}

		//游戏要出口
		if (key1 == -1 || key2 == -1)
			break;
		Sleep(200);
	}
	_getch();              // 按任意键继续
	closegraph();          // 关闭绘图窗口
}

//食物在范围内
void food(int num[])
{
	srand((unsigned)time(NULL));
	do
	{
		num[0] = rand() % 590;
		num[1] = rand() % 590;
	} while (!(num[0]<580 && num[0]>10 && num[1]<580 && num[1]>10));
}
//添加蛇身
void addlength(Snake *head)
{
	Snake *start = head;
	while (start->next != NULL)
		start = start->next;
	Snake *n = (Snake*)malloc(sizeof(Snake));
	n->next = NULL;

	n->prev = start;//链接前一个节点
	start->next = n;

}

实战七:文件操作及应用

本实战告诉你如何用C语言对文件进行读写,几个简单练习,你就可以掌握它。然后你可以自己写点好玩的东西,整蛊你室友。

练习一:简单的计数器

要求:

  1. 程序运行时,打开磁盘的数据文件,读取已经运行的次数。
  2. 再内存中计算本次程序运行的次数。
  3. 现实该程序本次运行的次数。
  4. 程序结束前,保存运行次数到磁盘数据文件中。
    实现:
#include "stdio.h"
#include "stdlib.h"
#include "conio.h"

void practice7project1()
{
	int count = 1;
	int key = 0;
	FILE *fp;
	if ((fp = fopen("practice7project1.dat", "r")) != NULL)//文件已经存在,进行count++
	{
		//读出数据
		fscanf(fp, "%d", &count);
		fclose(fp);//关闭只读
		//启动写入数据
		fp = fopen("practice7project1.dat", "w");
		count++;
		fprintf(fp, "%d", count);
		fclose(fp);
	}
	else if ((fp = fopen("practice7project1.dat", "w+")) == NULL)//第一次打开文件
	{
		printf("程序出错");
		getch();
		key = -1;
		if (key != -1)
		{
			fprintf(fp, "%d", count);
		}
	}
	if (key !=-1)
	{
		printf("这个程序运行%d次", count);
		getch();
	}
}

练习二:学生学籍管理系统(结构体+文件)

要求:

  1. 学生信息保存再磁盘文件:studentInfo.dat中。
  2. 学生学习管理系统可以完成对学生成绩信息的增、删、该、查操作。
  3. “平均成绩”项应该通过计算获得,不从键盘输入。
  4. 第一次使用噶系统时,可以从键盘输入初始数据,并建立初始学生信息磁盘文件:stendentInfo.dat。
  5. 退出系统前,要求把当前系统内的数据保存到文件中。
  6. 系统启动后,给出主操作菜单让用户选择操作,主菜单如下:
请选择排序字段
----------------------------------------------------------------------
1.现实所有学生信息			2.查询单个学生信息
3.修改学生信息			4.删除学生信息
5.增加学生信息			6.保存修改
0.退出系统
----------------------------------------------------------------------

实现(我可能偷懒了,没有按照要求来,但是核心功能实现了的):

#include "stdio.h"
#include "stdlib.h"
#include "conio.h"
typedef struct Student

{
	int id;
	char name[9];
	char sex[3];
	int old;
	float C_language;
	float Engkish;
	float Math;
	float average;
	Student *next;
};
int number;
//studentInfo.dat
//增加 删除 修改,查;
int  p72Display();
int input(Student* &head);//输入数据
int output(Student* head);//输出数据到文件
int  read(Student* &head);//从文件读取数据

void show(Student* head);//浏览数据
void addstudent(Student* &head);//添加元素
void delatestudent(Student* &head);//删除元素
void changestudent(Student* &head);//修改数据

//入口
void practice7project2()
{
	Student *head;
	head = NULL;
	int key;
	FILE *fp;
	printf("是否是第一次运行本程序:1.是\t2.不是\t3.不清楚\n");
	scanf("%d", &key);

	//原始提取
	while (true)
	{
		switch (key)
		{
		case 1://输入数据原始数据并写入文件
		{
			number = input(head);
			if (output(head))
				printf("写入文件成功!\n");
			else
				printf("写入文件失败");
			getch();
			break;
		}
		case 2://读取数据
			number= read(head);
			break;
		case 3://检查是否有数据,根据结果选择操作
		{
			if ((fp = fopen("practice7project2.dat", "r")) == NULL)
			{
				printf("检查到没有这个文件,现在请输入信息:\n");
				number = input(head);
				if (output(head))//将数据写入文件
					printf("写入文件成功!\n");
				else
					printf("写入文件失败");
				getch();
			}
			else
			{
				printf("检查到文件\n");
				number = read(head);
				if (number != 0)
					printf("文件读取成功!\n");
				else
					printf("文件读取失败!\n");
			}
			getch();
			break;
		}
		default:
			printf("输入错误");
			break;
		}
		if (key == 1 || key == 2 || key == 3)
			break;
	}
	//数据处理
	while (true)
	{
		system("cls");
		key = p72Display();
		switch (key)
		{
		case 1://查询数据
			show(head);
			break;
		case 2://添加数据
			addstudent(head);
			break;
		case 3://删除数据
			delatestudent(head);
			break;
		case 4://修改数据
			changestudent(head);
			break;
		case 5:
			break;
		default:
			printf("输入错误1");
			break;
		}
		if (key == 5)
			break;
	}
}

int p72Display()
{
	int key;
	printf("============================================================\n");
	printf("\t1.查询数据\n");
	printf("\t2.添加数据\n");
	printf("\t3.删除数据\n");
	printf("\t4.修改程序\n");
	printf("\t5.返回上一级菜单\n");
	printf("============================================================\n");
	scanf("%d", &key);
	return key;
}


//输入数据
int input(Student* &head)
{
	int num;
	Student *p = NULL;
	Student *q =NULL;
	printf("\n\n请输入你要输入的学生个人数:");
	scanf("%d",&num);
	for (int i = 0; i < num; i++)
	{
		if (head == NULL)
		{
			head = (Student*)malloc(sizeof(Student));
			head->next = NULL;
			printf("==========================================================================\n");
			printf("请输入学号:");
			scanf("%d", &head->id);
			printf("请输入姓名:");
			scanf("%s", &head->name);
			printf("请输入性别:");
			scanf("%s", &head->sex);
			printf("请输入年龄:");
			scanf("%d", &head->old);
			printf("请输入C语言:");
			scanf("%f", &head->C_language);
			printf("请输入英语:");
			scanf("%f", &head->Engkish);
			printf("请输入数学:");
			scanf("%f", &head->Math);
			head->average = (head->Math + head->C_language + head->Engkish) / 3;
			q = head;
		}
		else
		{
			p = (Student*)malloc(sizeof(Student));
			p->next = NULL;
			q->next = p;
			printf("==========================================================================\n");
			printf("请输入学号:");
			scanf("%d", &p->id);
			printf("请输入姓名:");
			scanf("%s", &p->name);
			printf("请输入性别:");
			scanf("%s", &p->sex);
			printf("请输入年龄:");
			scanf("%d", &p->old);
			printf("请输入C语言:");
			scanf("%f", &p->C_language);
			printf("请输入英语:");
			scanf("%f", &p->Engkish);
			printf("请输入数学:");
			scanf("%f", &p->Math);
			p->average = (p->Math + p->C_language + p->Engkish) / 3;
			q = p;
		}
	}
	printf("输入结束,按任意键继续...");
	getch();
	return num;
}

//输出数据到文件
int output(Student* head)
{
	int num=0;
	FILE *ff;
	if ((ff = fopen("practice7project2.dat", "w")) == NULL)
		printf("文件打开失败!\n");
	else
	{
		while (head != NULL)
		{
			num += fwrite(head, sizeof(Student), 1, ff);
			head = head->next;
		}
	}
	fclose(ff);
	return num;
}
//从文件读取数据
int  read(Student* &head)
{
	int num=0;
	FILE *ff;
	if ((ff = fopen("practice7project2.dat", "r")) == NULL)
		printf("文件打开失败!");
	else
	{
		Student *p = NULL;
		Student *q = NULL;
		while (!feof(ff))
		{
			if (head == NULL)
			{
				head = (Student*)malloc(sizeof(Student));
				fread(head, 1, sizeof(Student), ff);
				num++;
				q = head;
			}
			else
			{
				p = (Student*)malloc(sizeof(Student));
				if (fread(p, 1, sizeof(Student), ff) > 2)
				{
					num++;
					p->next = NULL;
					q->next = p;
					q = p;
				}
				else
				{
					free(p);
				}
			}
		}
	}
	return num;
}

//浏览数据
void show(Student* head)
{
	printf("学号\t姓名\t性别\t年龄\tC语言\t英语\t数学\t平均分\n");
	while (head!=NULL)
	{
		printf("%-4d\t%-4s\t%-4s\t%-4d\t%-4.2f\t%-4.2f\t%-4.2f\t%-4.2f\n",head->id, head->name, head->sex, head->old,head->C_language,head->Engkish,head->Math,head->average );
		head = head->next;
	}
	getch();
}

//添加元素
void addstudent(Student* &head)
{
	Student *oldhead=head;
	int num;
	printf("请输入你要添加的学生个数:");
	scanf("%d", &num);
	number += num;
	while (head->next!=NULL)
	{
		head = head->next;
	}
	Student *p = NULL;
	Student *q = NULL;

	q = head;
	for (int i = 0; i < num; i++)
	{
		p = (Student*)malloc(sizeof(Student));
		p->next = NULL;
		q->next = p;
		printf("==========================================================================\n");
		printf("请输入学号:");
		scanf("%d", &p->id);
		printf("请输入姓名:");
		scanf("%s", &p->name);
		printf("请输入性别:");
		scanf("%s", &p->sex);
		printf("请输入年龄:");
		scanf("%d", &p->old);
		printf("请输入C语言:");
		scanf("%f", &p->C_language);
		printf("请输入英语:");
		scanf("%f", &p->Engkish);
		printf("请输入数学:");
		scanf("%f", &p->Math);
		p->average = (p->Math + p->C_language + p->Engkish) / 3;
		q = p;
	}
	printf("输入结束,按任意键继续...");
	getch();
	head = oldhead;
	if (output(head) > 1)
		printf("写入文件成功!\n");
	else
		printf("写入文件失败!\n");
	getch();

}

//删除元素
void delatestudent(Student* &head)
{
	int num;
	Student *cp, *star = head;
	printf("请输入你想删除学生的学号:");
	scanf("%d", &num);
	while (star!=NULL)
	{
		if (star->id == num)
			break;
		cp = star;
		star = star->next;
	}
	if (cp==NULL)//删除第一个节点
	{
		cp = head;
		 head= head->next;
		free(cp);
	}
	else
		cp->next = star->next;

	//在把修改后的数据写入文件
	if (output(head) > 1)
		printf("删除成功!\n");
	else
		printf("删除失败!\n");
	number--;
	getch();
}

//修改数据
void changestudent(Student* &head)
{
	int num;
	Student *star = head;
	printf("请输入你想修改学生的学号:");
	scanf("%d", &num);
	while (star != NULL)
	{
		if (star->id == num)
			break;
		star = star->next;
	}
	printf("请输入修改的内容:\n");
	printf("==========================================================================\n");
	printf("请输入学号:");
	scanf("%d", &star->id);
	printf("请输入姓名:");
	scanf("%s", &star->name);
	printf("请输入性别:");
	scanf("%s", &star->sex);
	printf("请输入年龄:");
	scanf("%d", &star->old);
	printf("请输入C语言:");
	scanf("%f", &star->C_language);
	printf("请输入英语:");
	scanf("%f", &star->Engkish);
	printf("请输入数学:");
	scanf("%f", &star->Math);
	star->average = (star->Math + star->C_language + star->Engkish) / 3;

	//写入到文件
	if (output(head) > 1)
		printf("修改成功!\n");
	else
		printf("修改失败!\n");
	getch();
}

结语

所有的代码都是我在学习中自己积累,很多题目的实现现在看起来都很幼稚,但我很高兴,对于我来所我这个课程完成的不错。最后附上完整demo的地址: 点这里.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值