0x00 脚下的路

不知道为啥要写这个小标题,可能是年轻的心想体验一下苍老的感觉,抑或是少年的一阵迷茫。混沌的四年,终究还是入了这一行。从初时的不知,到现在的刚开始,中间的间隔竟是四年之久,想起了陈奕迅的《十年》,但却不像医生所唱的十年那么有故事。或许这四年有这四年的价值,这四年也应有所积累。少年狂应少发,更不是什么老夫,当然也没有什么资格。之后的路应该在脚下,应是一步一步。比较喜欢的一句话,不去想目的地,才能轻松踏上旅途。少些心血来潮,多些精专。

聊以此记,舒心之惑,明己之志。

0x01 歌词解析

这是一个用c语言完成的小项目,大神们称之为玩具。不过对于对于知识的积累确有不小的作用。对于自己也是很好的训练,吃透每个小项目,吃透每一个细节,故总结之。

何为歌词解析?效果如何。刚开始必然是一片迷茫,可使用过各种播放器的我们应该对此熟悉。这是平日的歌曲播放器的部分截图:

管中窥豹,实现后的具体效果大致也应如此。当然,歌词解析吗?更应该了解歌词是什么样子的,有什么样子的格式(我们都明白,一切的神秘下面都隐藏着简单的道理)。这是某个词文件的部分截图:

如此,大致便可有些许想法了:将歌词文件读取出来,逐行显示在屏幕上,并随着歌曲播放时间逐行滚动。

0x02 流程分析

通过观察歌词,可以想到使用链表存储歌词信息比较方便,因为歌词要一行一行显示,并且事先并不了解每首歌的歌词有多少句。可以将歌词的每一句存入链表的一个节点。

整个流程大致可以分为如下几块:

读取歌词文件

按行切割歌词文件

逐行分析歌词头部歌曲信息部分

逐行分析歌词正文部分,并根据每行歌词前的时间将歌词插入链表

模拟时钟,根据时间显示歌词和播放歌曲

歌词滚屏,歌词反显(当前歌词突出显示)

0x03 读取歌词文件

文本文件的读取大致分如下步骤:

打开歌词文件

计算歌词文件的大小

分配内存空间

将歌词读入内存

关闭歌词文件

/*读取歌词*/

void read_lrc(char *p_lrc, char **lrc_data)

{

/*打开歌词文件*/

FILE *fp = fopen(p_lrc, "r");

if(fp == NULL)

{

perror("fopen");

return;

}

/*计算歌词文件的大小*/

fseek(fp, 0, 2);

long lrc_len = ftell(fp);

rewind(fp);

/*分配内存空间*/

*lrc_data = (char *)calloc(1, lrc_len);

if(*lrc_data == NULL)

{

perror("ralloc");

return;

}

/*将歌词读入内存*/

fread(*lrc_data, lrc_len, 1, fp);

/*关闭文件*/

fclose(fp);

return;

}

0x04 按行切割歌词文件

歌词切割应注意如下(百度百科):

/*将歌词逐行分割*/

void lrctok(char ** buf, char *lrc_data)

{

buf[0] = lrc_data;

int i = 0;

while((buf[i] = (char *)strtok(buf[i], "\r\n")))

i++;

return;

}

0x05 逐行分析歌词头部

歌词头部信息格式(百度百科):

由于头部信息比较简单,所以并不把头部信息存入链表,而是直接分析后显示:

/*分析歌词头部信息*/

int analysis_lrc_head(char **buf)

{

clear_screen();

cusor_moveto(0, 0);

set_fg_color(COLOR_GREEN);

/*逐行分析头部*/

int i = 0;

while(*(buf[i] + 1) > '0')/*解释歌词信息*/

{

/*读取头部信息内容*/

char lrc[128]="";

sscanf(buf[i],"%*[^:]:%[^]]", lrc);

/*读取头部信息标签*/

char tags[10] = "";

sscanf(buf[i], "[%[^:]", tags);

cusor_moveto(35, i+1);

if(strcmp(tags, "ti") == 0)

{

printf("歌名:");

}

else if(strcmp(tags, "ar") == 0)

{

printf("歌手:");

}

else if(strcmp(tags, "al") == 0)

{

printf("专辑:");

}

else if(strcmp(tags, "by") == 0)

{

printf("制作:");

}

else if(strcmp(tags, "offset") == 0)

{

printf("offset:");

}

printf("%s\n", lrc);

i++;

}

//printf("%d\n", i);

return i;

}

