【C语言】软件开发基础篇–CL音乐

追求适度,才能走向成功;人在顶峰,迈步就是下坡;身在低谷,抬足既是登高;弦,绷得太紧会断;人,思虑过度会疯;水至清无鱼,人至真无友,山至高无树;适度,不是中庸,而是一种明智的生活态度。

导读:本篇文章讲解 【C语言】软件开发基础篇–CL音乐,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

作为基础篇,实现软件的那些功能呢?

a.构建基本框架

b.围绕歌曲信息的增删查改进行的

c.将内容通过文件操作存进文档

d.整理歌曲内容(排序)

e.实现简单的歌曲播放功能

有人可能就会问了,需要掌握C语言那些知识才能实现这些功能呢?

主要是 :数组,函数,指针,结构体,文件操作等知识即可.

接下来,带大家一起实操

首先,为了让部分功能分工明确,我们可以建立三个cpp文件,(播放音乐需要在c++的环境下)一个头文件,将他看成一个盖房子的过程:

CL-music.h 头文件(建筑图纸)

Basic struct.cpp 用来构建框架,地基

Function interface.cpp 功能界面(给建筑上色,标明门牌号)

play.cpp 实现各部分功能(家具)

【C语言】软件开发基础篇--CL音乐

首先从创建好的Basic struct.cpp开始实现

想象一下

在我们登录类似于QQ音乐,网易音乐的时候刚开始是不是都有一个登录界面,然后显示音乐logo

这里我们可以分装两个函数

//初始化界面  
Init_picture();
//登录
Lojin();

