Печать 10 лучших повторяющихся слов в файле - PullRequest
0 голосов
/ 09 октября 2018

Отредактированный вопрос: Привет, ребята, моя цель состоит в том, чтобы напечатать первые 10 встречающихся слов в файле, мне удалось заставить все работать: от чтения файла до подсчета вхождений слов и его печати, но когда я реализую свою qsort, яполучить segfault.Я посмотрел на мои указатели, и они выглядят хорошо для меня, я был бы признателен за любые отзывы.

#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;

}

Ответы [ 3 ]

0 голосов
/ 09 октября 2018

Первый temp уже является указателем, поэтому не включайте '&' перед ним в fscanf.Во-вторых, не экономьте на размере буфера (например, #define MAX 1024).В-третьих, защитите границы вашего массива с помощью модификатора field-width и не помещайте конечные пробелы в строку format-string .

В целом (если вы используете 1024 as MAX, вы можете использовать

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

Отлично с проверкой возврата fscanf во время чтения.

0 голосов
/ 11 октября 2018

Добавление к уже упомянутым вещам.

В createWordCounter(...)

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

вы выделяете память для char.Хотя указатель на структуру является указателем на ее первый член, первый элемент words является указателем на символ.Лучше быть осторожным и писать

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

Кроме того, помните о приоритетах операторов.В addWord(...) у вас есть

++pCounter->index;

. Что делает, так это увеличивает указатель pCounter перед доступом к index.Если вы пытаетесь увеличить index, это должно быть

++(pCounter->index);

или

pCounter->index++;

Я рекомендую разделить вашу программу до базовых и протестировать каждую часть по одной за разсистематически сужать причину ваших ошибок.

0 голосов
/ 09 октября 2018

Я думаю, что основной проблемой является размер временного массива при попытке использовать 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

...