0x06 逐行分析歌词正文

对于歌词正文部分,要处理的有两个方面:一方面分析每句歌词前面的时间,另一方面,将根据前面的时间将歌词插入链表。

/*分析歌词正文部分*/

int analysis_lrc_body(char **buf,int star_num, List *list)

{

int i = star_num;/*从头部信息之后开始分析*/

while(buf[i])/*解析歌词正文*/

{

char *str_lrc = buf[i];

while(*str_lrc == '[')/*寻找歌词位置*/

str_lrc +=10;

//printf("%s\n", str_lrc);/*打印当前歌词测试*/

char *str_time = buf[i];/*解析每句歌词前的时间*/

while(*str_time == '[')

{

int m = 0,s = 0;

sscanf(str_time,"[%d:%d.%*d]", &m, &s);

int time = m*60+s;//以秒为单位

/*将时间和歌词 --对应 放入结构体*/

LRC *tmp = (LRC *)calloc(1, sizeof(LRC));

if(tmp == NULL)

{

perror("calloc");

return i;

}

tmp->time = time;

strcpy(tmp->lrc, str_lrc);

//调用链表的有序插入函数

list_ins_sort(list, tmp);

//分析下一个时间

str_time += 10;

}

i++;

}

return i;

}

0x07 模拟时钟

使用模拟时钟的目的是模拟实现歌曲播放与歌词同步,模拟时钟和歌曲播放器同时启动,然后根据模拟时钟的时间在歌词链表中查找。

int i = 0;/*模拟计时器*/

while(1)

{

/*根据时间i到链表中查找,并且打印歌词*/

time_delay(1);

i++;

}

0x08 歌词滚屏、歌词反选

/*模拟时钟*/

int i = 0;/*模拟计时器*/

char show[5][128] = {"","","","",""};

while(1)

{

/*显示进度条*/

int base = 15;/*进度条从第base列起始*/

set_fg_color(COLOR_RED);

cusor_moveto(base, line + 9);

printf("%02d:%02d|",i/60,i%60);/*以mm:ss格式打印时间*/

fflush(stdout);

int endtime = ((LRC *)(list.tail->data))->time;

int length = (i*1.0)/endtime*45;

cusor_moveto(base + 6, line + 9);

int j = 0;

for(; j < length; j++)

{

printf(">");

}

cusor_moveto(base + 51, line + 9);

printf("|%02d:%02d",endtime/60, endtime%60);

/*查找此时的歌词*/

int offset = 0;/*调整歌词与歌曲同步偏差*/

LRC tmp;/*按时间查找歌词*/

tmp.time = i + offset;/*初始化查找时间*/

strcpy(tmp.lrc, "");

Node *ret = list_search(&list, &tmp);/*返回查找歌词在链表中的位置*/

if(ret != NULL)

{

/*滚动显示歌词*/

strcpy(show[0], show[1]);

strcpy(show[1], show[2]);

strcpy(show[2], show[3]);

strcpy(show[3], show[4]);

strcpy(show[4], ((LRC *)(ret->data))->lrc);

cusor_moveto(30, line+2);

set_fg_color(COLOR_WHITE);

printf("%s \n", show[0]);

fflush(stdout);

cusor_moveto(30, line+3);

printf("%s \n", show[1]);

fflush(stdout);

cusor_moveto(30, line+4);

printf("%s \n", show[2]);

fflush(stdout);

cusor_moveto(30, line+5);

printf("%s \n", show[3]);

fflush(stdout);

cusor_moveto(30, line+6);

set_fg_color(COLOR_BLUE);

printf("%s \n", show[4]);

set_fg_color(COLOR_WHITE);

fflush(stdout);

if(ret->next == NULL)

{

cusor_moveto(0, line+25);

cusor_show();

break;

}

}

time_delay(1);

i++;

}

0x09 运行结果

0x10 全部程序

[my_lrc]tree

.

├── list

│   ├── list.c

│   └── list.h

├── lrc

│   ├── coffe.lrc

│   ├── 邓紫棋-存在.lrc

