![](/img/trans.png)
[英]C program for counting the number of occurrences of a word in a file using threads getting segmentation fault error
[英]Segmentation fault error in a program for counting no of occurences of a word in a file using threads
因此,我遇到以下问题:实现一个程序,该程序将文件名后跟单词作为参数。 为每个单词创建一个单独的线程以计算其在给定文件中的出现次数,并打印出所有单词的出现总数。
我的代码是:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t mtx; // used by each of the three threads to prevent other threads from accessing global_sum during their additions
int global_sum = 0;
typedef struct{
char* word;
char* filename;
}MyStruct;
void *count(void*str)
{
MyStruct *struc;
struc = (MyStruct*)str;
const char *myfile = struc->filename;
FILE *f;
int count=0, j;
char buf[50], read[100];
// myfile[strlen(myfile)-1]='\0';
if(!(f=fopen(myfile,"rt"))){
printf("Wrong file name");
}
else
printf("File opened successfully\n");
for(j=0; fgets(read, 10, f)!=NULL; j++){
if (strcmp(read[j],struc->word)==0)
count++;
}
printf("the no of words is: %d \n",count);
pthread_mutex_lock(&mtx); // lock the mutex, to prevent other threads from accessing global_sum
global_sum += count; // add thread's count result to global_sum
pthread_mutex_unlock(&mtx); // unlock the mutex, to allow other threads to access the variable
}
int main(int argc, char* argv[]) {
int i;
MyStruct str;
pthread_mutex_init(&mtx, NULL); // initialize mutex
pthread_t threads[argc-1]; // declare threads array
for (i=0;i<argc-2;i++){
str.filename = argv[1];
str.word = argv[i+2];
pthread_create(&threads[i], NULL, count, &str);
}
for (i = 0; i < argc-1; ++i)
pthread_join(threads[i], NULL);
printf("The global sum is %d.\n", global_sum); // print global sum
pthread_mutex_destroy(&mtx); // destroy the mutex
return 0;
}
当我尝试运行它时,出现分段错误错误。 这是为什么? 谢谢!
在main()
两个i
循环不同
for (i=0;i<argc-2;i++){
...
pthread_create(&threads[i], NULL, count, &str);
}
接着
for (i = 0; i < argc-1; ++i)
pthread_join(threads[i], NULL);
在第二个循环中,您将引用在第一个循环中未创建的threads[argc-2]
。
首先,您的代码格式非常糟糕。 这甚至不一致。 您在启用警告的情况下进行编译也不会出现。
如果您是一门大学课程,并且他们没有告诉您如何格式化代码并通过警告进行编译,我强烈建议您请教您的导师提供什么。
如果使用gcc,请添加-Wall -Wextra。 对于编码风格,我建议从Linux或FreeBSD中窃取一种。 有多种编辑器可以为您设置代码格式,包括像vim这样的真正编辑器(即使看起来很苛刻也值得尝试)。
您的编码风格可帮助您解决问题。
void *count(void*str)
{
MyStruct *struc;
struc = (MyStruct*)str;
const char *myfile = struc->filename;
FILE *f;
int count=0, j;
char buf[50], read[100];
buf未使用,如果启用了警告,您将了解到。 读是一个坏名字。
// myfile[strlen(myfile)-1]='\0';
if(!(f=fopen(myfile,"rt"))){
printf("Wrong file name");
}
else
因为您不返回(应有的状态),所以您将自己设置为执行代码的不正确行为,而不应该这样做。 不用猜测,您的“ else”子句是无效的。 您缺少花括号,因此即使文件打开操作失败,也会执行下面的for循环。
printf("File opened successfully\n");
for(j=0; fgets(read, 10, f)!=NULL; j++){
10点 好像是一个错字,您可能要输入100。如果使用sizeof,则不会发生这种情况。
if (strcmp(read[j],struc->word)==0)
count++;
}
目前尚不清楚您在这里做什么。 似乎您想从read [0]开始,从read 1开始 ,等等进行strcmp。 但是,您读取了新数据并替换了原始缓冲区中的内容, 然后将其前进了一个。 这毫无意义。 最后,无论如何您做错了。 read [j]不会求值到一个地址,如果您要求,编译器会再次告诉您。
无论如何,strcmp方法非常糟糕。 尝试一种尝试匹配第一个字符并从那里开始工作的方法。
int main(int argc, char* argv[]) {
标准放错了“ *”。 使用char * argv []代替。
int i;
MyStruct str;
pthread_mutex_init(&mtx, NULL); // initialize mutex
pthread_t threads[argc-1]; // declare threads array
强烈不推荐。 首先验证参数,然后验证一个专用变量,该变量保存一定数量的线程。 此时,您可以分配一个数组。
for (i=0;i<argc-2;i++){
str.filename = argv[1];
str.word = argv[i+2];
pthread_create(&threads[i], NULL, count, &str);
}
与线程类似,将路径保存在某处。 将其称为argv 1是不好的风格,这会再次咬住您。 对单词使用argv可以。
但是,这通常是错误的。 您设置了本地结构并将其传递给线程,然后立即对其进行更改 。 因此,发生在一天结束时,所有线程都在计数相同的单词。 但是他们所指的单词在此过程中发生了变化。
for (i = 0; i < argc-1; ++i)
pthread_join(threads[i], NULL);
去搞清楚。 您没有一个拥有一定数量线程的变量,这导致了这种不一致(argc-1 vs argc-2)。
通常,通过正确阅读编译器警告,可以在很大程度上解决此问题,并且如果采用基本的良好实践,通常可以避免此问题。
当然,无论如何都会发生错误,在这种情况下,您至少可以缩小范围。
最后,关于通用方法的几句话。 目前尚不清楚该练习的目的是什么。 实际上,您必须强迫自己使用除pthread_create和pthread_join之外的任何方法。 假设唯一的要求是使用线程。
我不知道他们是否强迫您多次打开文件。 多次打开和读取内容不仅浪费,而且在文件被替换并且某些线程打开另一个文件的情况下使您打开。
一个好的解决方案是在主目录中打开一次文件。 打开后,您可以将文件和fstat映射为大小。 如果由于某种原因不能使用mmap,则应分配足够大的缓冲区并读取文件。
然后,所有线程都可以获得该缓冲区的地址,要查找的单词以及它们应将计数器存储到的地址(每个线程获得一个不同的地址)。
当所有线程退出时,您将循环以求和。
无论哪种方式都不会涉及锁定。
一次(可能)读取(最多)10个字符将丢失某些正在搜索的单词实例。
strcmp()始终从10个字符的开头开始。
1)需要在文件中的任何位置查找目标词。
2)需要在读入缓冲区的任何位置查找目标单词。
建议:
0) clear input buffer
1) input one char at a time,
accumulating characters in the input buffer,
2) when a word separator found, (for instance a space or EOF)
3) then check if the word matches the target word.
4) if matches, increment count.
5) if EOF, then exit, else goto 0
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.