我目前正在尝试编写一个应用程序来计算 ASCII 文件中单词的出现次数(标点符号被删除并忽略空格)。应用程序应该将单词和单词计数存储在一个数据结构中,最终将按降序排序,然后打印到 CSV 文件。

我已经开始使用这个程序,但是在尝试保存新单词时遇到了段错误。这是我的代码(我知道这不是一个完美的实现,我确实计划对其进行改进):

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

#define TRUE 1
#define FALSE 0

/* This program is designed to take an ASCII input file, count the occurrences of words in it
 * and write an output file displaying the data. I intend for it to convert uppercase to
 * lowercase, so as not to generate duplicate words in the data structure. It should also
 * ignore whitespace and punctuation.
*/

void getWords(void);
void printFile(void);
void save(char *input);

struct word {
    char *str;
    int wc;
};

struct word *warray = NULL;

FILE *infile;
FILE *outfile;

void getWords(void)
{

    rewind(infile);
    char cw[100]; // Current word storage
    int i = 0, j = 0, c;

    while((c = fgetc(infile)) != EOF)
    {
        if(isalpha(c))
        {
            if(isupper(c))
            {
                cw[i] = tolower(c);
                ++i;
            }
            else
            {
                cw[i] = c;
                ++i;
            }
        }
        else
        {
            if(c == '\n' || c == '\t' || c == ' ')
            {
                cw[i] = '\0';
                i = 0;
                save(cw);

                for(j = 0; j < cw[99]; j++)
                {
                    printf("%c", cw[j]);
                }
            }
        }

    }

}

void printFile(void)
{

    int i, c;

    printf("Printing the file to be counted in lowercase...\n");
    for(i = 0; (c = fgetc(infile)) != EOF; i++)
    {
        if(ispunct(c) || isdigit(c))
        {
            ++i;
        }
        else
        {
            putchar(tolower(c));
        }

    }
}

void save(char *input)
{

    int exists = FALSE, i = 0;
    int elements = sizeof(warray)/sizeof(struct word);

    if(!warray)
    {
        warray = malloc(sizeof(struct word));
        printf("Made array.\n");
    }
    else
    {
        printf("New.\n");
        warray = realloc(warray, (elements++)*sizeof(struct word));
    }

    while(i < elements)
    {
        printf("in while loop\n");
        if(strcmp(input, warray[i].str) == 0)
        {
            warray[i].wc++;
        }
        else
        {
            ++i;
        }

    }
    printf("Out while loop\n");

    if(strcmp(input, warray[i].str) == 1)
    {
        printf("Inside save if statement\n");

        warray[elements].str = malloc(strlen(input)+1);

        strcpy(warray[elements].str, input);

        warray[elements].wc = 1;

        elements++;
    }


}

int main (int argc, char *argv[])
{


    if (argc < 3)
    {
        puts("Please supply the input filename and desired output filename as arguments.");
        return 1;
    }

    infile = fopen(argv[1], "r");
    if(infile == NULL)
    {
        printf("File failed to open. Error: %d\n", errno);
        return 1;
    }
    else
    {
        puts("File opened successfully.");
        printFile();
        getWords();
    }

    return 0;

}

我已经放入了一些打印语句来尝试隔离问题,它似乎在这里遇到了问题,在 save(char *input) 函数中:
if(strcmp(input, warray[i].str) == 1)
{
    printf("Inside save if statement\n");

    warray[elements].str = malloc(strlen(input)+1);

    strcpy(warray[elements].str, input);

    warray[elements].wc = 1;

    elements++;
}

我确实有一种感觉,因为我要求 strcmp 检查它的值是否 == 1,当时也许我应该检查任何非零值,但我已经尝试过,但我仍然得到分段故障。

如果有人能指出我正确的方向,我将不胜感激,并提前致谢!

最佳答案

您的实现中有几个逻辑缺陷。从您的代码中,我假设您想要执行以下操作:

  • 检查 warray 是否为空。如果为空,则分配一个元素。
  • 如果不为空,则检查该词是否已存在。如果是,则增加计数器。
  • 如果单词不在数组中,则在数组中分配一个新元素并将单词保存在那里。

  • 但是您的代码执行以下操作。
    if(!warray)
    {
        warray = malloc(sizeof(struct word));
        printf("Made array.\n");
    }
    

    这部分没问题。
    else
    {
        printf("New.\n");
        warray = realloc(warray, (elements++)*sizeof(struct word));
    }
    

    这不应该在这里。您应该先检查重复项,然后根据需要进行分配。
    while(i < elements)
    {
        printf("in while loop\n");
        if(strcmp(input, warray[i].str) == 0)
        {
            warray[i].wc++;
        }
        else
        {
            ++i;
        }
    }
    

    这是错误的。如果这个词已经存在,那么它会卡在 warray[i].wc++; 行中。您应该在增加计数器后返回。
    if(strcmp(input, warray[i].str) == 1)
    {
        printf("Inside save if statement\n");
        warray[elements].str = malloc(strlen(input)+1);
        strcpy(warray[elements].str, input);
        warray[elements].wc = 1;
        elements++;
    }
    

    这也是错误的。在上一个循环之后, i 的值将等于 elements 的值。但是数组索引是从 0elements-1 。所以 warray[i]warray[elements] 都会导致段错误。 (您之前在 elements 行上增加了 warray = realloc(warray, (elements++)*sizeof(struct word)); 的值)

    注意:for(j = 0; j < cw[99]; j++) 函数中的 getwords 也可能导致段错误。

    编辑:我之前没有注意到后增量问题。它应该是
    warray = realloc(warray, (++elements)*sizeof(struct word));
    

    代替
    warray = realloc(warray, (elements++)*sizeof(struct word));
    

    感谢克罗诺斯。

    关于c - 字数统计应用程序 - C,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21966834/

    10-10 22:41