│   ├── 邓紫棋-喜欢你.lrc

│   └── 简单爱.lrc

├── lrc.c

├── lrc.h

├── main

├── main.c

├── makefile

├── mplayer

│   ├── start_mplayer.c

│   └── start_mplayer.h

├── pos

│   ├── console.c

│   └── console.h

├── song

│   ├── coffe.mp3

│   ├── 邓紫棋-存在.mp3

│   ├── 邓紫棋-喜欢你.mp3

│   └── 简单爱.mp3

└── time_delay

├── time_delay.c

└── time_delay.h

makefile

CC=gcc

obj=main.o lrc.o list.o start_mplayer.o console.o time_delay.o list.o

target=main

CFLAGS=-Wall

$(target):$(obj)

@$(CC) $^ -o $@ $(CFLAGS)

main.o:main.c

@$(CC) -c $< -o $@ $(CFLAGS)

lrc.o:lrc.c

@$(CC) -c $< -o $@ $(CFLAGS)

start_mplayer.o:./mplayer/start_mplayer.c

@$(CC) -c $< -o $@ $(CFLAGS)

console.o:./pos/console.c

@$(CC) -c $< -o $@ $(CFLAGS)

time_delay.o:./time_delay/time_delay.c

@$(CC) -c $< -o $@ $(CFLAGS)

list.o:./list/list.c

@$(CC) -c $< -o $@ $(CFLAGS)

clean:

@rm $(obj) -rf

main.c

#include

#include

#include

#include "time_delay/time_delay.h"

#include "mplayer/start_mplayer.h"

#include "list/list.h"

#include "pos/console.h"

#include "lrc.h"

int main(int argc, char *argv[])

{

/读取歌词文件/

char *lrc_data = NULL;

read_lrc("./lrc/coffe.lrc", &lrc_data);

/*将歌词按行分割*/

char *buf[128]={NULL};

lrctok(buf, lrc_data);

/*逐行解析歌词*/

List list;/*创建歌词链表*/

list_init(&list, destroy, print, time_cmp);

cusor_hide();

int line = analysis_lrc_head(buf);/*分析歌词头部信息*/

analysis_lrc_body(buf, line, &list);/*分析歌词正文*/

//print_list(&list);/*打印歌词链表调试*/

/*启动maplayer*/

mplayer_play("./song/coffe.mp3");

/*模拟时钟*/

int i = 0;/*模拟计时器*/

char show[5][128] = {"","","","",""};

while(1)

{

/*显示进度条*/

int base = 15;/*进度条从第base列起始*/

set_fg_color(COLOR_RED);

cusor_moveto(base, line + 9);

printf("%02d:%02d|",i/60,i%60);/*以mm:ss格式打印时间*/

fflush(stdout);

int endtime = ((LRC *)(list.tail->data))->time;

int length = (i*1.0)/endtime*45;

cusor_moveto(base + 6, line + 9);

int j = 0;

for(; j < length; j++)

{

printf(">");

}

cusor_moveto(base + 51, line + 9);

printf("|%02d:%02d",endtime/60, endtime%60);

/*查找此时的歌词*/

int offset = 0;/*调整歌词与歌曲同步偏差*/

LRC tmp;/*按时间查找歌词*/

tmp.time = i + offset;/*初始化查找时间*/

strcpy(tmp.lrc, "");

Node *ret = list_search(&list, &tmp);/*返回查找歌词在链表中的位置*/

if(ret != NULL)

{

/*滚动显示歌词*/

strcpy(show[0], show[1]);

strcpy(show[1], show[2]);

strcpy(show[2], show[3]);

strcpy(show[3], show[4]);

strcpy(show[4], ((LRC *)(ret->data))->lrc);

cusor_moveto(30, line+2);

set_fg_color(COLOR_WHITE);

printf("%s \n", show[0]);

fflush(stdout);

cusor_moveto(30, line+3);

printf("%s \n", show[1]);

fflush(stdout);

cusor_moveto(30, line+4);

printf("%s \n", show[2]);

fflush(stdout);

cusor_moveto(30, line+5);

printf("%s \n", show[3]);

fflush(stdout);

cusor_moveto(30, line+6);

set_fg_color(COLOR_BLUE);

printf("%s \n", show[4]);

set_fg_color(COLOR_WHITE);

fflush(stdout);

if(ret->next == NULL)

{

cusor_moveto(0, line+25);

cusor_show();

break;

}

}

time_delay(1);

i++;

}

/*释放空间*/

if(lrc_data != NULL)

{

free(lrc_data);

lrc_data = NULL;

}

list_destroy(&list);

return 0;

}

