【问题标题】:Printing top 10 recurring words in a file在文件中打印前 10 个重复出现的单词
【发布时间】:2019-03-13 17:40:11
【问题描述】:

已编辑的问题: 嗨,伙计们,我的目标是打印文件中出现的前 10 个单词,从读取文件到计算单词出现次数并打印它,我已经设法让一切正常工作,但是当我实现我的 qsort 时,我得到了一个段错误。我查看了我的指针,它们对我来说看起来不错,如果有任何反馈,我将不胜感激。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define MAX 51

struct words
{
  char *ch;
  int index;
  struct words *pNext;
};



struct words* createWordCounter(char *ch)
{
  struct words *pCounter = NULL;
  pCounter = (struct words*)malloc(sizeof(char));
  pCounter->ch = (char*)malloc(strlen(ch)+1);
  strcpy(pCounter->ch, ch);
  pCounter->index = 1;
  pCounter->pNext = NULL;
  return pCounter;
}

struct words *pStart = NULL;

char* removePunc(struct words* ch)
{
  char *src = ch, *dst = ch;

  while (*src)
  {
     if (ispunct((unsigned char)*src))
     {

        src++;
     }
     else if (isupper((unsigned char)*src))
     {

        *dst++ = tolower((unsigned char)*src);
        src++;
     }
     else if (src == dst)
     {

        src++;
        dst++;
     }
     else
     {

        *dst++ = *src++;
     }
  }

  *dst = 0;
}

void addWord(char *word)
{
  struct words *pCounter = NULL;
  struct words *pLast = NULL;

  if(pStart == NULL)
  {
    pStart = createWordCounter(word);
    return;
  }


  pCounter = pStart;
  while(pCounter != NULL)
  {
    if(strcmp(word, pCounter->ch) == 0)
    {
      ++pCounter->index;
      return;
    }
    pLast = pCounter;
    pCounter = pCounter->pNext;
  }
  pLast->pNext = createWordCounter(word);
}

void printWord(struct words *pCounter)
{


  printf("\n%-30s  %5d\n", pCounter->ch, pCounter->index);

}
//sort
int compare (const void * a, const void * b){
  struct words *A1 = (struct words *)a;
  struct words *B1 = (struct words *)b;
  return B1->index - A1->index;
/*
  if ((A1->count - B1->count) > 0)
        return -1;
  else if ((A1->count - B2->count) < 0)
        return 1;
  else
        return 0;
*/
}



int main(int argc, char * argv[])
{
  struct words *pCounter = NULL;


  char temp[MAX];
  FILE *fpt;


  if(argc == 2)
  {

    printf("File name is: %s\n",argv[1]);
    fpt = fopen(argv[1], "r");
    //fail test
    if(fpt == NULL)
    {
      printf("cannot open file, exiting program...\n");
      exit(0);
    }

    //get the data out of the file and insert in struct
    int wordCounter = 0;
    int i = 0;
    int lines = 0;
    while((fscanf(fpt, "%s ", &temp)) == 1)
    {

        removePunc(temp);
        addWord(temp);

        if(temp == ' ')
          i++;
        if(temp == '\n')
          lines++;

        wordCounter++;
    }


/*
    pCounter = pStart;
    while(pCounter != NULL)
    {
      printWord(pCounter);
      pCounter = pCounter->pNext;
    }
*/
  //sort
    qsort(pCounter, wordCounter, sizeof(struct words), compare);
    for(int j = 0; i < 10; i++)
    {
       printWord(pCounter);
    }

  }

  fclose(fpt);
  return 0;

}

【问题讨论】:

    标签: c file io segmentation-fault


    【解决方案1】:

    补充已经提到的东西。

    createWordCounter(...)

    pCounter = (struct words*)malloc(sizeof(char));
    

    您正在为char 分配内存。即使指向结构的指针是指向其第一个成员的指针,words 的第一个元素也是指向 char 的指针。还是小心点写吧

    struct words *pCounter = malloc(sizeof *pCounter);
    

    另外,请注意运算符的优先级。 在addWord(...) 你有

    ++pCounter->index;
    

    这样做是在访问index 之前增加指针pCounter。如果你想增加index,它应该是

    ++(pCounter->index);
    

    pCounter->index++;
    

    我建议您将您的程序精简到最基本的部分,并一次系统地测试每个部分,以缩小导致错误的原因。

    【讨论】:

      【解决方案2】:

      第一个temp 已经是一个指针,所以不要在fscanf 中包含'&amp;'。其次,不要吝啬缓冲区大小(例如#define MAX 1024)。第三,使用 field-width 修饰符保护你的数组边界,不要在 format-string 中放置尾随空格。

      总而言之(假设你使用1024 as MAX,你可以使用

      fscanf(fpt, "1023%s", temp))
      

      在阅读过程中检查fscanf 的返回做得很好。

      【讨论】:

      • 感谢您抽出时间回答我的问题,但是,我设法解决了这些问题,但是当我编写了一个新的排序函数并尝试实现它时,我遇到了一个段错误,你会不会碰巧知道是什么原因造成的吗?
      • @mahdi - qsort(pCounter, wordCounter, sizeof(struct words), compare); pCounter 分配在哪里? compare 定义在哪里?
      • compare 最好是return (A1-&gt;index &gt; B1-&gt;index) - (A1-&gt;index &lt; B1-&gt;index); 以避免潜在的溢出
      【解决方案3】:

      我认为主要问题是当您尝试使用 fscanf 时临时数组的大小。

      while((fscanf(fpt, "%s ", temp)) == 1)
      

      当一行的长度大于MAX时,会出现分段错误。

      您可以像这样更改您的代码

      #define SCANF_LEN2(x) #x
      #define SCANF_LEN(x) SCANF_LEN2(x)
      
      //...
      //your original code
      //...
      
      while((fscanf(fpt, "%"SCANF_LEN(MAX)"s ", temp)) == 1)
      

      顺便说一下,你应该检查一下

      (1) 关于类型的编译警告

      char* removePunc(struct words* ch) 应该是char* removePunc(char *ch)

      if(temp == ' ') 应该是if(temp[0] == ' ')

      if(temp == '\n') 应该是if(temp[0] == '\n')

      (2) malloc 大小

      pCounter = (struct words*)malloc(sizeof(char)); 应该是pCounter = (struct words*)malloc(sizeof(struct words));

      (3) 使用malloc后记得free

      【讨论】:

      • 非常感谢您的反馈,但是,从上传程序开始,我对程序进行了重大更改,现在我不确定在哪里,但我的比较出错了我无法弄清楚的功能。
      猜你喜欢
      • 2013-03-14
      • 2021-12-20
      • 1970-01-01
      • 2017-02-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多