Thread: Reading random line from a text file

  1. #1
    Registered User
    Join Date
    Apr 2008
    Posts
    26

    Reading random line from a text file

    Hello,
    I really need help with this program. It's a wheel of fortune program. I think I'm really close to finishing it but I really need help adapting it to read a text file of any length and to make sure that when a random line is chosen from the text file it is not chosen again. Thanks again in advance.
    Code:
    int initialize_array(char phrase[], char puzzle[], char clue[]){
    	FILE* phraseFile; /*input file*/
    	char temp[100]; /*temporary array*/
    	int line; /*line from which word and clue are chosen*/
    	size_t i=0; /*counter for loop*/
    	int len; /*length of line from file*/
    
    
    	line=rand()%43+1; /*randomization of line*/
    	
    	phraseFile = fopen("clues.txt", "r"); /*opens file*/
    	            
    	if (!phraseFile) {
    		fprintf(stderr, "Oops - file not opened !\n"); /*if there is error in opening file program is exited*/
    		exit(1);
    		}
    
    		while(line--){
    			fgets(temp, 100, phraseFile); /*gets line and stores in temp*/
    		}
    		
    	len=strlen(temp);
    	if(temp[len-1]=='\n')
    		temp[len-1]=0; /*places the null terminating character after word*/
    		
    		/*separates clues from word*/
    		strcpy(clue,strtok(temp, "%"));
    		/*
    		strcpy(phrase,strtok(NULL,"%"));*/
    	char tmp[WORD_LENGTH];
    	strcpy(tmp,strtok(NULL,"%"));
    	strcpy(phrase, tmp + 1);
    	strcpy(puzzle,phrase);
    
    
    		/*strcpy(puzzle,phrase);*/
    	
    		while(i<strlen(puzzle)){
    			if(isalpha(puzzle[i])){
    				puzzle[i] = '*'; /*hides word*/
    				}
    				++i;
    			}
    	fclose(phraseFile);	/*closes file*/	
    	return i;
    }

  2. #2
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    IMO, your best bet is to do one of the following:

    1. Read the entire file into memory line by line, and from there manage which lines are selected.
    2. Manage which line is selected internally, and then read to that line in the file.


    If the file is not large, use option 1. If the file is huge or you won't be selecting many lines, use option 2.

  3. #3
    Registered User
    Join Date
    Apr 2008
    Posts
    26
    So to modify my code I would need to do
    while(fgets(temp,100, phraseFile)....but then I'm lost as to what I should do after that. I would appreciate any guidance. I really want to get this project done. I've been working on it for weeks (I'm a beginning C student) and things have been really slow. Please help me

  4. #4
    Registered User
    Join Date
    Apr 2008
    Posts
    26
    Could someone please guide me in how to correct this? Thank you.
    Code:
    int initialize_array(char phrase[], char puzzle[], char clue[]){
    	FILE* phraseFile; /*input file*/
    	char temp[100]; /*temporary array*/
    	int line; /*line from which word and clue are chosen*/
    	int i=0; /*counter for loop*/
    	int len; /*length of line from file*/
    	int count=0;
    
    	
    	phraseFile = fopen("clues.txt", "r"); /*opens file*/
    	            
    	if (!phraseFile) {
    		fprintf(stderr, "Oops - file not opened !\n"); /*if there is error in opening file program is exited*/
    		exit(1);
    		}
     		
    		while(fgets(temp,100,phraseFile)!=0){
    			++count;
    		}
    			
    		line= rand()%count;
    	
    		while(line--){
    			fgets(temp, count, phraseFile); /*gets line and stores in temp*/
    		}
    		
    	len=strlen(temp);
    	if(temp[len-1]=='\n')
    		temp[len-1]=0; /*places the null terminating character after word*/
    		
    		/*separates clues from word*/
    		strcpy(clue,strtok(temp, "%"));
    		/*
    		strcpy(phrase,strtok(NULL,"%"));*/
    char tmp[WORD_LENGTH];
    	strcpy(tmp,strtok(NULL,"%"));
    	strcpy(phrase, tmp + 1);
    	strcpy(puzzle,phrase);
     
     
    		/*strcpy(puzzle,phrase);*/
    	
    		while(i<strlen(puzzle)){
    			if(isalpha(puzzle[i])){
    				puzzle[i] = '*'; /*hides word*/
    				}
    				++i;
    			}
    	fclose(phraseFile);	/*closes file*/	
    	return i;
    }

  5. #5
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    3 things to fix:
    - Don't use exit in your function. Return an error instead! It's bad to use exit in a function because you never know if the parent function or any other functions need to perform cleanup work if it fails, or if it can recover.
    - fgets wants buffer, sizeof(buffer), file, not buffer, count, file (count being 0! - which means fgets will read nothing or error).
    - Don't use strcpy(..., strtok(...)). If strtok returns NULL, you will crash your program! Use strtok first, check for NULL, then copy.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  6. #6
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    Quote Originally Posted by Elysia View Post
    3 things to fix:
    - Don't use exit in your function. Return an error instead! It's bad to use exit in a function because you never know if the parent function or any other functions need to perform cleanup work if it fails, or if it can recover.
    exit can't do cleanup?
    Code:
    NAME
           exit - cause normal program termination
    
    SYNOPSIS
           #include <stdlib.h>
    
           void exit(int status);
    
    DESCRIPTION
           The  exit() function causes normal program termination and
           the value of status is returned to the parent.  All  func-
           tions registered with atexit() and on_exit() are called in
           the reverse order of  their  registration,  and  all  open
           streams are flushed and closed.

  7. #7
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Well, exit may cause functions not to do cleanup or try to recover or print appropriate error messages. It's not recommended to use it.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #8
    Registered User
    Join Date
    Apr 2008
    Posts
    26
    Thanks for those warnings. However what I'm really trying to focus on is getting the line. After changing fgets(temp, count, phraseFile) to say while(fgets(temp, 100, phraseFile), what else do I need to do to get this code running. Everytime I run my program I get a segmentation fault. Thanks for the help so far.

  9. #9
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    > Well, exit may cause functions not to do cleanup or try to recover or print appropriate error messages. It's not recommended to use it.


    I don't believe it, maybe you could explain or demonstrate?

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Well, I mean...

    Code:
    int foo1()
    {
        /* Some stuff */
        return ERROR_FAIL;
    }
    
    void foo2()
    {
        int error = foo1();
        if (error)
            log("Error in foo2 - call to foo1 failed with error: " + error);
    }
    
    void foo3()
    {
        foo1();
    }
    This code won't compile, of course, but it's enough for demonstration purposes.
    I mean, how does foo1 know what its parent function will do?
    If it calls exit, then the parent function never gets to execute that code.
    Sure, it can be caught with some functions registered with at_exit, but again, how would at_exit know the state of the program? The parent function would know and could handle the error, perhaps even recover, which isn't something that's easy to do if you call exit.

    helloamuro:
    Take a closer look at the last two lines of advice I offered. They can cause undefined behaviour and crashes if improperly used.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  11. #11
    Registered User
    Join Date
    Apr 2008
    Posts
    26
    I've made your corrections, but there still is a segmentation fault....

  12. #12
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    Quote Originally Posted by Elysia View Post
    Well, I mean...

    Code:
    int foo1()
    {
        /* Some stuff */
        return ERROR_FAIL;
    }
    
    void foo2()
    {
        int error = foo1();
        if (error)
            log("Error in foo2 - call to foo1 failed with error: " + error);
    }
    
    void foo3()
    {
        foo1();
    }
    This code won't compile, of course, but it's enough for demonstration purposes.
    I mean, how does foo1 know what its parent function will do?
    If it calls exit, then the parent function never gets to execute that code.
    Sure, it can be caught with some functions registered with at_exit, but again, how would at_exit know the state of the program? The parent function would know and could handle the error, perhaps even recover, which isn't something that's easy to do if you call exit.
    True, true. Wouldn't want to start an argument here, but foo1 is poorly designed. If it returns error codes, under what circumstances would it call exit? It seems like you could avoid this whole kludge simply by rewriting the parent function so that it calls exit instead:
    Code:
    #include <stdlib.h>
    int child ( void )
    {
       return -1;
    }
    
    void parent ( void )
    {
       if ( child() == -1 ) {
          /** log( "fubar'd" ); **/
          exit( 1 );
       }
       /** ... **/
    }
    If that's not possible, it should be documented behavior, so it's not a mystery that the child function would call exit. In any case, the proper way to use the child function depends on its preconditions. Ensure a return if exit is a problem.

    Hope that helps you understand the C library a little better.

  13. #13
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    1. you probably need to rewind your file before starting the read again
    2. temp[len-1] - check that len > 0 before it
    3. where tmp is defined?
    4. are all passed buffers big enough to store the parts of the string?
    5. check the return value of strtok before copying
    6. while(i<strlen(puzzle))
    better to write
    while(puzzle[i])
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  14. #14
    Registered User
    Join Date
    Apr 2008
    Posts
    26
    I can't use rewind (I'm familiar with it, but it hasn't been covered in my class) but would just opening and closing the file again be sufficient?

  15. #15
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    That's a waste of time (but it could be done). Are you allowed to use fseek then? It can do the same thing.
    Otherwise, you can do as MacGyver initially suggested: open the file and read everything into memory and deal with it from there.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 7
    Last Post: 02-02-2009, 07:27 AM
  2. Formatting a text file...
    By dagorsul in forum C Programming
    Replies: 12
    Last Post: 05-02-2008, 03:53 AM
  3. reading from text file
    By jamez in forum C Programming
    Replies: 3
    Last Post: 11-30-2005, 07:13 PM
  4. end of line in text file
    By spveer in forum C Programming
    Replies: 5
    Last Post: 08-18-2005, 12:43 AM
  5. Unknown Memory Leak in Init() Function
    By CodeHacker in forum Windows Programming
    Replies: 3
    Last Post: 07-09-2004, 09:54 AM