lrc.h

#ifndef __LRC_H__

#define __LRC_H__

#include "list/list.h"

typedef struct lrc

{

//数据域

int time;

char lrc[128];

}LRC;

extern void print(const void *data);/打印歌词结构体/

extern int time_cmp(const void *key1, const void *key2);/歌词结构的比较,按时间比较/

extern void destroy(void *data);/歌词结构体空间的释放/

extern void read_lrc(char *p_lrc, char **lrc_data);/读取歌词文件,将内容写入制定内存空间,函数外部分配空间/

extern void lrctok(char ** buf, char *lrc_data);/逐行分割歌词/

extern int analysis_lrc_head(char **buf);/分析歌词头部信息/

extern int analysis_lrc_body(char **buf,int star_num, List *list);/分析歌词正文信息/

#endif //LRC_H

lrc.c

#include

#include

#include

#include "lrc.h"

#include "list/list.h"

#include "pos/console.h"

/定义歌词结构的打印方式/

void print(const void *data)

{

LRC *lrc_data = (LRC *)data;

printf("%s\n", lrc_data->lrc);

return;

}

/定义歌词结构的比较方式,此处以时间比较/

int time_cmp(const void *key1, const void *key2)

{

LRC *tm1 = (LRC *)key1;

LRC *tm2 = (LRC *)key2;

if(tm1->time > tm2->time)

return 1;

else if(tm1->time < tm2->time)

return -1;

else

return 0;

}

/定义歌词结构的空间的释放方式/

void destroy(void *data)

{

if(data != NULL)

{

free(data);

data = NULL;

}

return;

}

/读取歌词/

void read_lrc(char *p_lrc, char **lrc_data)

{

/打开歌词文件/

FILE *fp = fopen(p_lrc, "r");

if(fp == NULL)

{

perror("fopen");

return;

}

/*计算歌词文件的大小*/

fseek(fp, 0, 2);

long lrc_len = ftell(fp);

rewind(fp);

/*分配内存空间*/

*lrc_data = (char *)calloc(1, lrc_len);

if(*lrc_data == NULL)

{

perror("ralloc");

return;

}

/*将歌词读入内存*/

fread(*lrc_data, lrc_len, 1, fp);

/*关闭文件*/

fclose(fp);

return;

}

/将歌词逐行分割/

void lrctok(char ** buf, char *lrc_data)

{

buf[0] = lrc_data;

int i = 0;

while((buf[i] = (char *)strtok(buf[i], "\r\n")))

i++;

return;

}

/分析歌词头部信息/

int analysis_lrc_head(char **buf)

{

clear_screen();

cusor_moveto(0, 0);

set_fg_color(COLOR_GREEN);

/*逐行分析头部*/

int i = 0;

while(*(buf[i] + 1) > '0')/*解释歌词信息*/

{

/*读取头部信息内容*/

char lrc[128]="";

sscanf(buf[i],"%*[^:]:%[^]]", lrc);

/*读取头部信息标签*/

char tags[10] = "";

sscanf(buf[i], "[%[^:]", tags);

cusor_moveto(35, i+1);

if(strcmp(tags, "ti") == 0)

{

printf("歌名:");

}

else if(strcmp(tags, "ar") == 0)

{

printf("歌手:");

}

else if(strcmp(tags, "al") == 0)

{

printf("专辑:");

}

else if(strcmp(tags, "by") == 0)

{

printf("制作:");

}

else if(strcmp(tags, "offset") == 0)

{

printf("offset:");

}

printf("%s\n", lrc);

i++;

}

//printf("%d\n", i);

return i;

}

/分析歌词正文部分/

int analysis_lrc_body(char **buf,int star_num, List *list)

