【问题标题】:C : text file, string comparison and so onC:文本文件、字符串比较等
【发布时间】:2017-02-17 21:57:49
【问题描述】:

首先是我的代码的链接:http://codepad.org/u68QnKPp

简要描述一下我的代码的作用:它在执行时需要正好 5 个字母的序列(例如:./anagramme p a n n e)并经历了很多,包括创建单词列表、与静态字典(fr5.txt ) 来查看是否有任何创建的单词(字谜)存在于法语中,然后应该显示这些单词(如果它们存在的话)。

问题出现在第 191 行,即使两个字符串相等,比较(使用 streq)也会失败(提示缩进的小尝试调试部分),因此即使遇到正确的单词也永远不会匹配任何单词(除非您对其进行编码显然直接进入if条件...cf注释部分)。

streq() 函数似乎在起作用 clap clap,因为注释部分在未注释时效果很好。

我的问题是:我在字符串比较/指针操作中做错了什么,我应该如何解决?

[编辑:显示问题代码(最新版本始终是上面的链接)]

    time_t start,end;
    float elapsed;
        /**looping through dictionnary and comparing to words found**/
    start=clock();
    for(int i=0 ; i<res_len ; i++){
        fichier f = fopen("fr5.txt","r");
        if(f==NULL)exit(-1);
        if(verbose){echo("file opened for loop\n");}
        char* curr_loop_word = (char*)malloc(6 * sizeof(char));
        strcpy(curr_loop_word,iter[i]);
        for(int j=0 ; j<dico_nb_ligne ; j++){
            if(verbose)echo("browsing dictionnary");
            char* curr =(char*)malloc(6 * sizeof(char)) ;
            //strcpy(curr, fgetl(f));
            size_t len=5;
            ssize_t x = getline(&curr,&len,f);

                char* tst = (char*)malloc(6 * sizeof(char));
                char* test = (char*)malloc(6 * sizeof(char));
                for(int i=0 ; i<5 ; i++){
                    tst[i]=curr[i];
                    test[i]=curr_loop_word[i];
                }
                tst[5]='_';
                test[5]='_';
                strcpy(curr,tst);
                free(tst);
                strcpy(curr_loop_word,test);
                free(test);

            if(x==-1)exit((int)x);
            if(verbose)printf("size : %zu",x);
            if(verbose)printf("current dictionnary word : %s\n",curr);

            if(streq(curr,curr_loop_word)/* || streq(curr,"panne_")*/){//problem occurs here
                if(verbose)echo("found one :\n");
                strcpy(mots[mots_len],curr);
                mots_len+=1;
                if(verbose){
                    printf("correct word found : %s\n",curr);
                }
                break;
            }

        }
        fclose(f);
        if(verbose){echo("file closed after loop\n");}
    }
    end=clock();
    elapsed = (float)(end-start)/(float)CLOCKS_PER_SEC;

[/编辑]

PS: 我使用getline(),因为每个单词都在文件中的单独一行上(单词已经排序为仅包含 5 个字母单词)。

PS2: 我希望您不介意 main() 之前的函数的花哨缩进,这纯粹是为了清楚当我浏览代码而不在 main 上放置标记时是什么。

PS3: 我希望我的问题/问题很清楚,如果不告诉我什么不是,我会编辑它。

PS4: 也许一个好的解决方案是切换到 C++ 以避免至少一级指针?

【问题讨论】:

  • 我认为,如果您将一小段代码直接显示到您的帖子中,这可能会有所帮助。
  • @Vivick:当你的问题得到回答时,不要像那样更改问题中的代码,当你这样做时,现有的答案就会变得毫无意义。

标签: c arrays string file string-comparison


【解决方案1】:

这里(样式和缩进改进):

char * curr = malloc(6);
size_t len = 5;
ssize_t x = getline(&curr, &len, f);

char * tst = malloc(6);
char * test = malloc(6);
for ( int i = 0; i < 5; ++i ) {
    tst[i] = curr[i];
    test[i] = curr_loop_word[i];
}

tst[5] = '_';
test[5] = '_';

strcpy(curr, tst);
free(tst);

strcpy(curr_loop_word, test);
free(test);

您从curr 开始,这是一个您提供给getline() 的6 个字符的动态分配数组,用于存储一个5 个字符的字符串。到目前为止还不错,只是你从不检查 getline() 是否真的有 5 个字符,而你应该检查。

