Как прочитать и вернуть случайную строку из текста (C) - PullRequest
1 голос
/ 17 апреля 2020

Текст включает в себя 100 слов в каждой строке, 1 слово максимум 20 символов ниже кода печатает то же самое, я хочу это случайно, как редактировать мой код? Две функции printf выводят одно и то же слово. Я просмотрел все темы, но не был просветленным, потому что я новый ученик.

int main(){
char *str;
char *str_2;
    printf("%s",word("words.txt",str));
    printf("%s",word("words.txt",str_2));
}


char *word(char *file, char *str0) {
    int end, loop, line;
    int i;


   str0 = (char *)malloc(20);

    FILE *fd = fopen(file, "r");

    if (fd == NULL) {
        printf("Failed to open file\n");
        return (NULL);
    }

    srand(time(NULL));
    line = rand() % 100 + 1;

    for (end = loop = 0; loop < line; ++loop) {
        if (NULL == fgets(str0, 20, fd)) {
            end = 1;
            break;
        }
    }

    if (!end){
            fclose(fd);

            return str0;
            free(str0);

    }
}

1 Ответ

1 голос
/ 17 апреля 2020

Существует ряд ошибок и некоторые улучшения, которые необходимо внести.

Вот аннотированная версия вашего кода, показывающая ошибки и потенциальные изменения и исправления:

#include <stdio.h>
#include <time.h>
#include <stdlib.h>

char *
word(char *file, char *str0)
{
    int end, loop, line;
#if 0
    int i;
#endif

// NOTE/BUG: don't cast the return of malloc
#if 0
    str0 = (char *) malloc(20);
#else
    str0 = malloc(20);
#endif

    FILE *fd = fopen(file, "r");

// NOTE/BUG: opening and closing the file on _each_ call is wasteful -- having
// main open the file and passing the file descriptor is faster
    if (fd == NULL) {
        printf("Failed to open file\n");
        return (NULL);
    }

    // NOTE/BUG: put this in main
#if 0
    srand(time(NULL));
#endif
    line = rand() % 100 + 1;

    for (end = loop = 0; loop < line; ++loop) {
        if (NULL == fgets(str0, 20, fd)) {
            end = 1;
            break;
        }
    }

#if 1
    fclose(fd);
#endif

    if (!end) {
// NOTE/BUG: the fclose should _always_ be done (even on EOF) -- put it above
#if 0
        fclose(fd);
#endif

        return str0;
// NOTE/BUG: this will _never_ be executed -- so the return will leak this
// memory -- put free in main
#if 0
        free(str0);
#endif
    }

// NOTE/BUG: on EOF, we fall through to here -- we have no return statement
// for this case
#if 1
    return str0;
#endif
}

int
main(void)
{
    char *str;
    char *str_2;

#if 1
    srand(time(NULL));
#endif
// NOTE/BUG: passing the 2nd argument does nothing because word will toss any
// value
// NOTE/BUG: str and str_2 are _uninitialized
    printf("%s", word("words.txt", str));
    printf("%s", word("words.txt", str_2));

// NOTE/BUG: no return for main
#if 1
    return 0;
#endif
}

Вот очищенная и рабочая версия:

#include <stdio.h>
#include <time.h>
#include <stdlib.h>

char *
word(FILE *fd)
{
    char *str0;
    int end, loop, line;
    int len;

    len = 20;
    str0 = malloc(len);

    line = rand() % 100 + 1;

    rewind(fd);

    end = 0;
    for (loop = 0; loop < line; ++loop) {
        if (NULL == fgets(str0, len, fd)) {
            end = 1;
            break;
        }
    }

    if (end) {
        free(str0);
        str0 = NULL;
    }

    return str0;
}

int
main(void)
{
    char *str;

    srand(time(NULL));

    char *file = "words.txt";
    FILE *fd = fopen(file, "r");

    if (fd == NULL) {
        printf("Failed to open file\n");
        return 1;
    }

    for (int i = 1;  i <= 20;  ++i) {
        str = word(fd);
        if (str == NULL)
            continue;

        printf("%d: %s", i, str);

        free(str);
    }

    fclose(fd);

    return 0;
}

Выполнение malloc in word может быть расточительным. Это не совсем неправильно, если вы хотите, чтобы вызывающая сторона сохранила все строки в массиве.

Много раз для такой функции, как word, вызывающая сторона может передать указатель буфера и его максимальную длину в качестве аргументов. , Это делает word более похожим на fgets

Вот версия, которая делает это, чтобы проиллюстрировать альтернативный подход:

#include <stdio.h>
#include <time.h>
#include <stdlib.h>

int
word(FILE *fd,char *str0,int len)
{
    int found, loop, line;

    line = rand() % 100 + 1;

    rewind(fd);

    found = 1;
    for (loop = 0; loop < line; ++loop) {
        if (NULL == fgets(str0, len, fd)) {
            found = 0;
            break;
        }
    }

    return found;
}

int
main(void)
{
    char *str;
    int len = 20;

    srand(time(NULL));

    char *file = "words.txt";
    FILE *fd = fopen(file, "r");

    if (fd == NULL) {
        printf("Failed to open file\n");
        return 1;
    }

    str = malloc(len);

    for (int i = 1;  i <= 20;  ++i) {
        if (! word(fd,str,len))
            continue;

        printf("%d: %s", i, str);
    }

    fclose(fd);
    free(str);

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...