{

int i = star_num;/从头部信息之后开始分析/

while(buf[i])/解析歌词正文/

{

char *str_lrc = buf[i];

while(*str_lrc == '[')/*寻找歌词位置*/

str_lrc +=10;

//printf("%s\n", str_lrc);/*打印当前歌词测试*/

char *str_time = buf[i];/*解析每句歌词前的时间*/

while(*str_time == '[')

{

int m = 0,s = 0;

sscanf(str_time,"[%d:%d.%*d]", &m, &s);

int time = m*60+s;//以秒为单位

/*将时间和歌词 --对应 放入结构体*/

LRC *tmp = (LRC *)calloc(1, sizeof(LRC));

if(tmp == NULL)

{

perror("calloc");

return i;

}

tmp->time = time;

strcpy(tmp->lrc, str_lrc);

//调用链表的有序插入函数

list_ins_sort(list, tmp);

//分析下一个时间

str_time += 10;

}

i++;

}

return i;

}

mplayer_play.h

#ifndef __START_MPLAYER_H__

#define __START_MPLAYER_H__

//启动mplayer播放器

//参数song_path 为歌曲的路径

extern void mplayer_play(char * song_path);

#endif

mplayer_play.c

#include

#include

#include

//启动mplayer播放器

//参数song_path 为歌曲的路径

void mplayer_play(char * song_path)

{

pid_t pid;

pid=fork();

if(pid<0)

{

perror("fork");

}

else if(pid==0)

{

close(1);

close(2);

execlp("mplayer","mplayer","-slave","-quiet",song_path,NULL);

exit(0);

}

else

;

}

console.h

#ifndef _CONSOLE_H_

#define _CONSOLE_H_

#define COLOR_RED 31

#define COLOR_BLACK 30

#define COLOR_GREEN 32

#define COLOR_BLUE 34

#define COLOR_YELLOW 33

#define COLOR_WHITE 37

#define COLOR_CYAN 36

#define COLOR_MAGENTA 35

/*

COLOR_RED 红

COLOR_BLACK 黑

COLOR_GREEN 绿

COLOR_BLUE 蓝

COLOR_YELLOW 黄

COLOR_WHITE 白

COLOR_CYAN 青

COLOR_MAGENTA 洋红

*/

extern void cusor_moveto(int x, int y);//光标跳转到 y行 x列

extern void cusor_get_pos(void);//保存光标位置

extern void cusor_hide(void);//隐藏光标

extern void cusor_show(void);//显示光标

extern void cusor_set_pos(void);//恢复光标位置

extern void clear_screen(void);//清屏

extern void set_fg_color(int color);//设置字体前景色

extern void set_bg_color(int color);//设置字体背景色

#endif //CONSOLE_H

console.c

#include

#include

#include "console.h"

void cusor_moveto(int x, int y)

{// ESC[y;xH

printf("\033[%d;%dH",y,x);

fflush(stdout);

}

//保存光标位置

void cusor_get_pos(void)

{// ESC[s

printf("\033[s");

fflush(stdout);

}

//恢复光标位置

void cusor_set_pos(void)

{// ESC[u

printf("\033[u");

fflush(stdout);

}

//隐藏光标

void cusor_hide(void)

{

printf("\033[?25l");

}

//显示光标

void cusor_show(void)

{

printf("\33[?25h");

}

//清屏

void clear_screen(void)

{// ESC[2J

printf("\033[2J");

fflush(stdout);

}

/*

COLOR_RED 红

COLOR_BLACK 黑

COLOR_GREEN 绿

COLOR_BLUE 蓝

COLOR_YELLOW 黄

COLOR_WHITE 白

COLOR_CYAN 青

COLOR_MAGENTA 洋红

*/

//设置前景颜色

void set_fg_color(int color)

{// ESC[#m

printf("\033[%dm",color);

fflush(stdout);

}

//设置背景颜色

void set_bg_color(int color)

{// ESC[#m

printf("\033[%dm",(color+10));

fflush(stdout);

}

time_delay.h

#ifndef __TIME_DELAY__

#define __TIME_DELAY__

extern void time_delay(int sec);

#endif //TIME_DELAY

time_delay.c

#include

#include

void time_delay(int sec)

{

int s_time,e_time;

s_time=time(NULL);

while(1)

{

e_time=time(NULL);

if(e_time==s_time+sec)

break;

}

}

list.h

#ifndef LINK_H

#define LINK_H

typedef struct node//链表元素的结构