您似乎想要做的是将这 5 个字符加上一个下划线写入tst。但是你也让tst 6 个字符长,你需要 7 个字符作为你的 6 个字符加上终止的空字符。然后,最重要的是,您实际上并没有编写终端空字符,因此您的字符串不会终止,并且您的 strcpy() 调用将在您的数组末尾运行,并且任何后续 strcmp() 调用都是会同样惨败。

所以,这里需要分配 7 个字节,并且需要将终止的 null 写入两个字符串。

从您的代码中跳出的少量其他点:

  • 不要从 malloc() 转换返回值 - 这在 C 中是不必要的,通常被认为是不好的样式

  • sizeof(char) 定义为 1,所以不要使用它

  • typedefing FILE * 以这种方式只会带来麻烦 - 只需使用 FILE *

  • 不用定义 echo() 函数,您可以只使用标准的 puts()

  • 在您的notEOF() 函数中,在char 未签名的系统上,x == EOF 将不起作用。 getchar() 返回 int,而不是 char,因此您的 notEOF() 函数应该采用 int 参数,而不是 char 参数。

  • 没有必要使用malloc() 一次又一次地分配一个在编译时已知的小尺寸数组。修复时只需使用char tst[6];char tst[7];。当然没有必要在循环的每次迭代中一遍又一遍地malloc()free()

  • 在任何情况下,malloc() 都可能失败,而您永远不会对此进行检查。你应该。

  • 您的大 main() 函数急需分解成可以单独测试和调试的较小函数。

  • 在同一主题上,很难理解为什么这么短的程序有这么多全局变量,而所有这些变量都只在一个函数中使用

  • 尽量记住您的键盘有空格键

编辑:这是一种明智的方法,使用适合问题的实际数据结构,并将逻辑适当地分解为单独的函数。它最终得到的代码比您的示例多一点,但是您在编写更多代码上所花费的时间节省了您不花时间盯着屏幕想知道为什么它不工作的时间。特别是,查看主文件dictlist.c 并注意我们有多少次:

  • 致电malloc() - 从不

  • 比较一个字符串和另一个字符串 - 一次,检查命令行参数时

  • 复制字符串 - 从不

  • 直接设置字符串中的字符,或手动向字符串添加终止空字符 - 一次,从文件输入中删除换行符时

  • 增加一个计数器 - 从不,除了 for 循环索引

  • 排序数据 - 从不

每次我们在编写程序的主要逻辑时不做这些事情中的任何一件,都可以保证我们在做的时候不会出错。

dictfind.c:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "wordlist.h"
#include "logging.h"

#define MAX_LINE_LENGTH 64


/*
 * Returns a word list made from entries in a dictionary file
 */

WordList get_dictionary(void)
{
    WordList dict = wordlist_create();

    FILE * fp = fopen("dictionary.txt", "r");
    if ( !fp ) {
        perror("couldn't open dictionary for reading");
        exit(EXIT_FAILURE);
    }

    char buffer[MAX_LINE_LENGTH];
    while ( fgets(buffer, MAX_LINE_LENGTH, fp) ) {
        size_t len = strlen(buffer);
        if ( len > 0 && buffer[len - 1] == '\n' ) {
            buffer[len - 1] = 0;
        }
        wordlist_add(dict, buffer);
    }

    if ( fclose(fp) != 0 ) {
        perror("couldn't close dictionary file");
        exit(EXIT_FAILURE);
    }

    log_msg("Read %zu words into dictionary.\n", wordlist_length(dict));

    return dict;
}


/*
 * Returns true if none of the arguments equal each other
 */

bool no_dups(size_t i, size_t j, size_t k, size_t l, size_t m)
{
    return i != j && i != k && i != l && i != m &&
           j != k && j != l && j != m && k != l &&
           k != m && l != m;
}


/*
 * Returns a list of words of all combinations of the five
 * letter string provided.
 */

