设计题目1 统计热词
【实验目的】
1.熟悉Linux(Ubuntu版本)的登录和退出、命令及使用格式和常用基本操作命令;
2.练习并熟练使用Linux提供的vi编辑器;
3.练习并熟练使用Linux操作系统下最常用的C语言编译器gcc;
4.练习掌握Linux操作系统下最常用的代码调试器gdb的使用和调试代码的基本方法;
5.学习使用make命令和Makefile文件。
【实验要求】
统计某篇或某几篇文章中出现次数最多的单词。
【涉及的背景知识及采用的函数概述】
1、Lolcat命令
Lolcat 是一个针对 Linux,BSD 和 OSX 平台的工具,它类似于 cat 命令,并为 cat 的输出添加彩虹般的色彩。 Lolcat 主要用于在 Linux 终端中为文本添加彩虹般的色彩。
点击打开链接这个教程很好。
2、pthread介绍
包括一个pthread.h头文件和一个线程创建
编译方法
gcc -o ** **.c –lpthread
或
g++ -o ** **.cpp -lpthread
3、Makefile
在Makefile 中由#开始的行都是注释行。Makefile 中最重要的是描述文件的依赖关系的说明。一般的格式是:
target: components
TAB rule
第一行表示的是依赖关系。第二行是规则.
比如说我们上面的那个Makefile 文件的第二行
main:main.o mytool1.o mytool2.o
表示我们的目标(target)main 的依赖对象(components) 是main.o mytool1.o mytool2.o 当依赖的对象在目标修改后修改的话,就要去执行规则一行所指定的命令,就象我们的上面那个Makefile 第三行所说的一样要执行
gcc -o main main.o mytool1.o mytool2.o
注意规则一行中的TAB 表示那里是一个TAB 键
【题目设计思路】
(1)给定几篇文章的目录,调用多个线程统计出出现次数最多的前10个单词分别时什么.关于这个问题首先比较难的是如何找到给定的目录和如何保存统计出的字符串,这里我用到很多C++ STL中封装好的库,比如 map<>,string ,vector pair,等等.这样很方便存储和读取字符串了,我们将所有统计的字符串从map中取出放入vector,然后排序输入即可.
(2)将统计结果存入answer.txt中,然后通过lolcat命令以彩虹般的颜色输出来。
【调试过程问题分析】
统计用的文章是从网上随机下载的,包含各种文字字符。
(1)在生成makefile文件时,由于使用很多STL,在每个.cpp文件中加入前面定义过的变量会出现重定义的情况,可能c++特殊,在c语言中一般不会出现这种情况.
解决方法: 将已经定义过的变量声明为extern就可以解决了,表示沿用上一个的.这样便不用再次开辟空间。
(2)安装lolcat时,虚拟机不能连外网,安装出现权限问题等问题,均通过百度解决。
https://jingyan.baidu.com/album/6c67b1d68facbb2786bb1e7b.html?picindex=2
(3)Execl传参出现问题,第一个参数必需包含路径,可通过whereis lolcat来查看lolcat安装路径。
(4)写入文件用的freopen用法及注意问题。
freopen:
1)头文件:stdio.h
2)功 能: 替换一个流,或者说重新分配文件指针,实现重定向。
3)用 法: FILE *freopen(char *filename, char *type, FILE *stream);
filename是文件的名字,若无此文件则自行创建;
type是权限 “w”写,“r”读;
stream是流,stdout是输出流,stdin是输入流;
char str1[]="rank: word quantity";
freopen("answer.txt","w",stdout);//把输出到屏幕的文本输出到一个文本文件中
cout<<str1<<endl;//直接使用cout写入文件
int cnt=0;
for(vtt = vt.begin();vtt != vt.end();vtt++)
{
if(cnt==10)
break;
cout<<"\t"<<vtt->first<<"\t";
cout<<vtt->second<<endl;
cnt++;
}
freopen("/dev/tty","w",stdout);//注意一定要加这句话,将重定向解除,否则最后输不出(不能在终端显示出来)。
execl("/usr/games/lolcat","lolcat","answer.txt",NULL);
execl第一个参数如果不在根目录里则必需包含路径,使用whereis lolcat可以知道lolcat的安装目录。
(5)也是被freopen坑了,虽然写入文件简单,可是输出被重定向到文件里了,导致最后的结果老是输不到终端,在execl前加上freopen(“/dev/tty”,”w”,stdout);再将输出重定向到控制台。
【源代码】
1、main.cpp
#include<cstdio>
#include<iostream>
using namespace std;
void solve_choice1();
void welcome()
{
printf("请选择功能\n");
printf("1. 输入几篇文章,输出在这几篇文章中出现次数最多的10个单词\n");
return ;
}
int main()
{
int choice ;
welcome();
cin>>choice;
if(choice == 1)
{
solve_choice1();
}
return 0;
}
2、count_word.cpp
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<pthread.h>
#include<set>
#include<algorithm>
using namespace std;
const int max_char = 150;
extern const int max_file = 100;
pthread_mutex_t p_mutex = PTHREAD_MUTEX_INITIALIZER;
extern map<string,int>mp;
extern string str_file[max_file];
extern int tot_num;
string copy(char *s)
{
string str = "";
int len = strlen(s);
for(int i = 0;i < len;i++)
{
if((s[i] >= 'a'&&s[i] <= 'z') || (s[i] >= 'A' &&s[i] <= 'Z'))
str += s[i];
else
return "1";
}
return str;
}
void* count_word(void* args)
{
mp.clear();
int tmp = *((int*) args);
FILE *fp;
char ch[20];
int i;
for(i = 0;i < str_file[tmp].size();i++)
ch[i] = str_file[tmp][i];
ch[i] = '\0';
if((fp = fopen(ch,"r")) == NULL)
{
printf("fopen file error\n");
exit(0);
}
char str[max_char];
while(fscanf(fp,"%s",str) != EOF)
{
pthread_mutex_lock(&p_mutex);
string s = copy(str);
if(s != "1")
{
//puts("debug1");
mp[s]++;
tot_num++;
}
pthread_mutex_unlock(&p_mutex);
}
pthread_exit(0);
}
3、solve_choice1.cpp
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<pthread.h>
#include<set>
#include<algorithm>
#include<unistd.h>
using namespace std;
const int mp_num = 100;
const int max_file = 100;
string str_file[max_file];
map<string,int>mp;
map<string,int>::iterator it;
vector< pair <string,int> >vt;
vector< pair <string,int> >::iterator vtt;
int file_num,tot_num;
int num[mp_num];
void* count_word(void* args);
bool cmp(pair <string,int > a,pair <string,int> b)
{
return a.second > b.second;
}
void solve_choice1()
{
tot_num = 0;
printf("请输入文章的数量\n");
cin>>file_num;
while(file_num > max_file)
{
printf("文章数量过大,请重新输入\n");
cin>>file_num;
}
printf("请输入你要统计的文章\n");
for(int i = 0;i < file_num;i++)
cin >> str_file[i];
pthread_t id[mp_num];
for(int i = 0;i < file_num;i++)
{
num[i] = i;
while(pthread_create(&id[i],NULL,count_word,(void *) &(num[i])) != 0 );
}
for(int i = 0;i < file_num;i++)
{
while(pthread_join( id[i],NULL) != 0);
}
vt.clear();
for(it = mp.begin();it != mp.end();it++)
{
string cp = it -> first;
int w = it -> second;
// cout<<it -> first <<' '<<it -> second<<endl;
vt.push_back(make_pair(cp,w));
}
sort(vt.begin(),vt.end(),cmp);
char str1[]="rank: word quantity";
freopen("answer.txt","w",stdout);
cout<<str1<<endl;
int cnt=0;
for(vtt = vt.begin();vtt != vt.end();vtt++)
{
if(cnt==10)
break;
cout<<"\t"<<vtt->first<<"\t";
cout<<vtt->second<<endl;
cnt++;
}
freopen("/dev/tty","w",stdout);
execl("/usr/games/lolcat","lolcat","answer.txt",NULL);
return ;
}
4、makefile
main: main.o count_word.o solve_choice1.o
g++ -o $@ $^ -lpthread //注意一定要加-lpthread
http://www.linuxidc.com/Linux/2015-07/119839.htm
..c.o:
g++ -c $<
【运行过程】
makefile
./main
stdio.h |