{

void *data;/节点中的数据域,设置为无类型指针,数据类型大小由使用者定义/

struct node *next;/指向下一节点的指针/

}Node;

typedef struct list/链表的结构/

{

int size;/链表中节点个数/

void (*destroy)(void *data);/由于链表节点中的数据是用户自定义的,故需要调用者提供释放空间的函数/

void (*print_data)(const void *data);/同,由用户自定义打印数据的函数/

int (*match)(const void *key1, const void *key2);/同,由用户自定义数据的比较方式/

Node *head;/*记录链表的头部位置*/

Node *tail;/*记录链表的尾部位置*/

}List;

extern void list_init(List *list, void (*destroy)(void *data), void (*print_data)(const void *data),

int (*match)(const void *key1, const void *key2));/初始化一个链表/

extern int list_ins_head(List *list, const void *data);/链表的插入,将节点从头部插入/

extern int list_ins_tail(List *list, const void *data);/链表的插入,将节点从尾部插入/

extern int list_ins_sort(List *list, const void data);/链表的插入,插入后链表是一个有序的链表/

extern void list_search(List *list, const void data);/在链表中查找指定数据,若找到返回链表中的位置/

extern void list_remove(List *list, const void *data);/在链表中删除指定数据,若找到删除节点并将数据地址返回/

extern void list_reverse(List list);//将链表逆置/

extern void list_sort(List *list);/将链表按照一定方式排序/

extern void print_list(List *list);/打印链表/

extern void list_destroy(List *list);/删除整个链表/

#define list_size(list) (list->size) /返回链表节点个数/

#endif // LINK_H

list.c

#include "list.h"

#include

#include

#include

/初始化链表/

void list_init(List *list, void (*destroy)(void *data), void (*print_data)(const void *data),

int (*match)(const void *key1, const void *key2))

{

list->size = 0;

list->head = NULL;

list->tail = NULL;

list->match = match;

list->destroy = destroy;

list->print_data = print_data;

return;

}

/打印整个链表/

void print_list(List *list)

{

if(list->head == NULL)//链表为空

{

printf("list is empty\n");

}

else //链表非空

{

Node * p_cur = list->head;

while (p_cur)/*遍历链表*/

{

list->print_data(p_cur->data);

p_cur = p_cur->next;

}

}

return;

}

/在链表的头部插入数据/

int list_ins_head(List *list, const void *data)

{

Node *new_node = (Node *)calloc(1, sizeof (Node)); //创建插入的节点

if(new_node == NULL)

return -1;

new_node->data = (void *)data;//关联节点与数据

/*

if(list_size(list) == 0)//链表为空时,插入节点

{

list->tail = new_node;

new_node->next = NULL;

list->head = new_node;

}

else //链表非空时将节点插入头部

{

new_node->next = list->head;

list->head = new_node;

}

*/

if(list_size(list) == 0)//链表为空时,插入节点

list->tail = new_node;

new_node->next = list->head;

list->head = new_node;

list->size ++;

return 0;

}

/在链表的尾部插入数据/

int list_ins_tail(List *list, const void *data)

{

Node *new_node = (Node *)calloc(1, sizeof (Node)); //创建插入的节点

if(new_node == NULL)

return -1;

new_node->data = (void *)data;//关联节点与数据

if(list_size(list) == 0)

list->head = new_node;

else

list->tail->next = new_node;

list->tail = new_node;

new_node->next = NULL;

list->size ++;

return 0;

}

/在链表的有序插入数据/

int list_ins_sort(List *list, const void *data)

{

Node *new_node = (Node *)calloc(1, sizeof (Node)); //创建插入的节点

if(new_node == NULL)

return -1;

new_node->data = (void *)data;//关联节点与数据

if(list_size(list) == 0)//链表为空时,插入节点

{

list->tail = new_node;

new_node->next = NULL;

list->head = new_node;

}

else//链表非空时

{

Node *p_cur = list->head;

Node *p_pre = list->head;

while(p_cur != NULL && list->match(new_node->data, p_cur->data) > 0)//查找链表的插入位置

{

p_pre = p_cur;

p_cur = p_cur->next;

}

if(p_cur != NULL)//插入位置在头部和中间时

{

if(p_cur == list->head)//插入位置在头部

{

new_node->next = list->head;

list->head = new_node;

}

else//位置在链表中间

{

new_node->next = p_pre->next;

p_pre->next = new_node;

}

}

else//插入位置在链表尾部

{

list->tail->next = new_node;

list->tail = new_node;

new_node = NULL;

}

}

list->size ++;

return 0;

}