WordList make_words(char * letters)
{
    WordList words = wordlist_create();

    for ( size_t i = 0; i < 5; ++i ) {
        for ( size_t j = 0; j < 5; ++j ) {
            for ( size_t k = 0; k < 5; ++k ) {
                for ( size_t l = 0; l < 5; ++l ) {
                    for ( size_t m = 0; m < 5; ++m ) {
                        if ( no_dups(i, j, k, l, m) ) {
                            char new_word[] = {letters[i], letters[j],
                                letters[k], letters[l], letters[m], 0};
                            wordlist_add_unique(words, new_word);
                        }
                    }
                }
            }
        }
    }

    log_msg("Made %zu words from input.\n", wordlist_length(words));

    return words;
}


/*
 * Returns a list of dictionary matches from a list of candidate words
 */

WordList get_matches(WordList dict, WordList words)
{
    WordList matches = wordlist_create();

    for ( size_t i = 0; i < wordlist_length(words); ++i ) {
        char * word = wordlist_word(words, i);
        if ( wordlist_contains(dict, word) ) {
            wordlist_add(matches, word);
            log_msg("Adding found match: %s\n", word);
        }
    }

    return matches;
}


/*
 * Main function
 */

int main(int argc, char ** argv)
{
    if ( argc == 7 && strcmp(argv[6], "-v") == 0 ) {
        logging_enable(true);
    }
    else if ( argc != 6 ) {
        fprintf(stderr, "Usage: dictfind a b c d e [-v]\n");
        return EXIT_SUCCESS;
    }

    char letters[5] = {argv[1][0], argv[2][0], argv[3][0],
                       argv[4][0], argv[5][0]};

    WordList dict = get_dictionary();
    WordList words = make_words(letters);
    WordList matches = get_matches(dict, words);

    for ( size_t i = 0; i < wordlist_length(matches); ++i ) {
        printf("Match found: %s\n", wordlist_word(matches, i));
    }

    wordlist_destroy(dict);
    wordlist_destroy(words);
    wordlist_destroy(matches);

    return EXIT_SUCCESS;
}

wordlist.h:

#ifndef WORD_LIST_H
#define WORD_LIST_H

#include <stddef.h>
#include <stdbool.h>

typedef struct wordlist * WordList;

WordList wordlist_create(void);
void wordlist_destroy(WordList list);
void wordlist_add(WordList list, char * word);
void wordlist_add_unique(WordList list, char * word);
char * wordlist_word(WordList list, size_t index);
int wordlist_find(WordList list, char * word);
bool wordlist_contains(WordList list, char * word);
size_t wordlist_length(WordList list);

#endif

wordlist.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wordlist.h"

#define INITIAL_LIST_CAPACITY 16

struct wordlist {
    size_t length;
    size_t capacity;
    char ** words;
};

WordList wordlist_create(void)
{
    struct wordlist * new_list = malloc(sizeof *new_list);
    if ( !new_list ) {
        perror("couldn't allocate memory for word list");
        exit(EXIT_FAILURE);
    }

    char ** new_words = malloc(INITIAL_LIST_CAPACITY * sizeof(*new_words));
    if ( !new_words ) {
        perror("couldn't allocate memory for words");
        exit(EXIT_FAILURE);
    }

    new_list->length = 0;
    new_list->capacity = INITIAL_LIST_CAPACITY;
    new_list->words = new_words;

    return new_list;
}

void wordlist_destroy(WordList list)
{
    for ( size_t i = 0; i < list->length; ++i ) {
        free(list->words[i]);
    }
    free(list->words);
    free(list);
}

void wordlist_add(WordList list, char * word)
{
    if ( list->length == list->capacity ) {
        list->capacity *= 2;
        char ** new_words = realloc(list->words,
                                    list->capacity * sizeof *new_words);
        if ( !new_words ) {
            perror("couldn't reallocate memory for word list");
            exit(EXIT_FAILURE);
        }
        list->words = new_words;
    }

    char * new_word = malloc(strlen(word) + 1);
    if ( !new_word ) {
        perror("couldn't allocate memory for new word");
        exit(EXIT_FAILURE);
    }

    strcpy(new_word, word);
    list->words[list->length++] = new_word;
}

void wordlist_add_unique(WordList list, char * word)
{
    if ( wordlist_find(list, word) == -1 ) {
        wordlist_add(list, word);
    }
}

char * wordlist_word(WordList list, size_t index)
{
    if ( index >= list->length ) {
        fprintf(stderr, "word list accessed out of bounds\n");
        exit(EXIT_FAILURE);
    }
    return list->words[index];
}

