theNewPlayer
theNewPlayer

Reputation: 37

How to Read and Return Random Line From Txt(C)

Text include 100 word in every line,1 word max 20 character below code prints same thing,ı want this random,how to edit my code? Two printf functions print the same word. I browsed related all topics but I wasn't enlightened, because I'm a new learner.

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

    }
}

Upvotes: 1

Views: 211

Answers (1)

Craig Estey
Craig Estey

Reputation: 33601

There are a number of bugs and some improvements to be made.

Here's an annotated version of your code showing bugs and potential changes and fixes:

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

Here's a cleaned up and working version:

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

Doing malloc in word can be wasteful. It's not absolutely wrong, if you intend for caller to save all the strings in an array.

Many times, for a function such as word, caller can pass down the buffer pointer and its maximum length as arguments. This makes word be more similar to fgets

Here's a version that does that, to illustrate an alternate approach:

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

Upvotes: 2

Related Questions