/查找链表中与数据匹配的节点,并返回节点指针/

void* list_search(List *list, const void *data)

{

if(list_size(list) == 0)

{

printf("list is empty\n");

return NULL;

}

else

{

Node *p_cur = list->head;

while(p_cur != NULL && list->match(p_cur->data, data) != 0)//查找数据在链表中的位置

{

p_cur = p_cur->next;

}

return p_cur;

}

}

/删除指定数据的节点/

void* list_remove(List *list, const void *data)

{

void *old_data = NULL;

Node *p_cur = list->head;

Node *p_pre = list->head;

while (p_cur != NULL && list->match(p_cur->data, data) !=0)

{

p_pre = p_cur;

p_cur = p_cur->next;

}

if(p_cur != NULL && list->match(p_cur->data, data) ==0)//删除位置在头部和中间时

{

if(p_cur == list->head)//删除位置在头部

{

list->head = p_cur->next;

if(p_cur->next == NULL)

list->tail = NULL;

}

else//中部时或尾部

{

p_pre->next = p_cur->next;

if(p_cur->next == NULL)

list->tail = p_pre;

}

old_data = p_cur->data;

free(p_cur);

list->size --;

}

return old_data;

}

/将链表逆置/

void list_reverse(List *list)

{

if(list_size(list) != 0)

{

Node *p_pre = list->head;

Node *p_cur = list->head->next;

list->head->next = NULL;

list->tail = list->head;

while(p_cur!= NULL)

{

p_pre = p_cur;

p_cur = p_cur->next;

p_pre->next = list->head;

list->head = p_pre;

}

}

return;

}

/给链表排序/

void list_sort(List *list)

{

if(list_size(list) != 0)

{

Node *p_i = list->head;

while(p_i->next != NULL)

{

Node *p_min = p_i;

Node *p_j = p_min->next;

while (p_j != NULL)

{

if(list->match(p_min->data, p_j->data) > 0)

p_min = p_j;

p_j = p_j->next;

}

if(p_min != p_i)

{

void *data = p_i->data;

p_i->data = p_min->data;

p_min->data = data;

}

p_i = p_i->next;

}

}

return;

}

/摧毁链表/

void list_destroy(List *list)

{

Node *p_cur = list->head;

while (p_cur != NULL)

{

list->head = list->head->next;

list->destroy(p_cur->data);//释放节点中的数据

free(p_cur);//释放节点

p_cur = list->head;

}

memset(list, 0, sizeof (List));

return;

}

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[C语言之歌词解析]http://www.zyiz.net/tech/detail-121858.html

