计算每个单词

时间:2016-07-12 01:52:32

标签: c arrays string

我试图计算函数countWords中每个单词的出现次数我相信我在函数中正确启动了for循环但是如何将数组中的单词进行比较并计算他们然后删除重复?它不像斐波那契系列,还是我弄错了?此外int n的值为756,因为数组中有多少个单词,wordsArray是数组中的元素。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

int *countWords( char **words, int n);
int main(int argc, char *argv[])
{
  char buffer[100];  //Maximum word size is 100 letters
  FILE *textFile;
  int numWords=0;
  int nextWord;
  int i, j, len, lastChar;
  char  *wordPtr;
  char  **wordArray;
  int *countArray;
  int *alphaCountArray;
  char **alphaWordArray;
  int *freqCountArray;
  char **freqWordArray;
  int choice=0;

  //Check to see if command line argument (file name)
  //was properly supplied.  If not, terminate program
  if(argc == 1)
  {
    printf ("Must supply a file name as command line argument\n");
    return (0);
  }

  //Open the input file.  Terminate program if open fails
  textFile=fopen(argv[1], "r");
  if(textFile == NULL)
  {
    printf("Error opening file. Program terminated.\n");
    return (0);
  }

  //Read file to count the number of words
  fscanf(textFile, "%s", buffer);
  while(!feof(textFile))
  {
    numWords++;
    fscanf(textFile, "%s", buffer);
  }

  printf("The total number of words is: %d\n", numWords);
  //Create array to hold pointers to words
  wordArray = (char **) malloc(numWords*sizeof(char *));
  if (wordArray == NULL)
  {
     printf("malloc of word Array failed.  Terminating program.\n");
     return (0);
  }
  //Rewind file pointer and read file again to create
  //wordArray
  rewind(textFile);
  for(nextWord=0; nextWord < numWords; nextWord++)
  {
    //read next word from file into buffer.
    fscanf(textFile, "%s", buffer);

    //Remove any punctuation at beginning of word
    i=0;
    while(!isalpha(buffer[i]))
    {
      i++;
    }
    if(i>0)
    {
      len = strlen(buffer);
      for(j=i; j<=len; j++)
      {
        buffer[j-i] = buffer[j];
      }
    }

    //Remove any punctuation at end of word
    len  = strlen(buffer);
    lastChar = len -1;
    while(!isalpha(buffer[lastChar]))
    {
      lastChar--;
    }
    buffer[lastChar+1] = '\0';

    //make sure all characters are lower case
    for(i=0; i < strlen(buffer); i++)
    {
      buffer[i] = tolower(buffer[i]);
    }

    //Now add the word to the wordArray.
    //Need to malloc an array of chars to hold the word.
    //Then copy the word from buffer into this array.
    //Place pointer to array holding the word into next
    //position of wordArray
    wordPtr = (char *) malloc((strlen(buffer)+1)*sizeof(char));
    if(wordPtr == NULL)
    {
      printf("malloc failure.  Terminating program\n");
      return (0);
    }
    strcpy(wordPtr, buffer);
    wordArray[nextWord] = wordPtr;
  }

  //Call countWords() to create countArray and replace
  //duplicate words in wordArray with NULL
  countArray = countWords(wordArray, numWords);
  if(countArray == NULL)
  {
    printf("countWords() function returned NULL; Terminating program\n");
    return (0);
  }

  //Now call compress to remove NULL entries from wordArray
  compress(&wordArray, &countArray, &numWords);
  if(wordArray == NULL)
  {
    printf("compress() function failed; Terminating program.\n");
    return(0);
  }
  printf("Number of words in wordArray after eliminating duplicates and compressing is: %d\n", numWords);

  //Create copy of compressed countArray and wordArray and then sort them alphabetically
  alphaCountArray = copyCountArray(countArray, numWords);
  freqCountArray = copyCountArray(alphaCountArray, numWords);
int *countWords( char **wordArray, int n)
{
  return NULL;
  int i=0;
  int n=0;

  for(i=0;i<n;i++)
  {
      for(n=0;n<wordArray[i];n++)
      {

      }
   }

}

2 个答案:

答案 0 :(得分:1)

假设您希望countWords的返回值是一个整数数组,每个唯一字都有字数,您需要有一个双循环。一个循环遍历整个数组,第二个循环遍历数组的其余部分(在当前单词之后),寻找重复数据。

你可以做类似这样的伪代码:

Allocate the return array countArray (n integers) 
Loop over all words (as you currently do in your `for i` loop)
   If the word at `i` is not null // Check we haven't already deleted this word
      // Found a new word
      Set countArray[i] to 1
      Loop through the rest of the words e.g. for (j = i + 1; j < n; j++)
         If the word at j is not NULL and matches the word at i (using strcmp)
            // Found a duplicate word
            Increment countArray[i] (the original word's count)
            // We don't want wordArray[j] anymore, so 
            Free wordArray[j]
            Set wordArray[j] to NULL
   Else
      // A null indicates this was a duplicate, set the count to 0 for consistency.
      Set countArray[i] to 0
Return wordArray

答案 1 :(得分:0)

我会在这里给你一点曲线球。

我决定从头开始编写一个例子,而不是修复你的代码,而代码可以很容易地修复,因为它本身很好,但不完整,我决定写一个例子。

无需两次读取文件[第一次只是为了获得最大计数]。这可以由动态数组和realloc处理。

我想主要的一点是,在创建时,确保单词列表 no 重复更容易,而不是在最后删除重复项。

我选择了一些东西。

我创建了一个&#34;字控制&#34;结构。您已经有几个单独的数组以相同的方式编制索引。那种,有点,&#34;哭泣&#34;对于结构。也就是说,而不是[比较] 5个单独的数组,而是有一个结构的单个数组,其中包含5个元素。

单词列表是这些结构的链表。 可能是堆上的动态数组,而不是realloc,但链接列表实际上更容易为此特定用途维护。

每个结构都有[已清理]单词文本和出现次数(与单独的wordArraycountArray相对)。

添加单词时,会扫描列表以查找现有匹配项。如果找到一个,则递增计数,而不是创建新的单词列表元素。这是消除重复的关键[即不要在第一时间创建它们。

无论如何,这是:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>

#define sysfault(_fmt...) \
    do { \
        printf(_fmt); \
        exit(1); \
    } while (0)

// word control
typedef struct word {
    struct word *next;              // linked list pointer
    char *str;                      // pointer to word string
    int count;                      // word frequency count
} word_t;

word_t wordlist;                    // list of words

// cleanword -- strip chaff and clean up word
void
cleanword(char *dst,const char *src)
{
    int chr;

    // NOTE: using _two_ buffers in much easier than trying to clean one
    // buffer in-place
    for (chr = *src++;  chr != 0;  chr = *src++) {
        if (! isalpha(chr))
            continue;
        chr = tolower(chr);
        *dst++ = chr;
    }

    *dst = 0;
}

// addword -- add unique word to list and keep count of number of words
void
addword(const char *str)
{
    word_t *cur;
    word_t *prev;
    char word[1000];

    // get the cleaned up word
    cleanword(word,str);

    // find a match to a previous word [if it exists]
    prev = NULL;
    for (cur = wordlist.next;  cur != NULL;  cur = cur->next) {
        if (strcmp(cur->str,word) == 0)
            break;
        prev = cur;
    }

    // found a match -- just increment the count (i.e. do _not_ create a
    // duplicate that has to be removed later)
    if (cur != NULL) {
        cur->count += 1;
        return;
    }

    // new unique word
    cur = malloc(sizeof(word_t));
    if (cur == NULL)
        sysfault("addword: malloc failure -- %s\n",strerror(errno));

    cur->count = 1;
    cur->next = NULL;

    // save off the word string
    cur->str = strdup(word);
    if (cur->str == NULL)
        sysfault("addword: strdup failure -- %s\n",strerror(errno));

    // add the new word to the end of the list
    if (prev != NULL)
        prev->next = cur;

    // add the first word
    else
        wordlist.next = cur;
}

int
main(int argc,char **argv)
{
    FILE *xf;
    char buf[1000];
    char *cp;
    char *bp;
    word_t *cur;

    --argc;
    ++argv;

    xf = fopen(*argv,"r");
    if (xf == NULL)
        sysfault("main: unable to open '%s' -- %s\n",*argv,strerror(errno));

    while (1) {
        // get next line
        cp = fgets(buf,sizeof(buf),xf);
        if (cp == NULL)
            break;

        // loop through all words on a line
        bp = buf;
        while (1) {
            cp = strtok(bp," \t\n");
            bp = NULL;

            if (cp == NULL)
                break;

            // add this word to the list [avoiding duplicates]
            addword(cp);
        }
    }

    fclose(xf);

    // print the words and their counts
    for (cur = wordlist.next;  cur != NULL;  cur = cur->next)
        printf("%s %d\n",cur->str,cur->count);

    return 0;
}