作为基础篇,实现软件的那些功能呢?
a.构建基本框架
b.围绕歌曲信息的增删查改进行的
c.将内容通过文件操作存进文档
d.整理歌曲内容(排序)
e.实现简单的歌曲播放功能
有人可能就会问了,需要掌握C语言那些知识才能实现这些功能呢?
主要是 :数组,函数,指针,结构体,文件操作等知识即可.
接下来,带大家一起实操
首先,为了让部分功能分工明确,我们可以建立三个cpp文件,(播放音乐需要在c++的环境下)一个头文件,将他看成一个盖房子的过程:
CL-music.h 头文件(建筑图纸)
Basic struct.cpp 用来构建框架,地基
Function interface.cpp 功能界面(给建筑上色,标明门牌号)
play.cpp 实现各部分功能(家具)
首先从创建好的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环境下进行,并且需要修改字符集,修改为使用多字节字符集,如下图
下一步,需要引用一些头文件
//加载音乐需要的头文件
#include<Windows.h>
#include<mmsystem.h>//包含多媒体设备接口头文件
#pragma comment (lib,"winmm.lib")//加载静态库
接着,将需要播放的音乐下载好,(注意:网易音乐不行,有加密),放在当前路径下
接着如下代码
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");
}
这样一个基本的框架就建立好啦
码字不易~