歌词模拟项目c语言,C语言之歌词解析相关推荐

  1. c语言数码管数字时钟程序,数码管显示模拟8位时钟C语言程序设计

    原标题:数码管显示模拟8位时钟C语言程序设计 //数码时钟设计 #include // 包含寄存器定义的头文件 unsigned char Tab[ ]={0xc0,0xf9,0xa4,0xb0,0x ...

  2. java的开源项目哪里找,我想参加开源项目的开发,请问在网上去哪找这样的项目? 纯C语言的(非C++或JAVA)...

    我想参加开源项目的开发,请问在网上去哪找这样的项目? 纯C语言的(非C++或JAVA)以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起 ...

  3. 让数组的左边全为奇数C语言,2015年全国计算机等级考试全真模拟考场_二级C语言试卷四.docx...

    2015年全国计算机等级考试全真模拟考场_二级C语言试卷四 全国计算机等级考试全真模拟试卷(4) 二级C (考试时间l20分钟,满分100分) 一.选择题(每小题1分,共40分) (1)算法是指( ) ...

  4. 单片机交通灯灯c语言程序,关于LED模拟交通灯单片机C语言程序设计 - 全文

    本文为大家带来三个关于LED模拟交通灯单片机C语言程序设计. 关于LED模拟交通灯单片机C语言程序设计一 功能说明 东西向绿灯亮若干秒,黄灯闪烁5次后红灯亮,红灯亮后,南北向由红灯变为绿灯,若干秒后南 ...

  5. 反思:项目开发中的语言沟通与文档沟通

    反思:项目开发中的语言沟通与文档沟通 问题引出:刚进入公司试用期,有导师安排开发实现一些功能模块或者小的应用.毕竟需要在整个产品的框架下添加代码,看了下整个产品近1G的源代码,相当浩瀚.虽然是不需要我 ...

  6. 操作系统大作业 基于Linux的模拟进程调度算法 运用c++语言编程 在VMware虚拟机里 centos 亲自写亲自测试 代码 说明书

    发布文章 博文管理我的博客退出 Trash Temp 操作系统大作业 基于Linux的模拟进程调度算法 运用c++语言编程 在VMware虚拟机里 centos 亲自写亲自测试 代码 说明书 @[TO ...

  7. 欧姆龙PLC ST语言6轴伺服RS232C通讯板CP1W-C IF0 真实项目程序,ST语言写的FB块

    欧姆龙PLC ST语言6轴伺服RS232C通讯板CP1W-C IF0 真实项目程序,ST语言写的FB块 PLC用是两台CP1H-X40DT-D配置4块RS232C通讯板CP1W-CIF01 触摸屏是N ...

  8. 关于c语言排序计时器完整程序,先来先服务调度算法模拟实验程序源代码(C语言)...

    先来先服务调度算法模拟实验程序源代码(C语言) 下载提示(请认真阅读)1.请仔细阅读文档,确保文档完整性,对于不预览.不比对内容而直接下载带来的问题本站不予受理. 2.下载的文档,不会出现我们的网址水 ...

  9. 【译】将 Android 项目迁移到 Kotlin 语言

    本文讲的是[译]将 Android 项目迁移到 Kotlin 语言, 原文地址:Migrating an Android project to Kotlin 原文作者:Ben Weiss 译文出自:掘 ...

  10. Xamarin XAML语言教程XAML文件结构与解析XAML

    Xamarin XAML语言教程XAML文件结构与解析XAML XAML文件结构 在上文中,我们创建XAML文件后,会看到类似图1.16所示的结构 图1.16  结构 其中,.xaml文件和.xaml ...

最新文章

  1. http 错误 404.0 - not found_python3从零学习-5.10.8、http.client—HTTP 协议客户端
  2. 自己写 localtime 函数(含完整注释,代码)转载
  3. Windows Server 2008 R2 如何启用WINS服务
  4. RTL8111H-CG规格书 DATASHEET
  5. 阿里云CentOS7.3搭建多用户私有git服务器(从安装git开始)
  6. TFS创建团队项目(三)
  7. Excel VBA 处理图形图表详解
  8. json规范及转义字符
  9. python二元函数拟合_Python拟合二元一次函数
  10. 计算机第二章测试题及答案,计算机组成原理第二章练习题及答案
  11. 官方发布 激情世界杯】浩海技术 GHOST XP SP3 世界杯装机特别版★用稳定压倒一切!...
  12. 二年级课程表(4月2日-4月8日)
  13. 计算机电源的正确连接顺序是什么意思,先插电脑还是先插电源?插入顺序你知道吗?...
  14. MATLAB提取不规则txt文件中的数值数据(简单且实用)
  15. 支持Tasker控制的app合集
  16. 你知道数据运营日常主要工作吗?
  17. ioDraw - 免费的在线图表制作工具
  18. 超级表格教你怎样“零”成本制作签到系统
  19. 在一台电脑上如何安装两个JDK,并实现自由切换
  20. 新媒体运营胡耀文教程:浅谈ToB市场精细化运营

热门文章

  1. ppt 计算机图标不见了,显示桌面图标不见了如何恢复.ppt
  2. 对一个list进行乱序处理
  3. flutter版本升级
  4. html 广告加载页面,JS广告代码延迟加载或是最后加载加快页面载入
  5. webview的白屏,和硬件加速
  6. 玛雅历 —— C++
  7. Python中使用snip问题
  8. tomcat10 实例化servlet 500错误解决办法
  9. 阿里云OSS线程增长问题分析
  10. (基础)SpringCloud Alibaba Nacos作为多环境配置中心