接着在CL-music.h实现函数声明(可以把所有需要引用的头文件都写入CL-music.h,其他文件只需要引用一下此头文件即可,例如#include”CL-music.h”)

这两项都不需要返回值,所以写成void即可

//初始化加载界面
void Init_picture();

//登录/注册
void Lojin();

接下来在Basic struct.cpp里实现

初始化界面就不展示啦,大家可以根据自己的创意来设计logo~

登录如何实现呢?

想象一下

大家刚开始在使用这个软件的时候是不是都没账号,所以要有注册界面,然后再登录(已有账号可以直接跳过注册),账号通过两个数组来维护,一个是注册时输入的,一个是登录时确定的,通过比较即可确定是否输入正确,密码也是如此,账号或密码输入需要重新输入.

下面是登录代码:

//登录
void Lojin()
{

	printf("|-----------------------------------------|\n");
	printf("                  请登录                  \n");
	printf("|-----------------------------------------|\n");
	char account[10] = { 0 };
	char password[10] = { 0 };
	char account_1[10] = { 0 };
	char password_1[10] = { 0 };
	while (1)
	{
		printf("请输入账号(如果您还没有账号请输入\"*\"注册账号) :");
		scanf("%s", account_1);
		if (account_1[0] == '*')
		{
			printf("\n请输入您要注册的账号:");
			scanf("%s", account);
			printf("\n请输入您要注册的密码:");
			scanf("%s", password);
			printf("注册成功\n");
		}
		else
		{
			if (strcmp(account, account_1) == 0)
			{
				printf("请输入密码:");
				scanf("%s", &password_1);
				if (strcmp(password, password_1) == 0)
				{
					printf("登录成功\n");
					printf("正在为您加载...\n");
					Sleep(4000);
					system("cls");
					return;
				}
				else
				{
					printf("密码错误,请重新输入!\n");
				}
			}
			else
			{
				printf("账户错误,请重新输入!\n");
			}
		}
	}

}

成功登录进入后,是不是因该转入功能界面了呢?

大家可以自己想象设计一下功能界面,比如热门歌曲选项,主页,搜索,等等

由于是基础篇,不需要考虑网络搭建,有些界面只需要一个形式即可

下面是功能界面代码实现:

//加载功能界面--主界面
int Func_picture()
{
	printf("|-----------------------------------------|\n");
	printf("|   搜索(1):                             |\n");
	printf("|-----------------------------------------|\n");
	printf("|   热门(2)  |     歌单(3)   |  主页(4)   |\n");
	printf("|-----------------------------------------|\n");
	printf("|-----------------------------------------|\n");
	printf("|                                         |\n");
	printf("|                                         |\n");
	printf("|                欢迎您来到               |\n");
	printf("|                                         |\n");
	printf("|                   CL                    |\n");
	printf("|    海报                          海报   |\n");
	printf("|                  musci                  |\n");
	printf("|                                         |\n");
	printf("|                  ...                    |\n");
	printf("|                                         |\n");
	printf("|                关闭程序(0)              |\n");
	printf("|                                         |\n");
	printf("|-----------------------------------------|\n");
	printf("请输入您要进行操作的序号:");
	int input = 0;
	scanf("%d", &input);
	system("cls");
	return input;
}

以上各功能只需输入对应的序号即可执行操作,并通过system(“cls”);清除界面,实现界面跳转

补充一点,system函数来源于stdlib.h文件,登录界面的字符串比较函数来自string.h因此需要在头文件里包含

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

int Func_picture();这个功能界面为什么需要返回值呢?

接下来看主体框架

int main()
{
	//初始化加载界面
	Init_picture();
	int input1 = 0;
	Lojin();//登录
	do
	{
		switch (input1 = Func_picture())
		{
		case 1:
			break;
		case 2:
			break;
		case 3:
            break;
		case 4:
			break;
		case 5:
			break;
		case 0:
			printf("退出音乐\n");
			return 0;
		default:
			printf("输入非法,请重新输入!\n");
			break;
		}
	} while (input1);
	return 0;
}

通过 Func_picture();的返回值来判断进入哪个case语句,并实现相应功能

既然是歌曲库,那么何来的库呢?

这里通过结构来创建歌曲库

结构体放入.h文件即可

typedef struct Songinfo //歌曲相关信息
{
	char Charname[NAME_MAX];
	char Charauthor[AUTHOR_MAX];
	char Charsinger[SINGER_MAX];
	char Charpub_date[DATE_MAX];
}Songinfo;

这里的数量我用的#define定义的,可以方便后期维护和修改

#define NAME_MAX 20
#define AUTHOR_MAX 20
#define SINGER_MAX 20
#define DATE_MAX 11

可是我们总不可能写入一个歌曲信息就去手动创建一个

可以另外创建一个结构体,实现真正的歌曲库,里面包含一个结构体数组和一个计数器,每添加一个歌曲信息就将计数器加1,这样不仅实现了多信息的存储,也记录了信息的存储数量

typedef struct Song_library //歌曲库
{
	Songinfo arr[MUSIC_MAX];//添加进的歌曲
	int sz;//记录当前有效信息数
}Song_library

创建歌曲库,命名为son

//歌曲库
	Song_library son;

下一步,将结构体数据初始化,写入play.cpp

注意这里传址

//初始化库存音乐
void Init_library(Song_library* son)
{
	son->sz = 0;
	memset(son->arr, 0, sizeof(son->arr));
}

接下来就可以一步一步实现功能界面部分功能啦

既然是实现功能,不妨将这些功能分装成不同的函数,放在play.cpp中

注意:不要忘记将这些函数声明哦~

首先是

搜索歌曲功能

通过搜索歌曲名,展示出歌曲相应信息

如何实现呢

可以通过遍历数组,用字符串比较函数的方法来查询

下面是搜索代码实现

//查找信息
static int Find_song(const Song_library* son, char name[NAME_MAX])
{
    assert(son != NULL);
	int i = 0;
	for (i = 0; i < son->sz; i++)
	{
		if (0 == strcmp(name, son->arr[i].Charname))
		{
			return i;
		}
	}
	return -1;
}

注:assert(son != NULL);保证指针有效性

细心的小伙伴可能就发现了,

这里的static是干什么的?

const又是干什么的?

第一个问题:想象一下,如果在未来的公司里,每个文件分别实现不同功能,当代码量特别大的时候,在两个不同的文件下定义了两个同名的函数,但是要实现不同的功能,这时代码就会出现冗余的现象,为了避免,加上static关键字,将其修饰为静态变量,使其函数功能的实现只能在本文件里使用,就有效防止了代码的冗余.

第二个问题:搜索功能不需要去修改什么,const是为了防止Song_library* son被修改,这样加强了代码,未来实现一个大的工程,不是只有你一个人在完成这个项目,别人可能并不知道这个变量不能被修改!

第二个模块:

热门选项:

//热门
void Hot()
{

	printf("|-----------------------------------------|\n");
	printf("|                  热门                   |\n");
	printf("|-----------------------------------------|\n");
	printf("|                今日榜单                 |\n");
	printf("|                                         |\n");
	printf("|         说好不哭 周杰伦 试听(1)         |\n");
	printf("|                                         |\n");
	printf("|       不为谁而作的歌 林俊杰 试听(2)     |\n");
	printf("|                                         |\n");
	printf("|         七里香 周杰伦 试听(3)           |\n");
	printf("|                                         |\n");
	printf("|                   ...                   |\n");
	printf("|                 返回(0)                 |\n");
	printf("|                                         |\n");
	printf("|-----------------------------------------|\n");

	int input = 0;
	printf("请选择:");
	scanf("%d", &input);
	switch (input)
		{
		case 1:
			system("cls");
			Music(input);
			break;
		case 2:
			system("cls");
			Music(input);
			break;
		case 3:
			system("cls");
			Music(input);
			break;
		case 0:
			system("cls");
			break;
		default:
			printf("输入非法,请重新输入!\n");
			break;
		}
	system("cls");

一个简易的播放界面,作为试听歌曲

第三个模块:

歌单界面:

int Playlist_menu()
{
	printf("|-----------------------------------------|\n");
	printf("|               *** LC ***                |\n");
	printf("|       |-------------------------|       |\n");
	printf("|       |        添加歌曲(1)      |       |\n");
	printf("|       |-------------------------|       |\n");
	printf("|       |        删除歌曲(2)      |       |\n");
	printf("|       |-------------------------|       |\n");
	printf("|       |        查询歌单(3)      |       |\n");
	printf("|       |-------------------------|       |\n");
	printf("|       |        修改歌曲(4)      |       |\n");
	printf("|       |-------------------------|       |\n");
	printf("|                 返回(0)                 |\n");
	printf("|-----------------------------------------|\n");
	printf("请输入您要进行操作的序号:");
	int input = 0;
	scanf("%d", &input);
	system("cls");
	return input;
}

这就是整个信息管理系统的核心部分,对歌曲信息进行增删查改功能

因此,我们因该在Basic struct.cpp这个基础框架中添加选项,如下代码:

do
	{
		switch (input1 = Func_picture())
		{
		case 1:
			Search(&son);
			break;
		case 2:
			Hot();
			break;
		case 3:
			do
			{
				switch (input2 = Playlist_menu())//歌单
				{
				case 1:
					//增加歌曲
					Add_song(&son);
					Bubble_sort(&son);
					break;
				case 2:
					//删除歌曲
					Delete(&son);
					break;
				case 3:
					//查询歌曲
					Show_list(&son);
					break;
				case 4:
					//修改信息
					Modify(&son);
					break;
				case 0:
					break;
				default:
					printf("输入非法,请重新输入\n");
					break;
				}
			} while (input2);
			break;
		case 4:
				Home_page();
			break;
		case 5:
			Music(input1);
			break;
		case 0:
			printf("退出音乐\n");
			return 0;
		default:
			printf("输入非法,请重新输入!\n");
			break;
		}
	} while (input1);

先来看看添加歌曲

//增加歌曲
void Add_song(Song_library* son)
{
	assert(son != NULL);
	if (son->sz == MUSIC_MAX)
	{
		printf("歌曲库已满,无法添加\n");
	}
	else
	{
		FILE* write = NULL;
		if (son->sz == 0)
		{
			 write = fopen("歌曲库.txt", "w");
			if (write == NULL)
			{
				return;
			}
		}
		else
		{
			write = fopen("歌曲库.txt", "a");
			if (write == NULL)
			{
				return;
			}
		}
		printf("请输入歌曲名:");
		scanf("%s",&(son->arr[son->sz].Charname));
		printf("请输入作者:");
		scanf("%s", &(son->arr[son->sz].Charauthor));
		printf("请输入演唱者:");
		scanf("%s", &(son->arr[son->sz].Charsinger));
		printf("请输入发行时间:");
		scanf("%s", &(son->arr[son->sz].Charpub_date));

		//写入歌曲库
		fprintf(write, "%-10s\t", son->arr[son->sz].Charname);
		fprintf(write, "%-10s\t", son->arr[son->sz].Charauthor);
		fprintf(write, "%-10s\t", son->arr[son->sz].Charsinger);
		fprintf(write, "%-10s\t\n", son->arr[son->sz].Charpub_date);
		son->sz++;
		printf("添加成功!\n");
		fclose(write);
		write = NULL;
	}
}

想象一下,进入此模块,首先因该想到该歌曲库是否已经被填满

       接下来,要注意,不能只是简单的进行”w”操作,”w”为只写,我们每次往文件里添加歌曲的时候都会覆盖上一个创建的文件,如果没有文件,则会重新创建一个,所以这首先因该判断,如果歌曲库的歌曲个数为零,则可以通过”w”创建一个txt文件,倘若歌曲个数不为零,我们则可以通过”a”来追加

下一个功能:

删除歌曲

//删除歌曲
void Delete(Song_library* son)
{
	assert(son != NULL);
	char name[NAME_MAX] = { 0 };
	printf("请输入要删除的歌曲的名字:");
	scanf("%s", name);
	int ret = Find_song(son, name);//查找
	if (ret == -1)
	{
		printf("对不起,没有您要找的歌曲信息!\n");
	}
	else
	{
		int i = 0;  //从后向前覆盖
		for (i = ret; i < son-> sz - 1; i++)
		{
			son->arr[i] = son->arr[i + 1];
		}
		son->sz--;
		//重新写入文件
		FILE* write = fopen("歌曲库.txt", "w");
		if (write == NULL)
		{
			return;
		}
		for (i = 0; i < son->sz; i++)
		{
			fprintf(write, "%-10s\t", son->arr[i].Charname);
			fprintf(write, "%-10s\t", son->arr[i].Charauthor);
			fprintf(write, "%-10s\t", son->arr[i].Charsinger);
			fprintf(write, "%-10s\t\n", son->arr[i].Charpub_date);
		}
		printf("删除成功!\n");
		fclose(write);
		write = NULL;
	}
	system("pause");
	system("cls");
}

       输入的歌曲名通过数组存放,再用之前的查找函数Find_song进行搜索,没找到输出提示,找到了进行删除歌曲信息操作,如何删除呢,由于歌曲库未添加歌曲的地方被初始化成全0,所以通过从后向前覆盖的方式进行删除

下一个功能:

查找歌曲信息

//歌单列表
void Show_list(const Song_library* son)
{
	assert(son != NULL);
		FILE* read = fopen("歌曲库.txt", "r");
		if (read == NULL)
		{
			return;
		}
		int i = 0;
		for (i = 0; i < son->sz; i++)
		{
			fscanf(read, "%s", &(son->arr[i].Charname));
			fscanf(read, "%s", &(son->arr[i].Charauthor));
			fscanf(read, "%s", &(son->arr[i].Charsinger));
			fscanf(read, "%s", &(son->arr[i].Charpub_date));
		}
		printf("|------------------------------------------------------------|\n");
		printf("  %-18s\t%-8s\t%-8s\t%-11s\n", "歌曲名", "作词人", "演唱者", "日期");
		for (i = 0; i < son->sz; i++)
		{
			if (i % 10 == 0 && i != 0)
			{
				system("pause");
			}
			printf("  %-18s\t%-8s\t%-8s\t%-11s\n",
				son->arr[i].Charname,
				son->arr[i].Charauthor,
				son->arr[i].Charsinger,
				son->arr[i].Charpub_date);
		}
		printf("|------------------------------------------------------------|\n");
		system("pause");
		system("cls");
		fclose(read);
		read = NULL;
}

     通过fscanf函数从歌曲库中获取信息,再通过printf进行打印,分屏输出,每次10条歌曲信息

注意:

	for (i = 0; i < son->sz; i++)
		{
			if (i % 10 == 0 && i != 0)
			{
				system("pause");
			}

这里的 i = 0 时进入 i % 10 = 0 依然成立,所以这里要注意并且的条件

下一个功能:

修改歌曲信息

//修改
void Modify(Song_library* son)
{
	assert(son != NULL);
	char name[NAME_MAX] = { 0 };
	printf("请输入您要修改信息的歌曲名:");
	scanf("%s", name);
	int ret = Find_song(son, name);
	if (ret == -1)
	{
		printf("对不起,没有您要找的歌曲信息!\n");
	}
	else
	{
		FILE* modif = fopen("歌曲库.txt", "a");
		if (modif == NULL)
		{
			return;
		}
		printf("请输入歌曲名:");
		scanf("%s", &(son->arr[ret].Charname));
		printf("请输入作者:");
		scanf("%s", &(son->arr[ret].Charauthor));
		printf("请输入演唱者:");
		scanf("%s", &(son->arr[ret].Charsinger));
		printf("请输入发行时间:");
		scanf("%s", &(son->arr[ret].Charpub_date));

		//重新写入文件
		FILE* write = fopen("歌曲库.txt", "w");
		if (write == NULL)
		{
			return;
		}
		int i = 0;
		for (i = 0; i < son->sz; i++)
		{
			fprintf(write, "%-10s\t", son->arr[i].Charname);
			fprintf(write, "%-10s\t", son->arr[i].Charauthor);
			fprintf(write, "%-10s\t", son->arr[i].Charsinger);
			fprintf(write, "%-10s\t\n", son->arr[i].Charpub_date);
		}
		printf("修改成功!\n");
		fclose(write);
		write = NULL;
	}
	system("pause");
	system("cls");
}

     首先,通过查找歌曲函数先找到歌曲信息,然后对歌曲重新写入,覆盖之前的歌曲信息,最后修改成功并给予反馈

增删查改功能到这里就完成啦,为了让歌曲信息直观有序,继续创建一个模块

排序功能

//排序
void Bubble_sort(Song_library* son)
{
	assert(son != NULL);
	char tmp_name[NAME_MAX] = { 0 };
	//写入结构体数组
	int i = 0;
	for (i = 0; i < son->sz - 1; i++)
	{
		int j = 0;
		for (j = 0; j < son->sz - i - 1; j++)
		{
			if (strcmp(son->arr[j].Charname, son->arr[j + 1].Charname) > 0)
			{
				//名字
				strcpy(tmp_name, son->arr[j].Charname);
				strcpy(son->arr[j].Charname, son->arr[j + 1].Charname);
				strcpy(son->arr[j + 1].Charname, tmp_name);
				//作者
				strcpy(tmp_name, son->arr[j].Charauthor);
				strcpy(son->arr[j].Charauthor, son->arr[j + 1].Charauthor);
				strcpy(son->arr[j + 1].Charauthor, tmp_name);
				//演唱者
				strcpy(tmp_name, son->arr[j].Charsinger);
				strcpy(son->arr[j].Charsinger, son->arr[j + 1].Charsinger);
				strcpy(son->arr[j + 1].Charsinger, tmp_name);
				//发行日期
				strcpy(tmp_name, son->arr[j].Charpub_date);
				strcpy(son->arr[j].Charpub_date, son->arr[j + 1].Charpub_date);
				strcpy(son->arr[j + 1].Charpub_date, tmp_name);
			}
		}
	}
	//重新写入文件
	FILE* write = fopen("歌曲库.txt", "w");
	if (write == NULL)
	{
		return;
	}
	for (i = 0; i < son->sz; i++)
	{
		fprintf(write, "%-10s\t", son->arr[i].Charname);
		fprintf(write, "%-10s\t", son->arr[i].Charauthor);
		fprintf(write, "%-10s\t", son->arr[i].Charsinger);
		fprintf(write, "%-10s\t\n", son->arr[i].Charpub_date);
	}
	printf("修改成功!\n");
	fclose(write);
	write = NULL;

}

            比较首元素ASCII码值的大小,由小到大进行排序,创建一个临时数组    char tmp_name[NAME_MAX] = { 0 };  用来临时存放歌曲信息,方便交换,相当于你要交换一个油瓶和一个醋瓶中的液体一样,肯定是需要一个空瓶来临时存放的,这里的临时数组就相当于空瓶,最后重新写入文件,注意这里因该覆盖掉之前的文件内容;此功能可以放在增添歌曲功能的后面

如下代码:

				case 1:
					//增加歌曲
					Add_song(&son);
					Bubble_sort(&son);
					break;
				case 2:

最后一个模块

音乐播放

这里首先要保证是在cpp环境下进行,并且需要修改字符集,修改为使用多字节字符集,如下图

【C语言】软件开发基础篇--CL音乐

下一步,需要引用一些头文件

//加载音乐需要的头文件
#include<Windows.h>
#include<mmsystem.h>//包含多媒体设备接口头文件
#pragma comment (lib,"winmm.lib")//加载静态库

接着,将需要播放的音乐下载好,(注意:网易音乐不行,有加密),放在当前路径下

【C语言】软件开发基础篇--CL音乐

 接着如下代码

mciSendString("open 说好不哭.mp3 alias a", 0, 0, 0);// alias 是重命名
mciSendString("play a", 0, 0, 0);//播放刚刚被命名的a音乐

如果需要暂停音乐,可以用如下代码

mciSendString("close a", 0, 0, 0);

模仿音乐播放功能,就有了如下代码

//音乐播放
void Music(const int ret)
{
	int input = 0;
	if (ret == 1)
	{
		A:
		printf("|-----------------------------------------|\n");
		printf(" 正在为您播放“说好不哭”\n");
		mciSendString("close a", 0, 0, 0);
		mciSendString("close b", 0, 0, 0);
		mciSendString("close c", 0, 0, 0);
		mciSendString("open 说好不哭.mp3 alias a", 0, 0, 0);
		mciSendString("play a", 0, 0, 0);
		printf(" 播放(1)       关闭播放(2)       单曲循环(3)\n");
		printf("                 返回(0)\n");
		printf("|-----------------------------------------|\n");
	}
	else if (ret == 2)
	{
		B:
		printf("|-----------------------------------------|\n");
		printf(" 正在为您播放“不为谁而作的歌”\n");
		mciSendString("close a", 0, 0, 0);
		mciSendString("close b", 0, 0, 0);
		mciSendString("close c", 0, 0, 0);
		mciSendString("open 不为谁而作的歌.mp3 alias b", 0, 0, 0);
		mciSendString("play b", 0, 0, 0);
		printf(" 播放(1)       关闭播放(2)       单曲循环(3)\n");
		printf("                 返回(0)\n");
		printf("|-----------------------------------------|\n");
	}
	else if (ret == 3)
	{
		C:
		printf("|-----------------------------------------|\n");
		printf(" 正在为您播放“七里香”\n");
		mciSendString("close a", 0, 0, 0);
		mciSendString("close b", 0, 0, 0);
		mciSendString("close c", 0, 0, 0);
		mciSendString("open 七里香.mp3 alias c", 0, 0, 0);
		mciSendString("play c", 0, 0, 0);
		printf(" 播放(1)       关闭播放(2)       单曲循环(3)\n");
		printf("                 返回(0)\n");
		printf("|-----------------------------------------|\n");
	}
	while (1)
	{
		printf("请选择:");
		scanf("%d", &input);
		if (input == 1)
		{
			if (ret == 1)
			{
				system("cls");
				goto A;
			}
			else if (ret == 2)
			{
				system("cls");
				goto B;
			}
			else if (ret == 3)
			{
				system("cls");
				goto C;
			}
		}
		else if (input == 2)
		{
			if (ret == 1)
				mciSendString("close a", 0, 0, 0); 
			else if(ret == 2)
				mciSendString("close b", 0, 0, 0);
			else if(ret == 3)
				mciSendString("close c", 0, 0, 0);
		}
		else if (input == 3)
		{
			if (ret == 1)
				mciSendString("repeat a", 0, 0, 0); 
			else if (ret == 2)
				mciSendString("repeat b", 0, 0, 0);
			else if(ret == 3)
				mciSendString("repeat c", 0, 0, 0);
		}
		else if (input == 0)
		{
			break;
		}
	}
	system("cls");
}

这样一个基本的框架就建立好啦

码字不易~

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/129924.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!