int wordlist_find(WordList list, char * word)
{
    for ( int i = 0; i < list->length; ++i ) {
        if ( strcmp(list->words[i], word) == 0 ) {
            return i;
        }
    }
    return -1;
}

bool wordlist_contains(WordList list, char * word)
{
    return wordlist_find(list, word) != -1;
}

size_t wordlist_length(WordList list)
{
    return list->length;
}

logging.h:

#ifndef LOGGING_H
#define LOGGING_H

#include <stdbool.h>

void logging_enable(bool enabled);
void log_msg(char * fmt, ...);

#endif

logging.c:

#include <stdio.h>
#include <stdbool.h>
#include <stdarg.h>
#include "logging.h"

static bool logging_enabled = false;

void logging_enable(bool enabled)
{
    logging_enabled = enabled;
}

void log_msg(char * fmt, ...)
{
    if ( logging_enabled ) {
        va_list ap;
        va_start(ap, fmt);
        vfprintf(stderr, fmt, ap);
        va_end(ap);
    }
}

字典.txt:

apple
plate
words
finds
trunk
poked
tiger
horse
spill
horns
stuff
boxed
fried
biter
sword
tribe
shore
hoser
pills
fired

生成文件:

dictfind: dictfind.o wordlist.o logging.o
    cc -o dictfind dictfind.o wordlist.o logging.o

dictfind.o: dictfind.c wordlist.h logging.h
    cc -o dictfind.o dictfind.c -c -std=c99 -pedantic -Wall

wordlist.o: wordlist.c wordlist.h
    cc -o wordlist.o wordlist.c -c -std=c99 -pedantic -Wall

logging.o: logging.c logging.h
    cc -o logging.o logging.c -c -std=c99 -pedantic -Wall

clean:
    rm -f dictfind dictfind.o wordlist.o logging.o

带有样本输出:

paul@thoth:~/src/sandbox/dictfind$ make
cc -o dictfind.o dictfind.c -c -std=c99 -pedantic -Wall
cc -o wordlist.o wordlist.c -c -std=c99 -pedantic -Wall
cc -o logging.o logging.c -c -std=c99 -pedantic -Wall
cc -o dictfind dictfind.o wordlist.o logging.o
paul@thoth:~/src/sandbox/dictfind$ ./dictfind b r i t e
Match found: biter
Match found: tribe
paul@thoth:~/src/sandbox/dictfind$ ./dictfind d w s r o -v
Read 20 words into dictionary.
Made 120 words from input.
Adding found match: words
Adding found match: sword
Match found: words
Match found: sword
paul@thoth:~/src/sandbox/dictfind$ ./dictfind b i t e s
paul@thoth:~/src/sandbox/dictfind$ ./dictfind f t u s f -v
Read 20 words into dictionary.
Made 60 words from input.
Adding found match: stuff
Match found: stuff
paul@thoth:~/src/sandbox/dictfind$ ./dictfind a a a a h -v
Read 20 words into dictionary.
Made 5 words from input.
paul@thoth:~/src/sandbox/dictfind$ 

【讨论】:

  • 为了遵循您的回答,我减少了 malloc 指针的数量并尽可能多地替换为数组,如果任何指针为 nil,我确保退出程序,我确保有我的 '\0' 和每个数组上正确数量的字符。这无疑使事情变得更加安全和正确,但它仍然没有解决在 mods 之后仍然发生的比较问题:/.
  • @Vivick:iter[wc]=word; 显然也是错误的,因为您正在存储一个指向即将超出范围并不再存在的数组的指针。您应该使用strcpy() 来复制字符串。
【解决方案2】:

首先感谢大家非常有帮助的回答。 感谢 Paul Griffiths,我发现了我的重大错误:

我复制粘贴了他的作品来尝试一下,我很惊讶地没有看到任何结果,我瞬间想起了一件愚蠢的小事:我在 windows 上。 这意味着我的文件中有大量的 \r 导致程序永远找不到正确的匹配项。 因此,我只是在 babun 和 tada 上解决了“dos2unix f5.txt”问题

现在我发现了我的错误,我想我会使用(肯定的)对象将整个程序重写为 C++(对我来说更容易),并且可能像 Paul 那样构建侧库。

再次感谢您的回答;)。

记住孩子:Windows 文本编辑 -> \r

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-11
    • 2021-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多