Thread: Problem with I/O program

  1. #1
    Registered User
    Join Date
    Jun 2011
    Posts
    19

    Problem with I/O program

    I am in the process of writing a program that takes the input of a text file, recognizes all the unique words, and prints them into another text file.

    For some reason, when it prints a long list, it sometimes prints random blank lines in between words to the text file, thinking that it's a word. It might be because of subsequent new line characters, but I'm not sure.

    Code:
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<ctype.h>
    #define ROW 600
    #define COL 21
    int word_total = 0, line_num = 0, duplicates = 0, num_words = 0, total_word_len = 0;
    void read_text(FILE *fp1, char (*textArray)[21], char (*wordArray)[21]);
    void write_text(FILE *fp2, char (*textArray)[21]);
    void write_average(FILE *fp2, int total_word_len, int word_total);
    void write_max_min(FILE *fp2, char (*wordArray)[21]);
    
    int main(void)
    {
        FILE *fp1, *fp2;
        char textArray[ROW][COL], wordArray[ROW][COL];
        
        if((fp1 = fopen("in.txt", "r")) == NULL)
        {
              printf("Unable to read file. Press any key to exit.");
              getchar();
              exit(EXIT_FAILURE);
        }
        else
        {
              printf("Input file accessed successfully. Scanning stream ");
              printf("from in.txt.\n");
              read_text(fp1, textArray, wordArray);
        } 
        
        if((fp2 = fopen("out.txt", "w")) == NULL)
        {
               printf("Unable to write file. Press any key to exit.");
               getchar();
               exit(EXIT_FAILURE);
        }
        else
        {
              printf("Output file accessed successfully. Outputing stream ");
              printf("to file out.txt.\n");
              write_text(fp2, textArray);
              write_average(fp2, total_word_len, word_total);
              write_max_min(fp2, wordArray);
        } 
        
        printf("The program was able to access all files successfully.\n");
        printf("Program executed on %s at %s.\n", __DATE__, __TIME__);
            
        fclose(fp1);
        fclose(fp2);
        
        getchar();
        return 0;
    }
    
    void read_text(FILE *fp1, char (*textArray)[21], char (*wordArray)[21])
    {
        int i = 0, j = 0, h = 0;
        char ch = ' '; 
         
        while((ch = fgetc(fp1)) != EOF)
        {
                 if((ch == ' ')||(ch == '\n'))
                 {
                    i++;
                    j = 0;     
                 }
                 if((ch < 32)||(ch > 64)||((ch < 91)&&(ch > 96)&&(ch < 123)))
                 {
                       textArray[i][j] = tolower(ch);
                       j++;
                 }
        }
        word_total = i;   
        
      /*  for(h = 0; h < word_total; h++)
        {
        textArray[h][j] = wordArray[h][j];
        }
        */
    }
    
    void write_text(FILE *fp2, char (*textArray)[21])
    {
      fprintf(fp2, "Number of unique words = %d\n\n", (word_total - duplicates));
      
      int i;
         
          for (i = 0; i < (word_total - duplicates); i++) 
          {
              fprintf(fp2, "%d  ", line_num);  
              fprintf(fp2, "%s\n", textArray[i]);
              line_num++;
          }
          
          fprintf(fp2, "\nTotal number of words = %d", (word_total + duplicates));
    }
    
    void write_average(FILE *fp2, int total_word_len, int word_total)
    {      
        double avg;
        
        avg = total_word_len / word_total;
        
        fprintf(fp2, "\nAverage = %.2f\n", avg);
    }
    
    void write_max_min(FILE *fp2, char (*wordArray)[21])
    {
    
    }

  2. #2
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Code:
        while((ch = fgetc(fp1)) != EOF)
        {
                 if((ch == ' ')||(ch == '\n'))
                 {
                    i++;
                    j = 0;     
                 }
                 if((ch < 32)||(ch > 64)||((ch < 91)&&(ch > 96)&&(ch < 123)))
                 {
                       textArray[i][j] = tolower(ch);
                       j++;
                 }
        }
        word_total = i;
    Yep, it's due to multiple spaces or new lines. Each time you come across a single instance of those characters, you increment i and reset j. So if you hit two spaces in a row, you increment your word counter twice, leaving you with random data in that slot of textArray. You only need to do that when you go from being in a word (reading alpha chars) to being out of a word (reading non-alpha chars). You should probably have a flag called in_word or something. Also, you included ctype.h for the tolower function, but you must have missed some of the other, wonderful functions in there, like isalpha(). That will let you replace the ugly, incorrect line I highlighted in red above with the clearer if (isalpha(ch)).

  3. #3
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Check your bracketing... several syntax errors there...
    Also check for the right way to pass strings into a function... char (*textArray)[21]) ... isn't going to work

  4. #4
    Registered User
    Join Date
    May 2011
    Location
    Around 8.3 light-minutes from the Sun
    Posts
    1,949
    How are you doing Tater? Actually, he isn't trying to pass a string he is passing a character array. The syntax:
    Code:
    char (*textArray)[21]
    Is actually a pointer to an array of 21 characters.

    EDIT: Yes, yes a char array is a string.....
    Quote Originally Posted by anduril462 View Post
    Now, please, for the love of all things good and holy, think about what you're doing! Don't just run around willy-nilly, coding like a drunk two-year-old....
    Quote Originally Posted by quzah View Post
    ..... Just don't be surprised when I say you aren't using standard C anymore, and as such,are off in your own little universe that I will completely disregard.
    Warning: Some or all of my posted code may be non-standard and as such should not be used and in no case looked at.

  5. #5
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by AndrewHunter View Post
    How are you doing Tater? Actually, he isn't trying to pass a string he is passing a character array. The syntax:
    Code:
    char (*textArray)[21]
    Is actually a pointer to an array of 21 characters.
    Declared as a function parameter?

    All he needs is ... char *textarray

  6. #6
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    No Tater, I think you're misunderstanding. He's passing a 2-d array to the function, which is demoted to a pointer to an array of 21 chars. He could also have written char textArray[][21]. Just like you can do char *foo or char foo[] for a 1-d array.

  7. #7
    Registered User
    Join Date
    Jun 2011
    Posts
    19
    Code:
    void read_text(FILE *fp1, char (*textArray)[21], char (*wordArray)[21]);
    void write_text(FILE *fp2, char (*textArray)[21]);
    void write_max_min(FILE *fp2, char (*wordArray)[21]);
    I tried declaring those without the parenthesis around the pointer, but in the function calls that had the pointers, the compiler stated that I was passing an incompatible pointer type for the arguments. Putting parenthesis around the pointers worked, oddly enough.


    I fixed the issue about multiple spaces throwing off the numbering of the array, but now it the program outputs one blank line at the beginning of the output file.

    Code:
    void read_text(FILE *fp1, char (*textArray)[21], char (*wordArray)[21])
    {
        int i = 0, j = 0, in_char = 0;
        char ch = ' '; 
        
        while((ch = fgetc(fp1)) != EOF)
        {
                 if(!isalpha(ch))
                 {
                   in_char = 1;  
                 }
                 if(isalpha(ch))
                 {
                       if(in_char == 1)
                       {
                            i++;
                            j = 0;
                       }
                       textArray[i][j] = tolower(ch);
                       j++;
                       in_char = 0;
                 }
        }
        word_total = i;

  8. #8
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    You're close, but not quite there. I don't know why you called it "in_char", since you're always "in a char", and also your condition is backwards. in_word should be set to true (1) when you're reading alpha characters, and false (0) when reading non-alpha. Something like:
    Code:
    initialize in_word to false
    while ((ch = ...)
        if ch is alpha
            set in_word to true
            add ch to text at textArray[i][j] using tolower
            increment letter counter
        else if in_word  // this way, it will only happen once, when you transition from a word to a non-word
            null terminate current word
            increment word counter
            reset letter counter
            set in_word to false
        // otherwise, your loop will keep reading through the characters, discarding them and waiting for an EOF

  9. #9
    Registered User
    Join Date
    Jun 2011
    Posts
    19
    The function works and prints out the characters correctly. However, I am trying to pass the array of characters over to another array to compare the two, using strncmp to find unique words. When I try to do this the program eats characters of any word that is longer than nine digits. The commented out portion of the function is my attempt. I tried strncpy as well, but the program only output a blank list.

    Code:
    void read_text(FILE *fp1, char (*textArray)[21], char (*wordArray)[21])
    {
        int i = 0, j = 0, in_word = 0, h = 0;
        char ch = ' '; 
        
        while((ch = fgetc(fp1)) != EOF)
        {
                 if(isalpha(ch))
                 {
                   in_word = 1;  
                   textArray[i][j] = tolower(ch);
                   j++;
                 }
                 else if(in_word ==1)
                 {
                       i++;
                       j = 0;
                       in_word = 0;
                 }
        }
        word_total = i;   
        
       /* for(h = 0; h < word_total; h++)
        {
        textArray[h][j] = wordArray[h][j];
        }
        */
    
    }

  10. #10
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    You forgot something:
    Quote Originally Posted by anduril462 View Post
    Code:
    ...
            null terminate current word
    ...
    Code:
    for(h = 0; h < word_total; h++)
    {
        textArray[h][j] = wordArray[h][j];
    }
    Some notes on your current code:

    1. Your assignment there is backwards. wordArray needs to contain the unique elements of textArray.
    2. j has the value from the end of your while loop (which should be the length of the last word). You never initialize it or change it's value, so you're only copying one garbage character from the wrong array into the good array.
    3. You will need the value in word_total for your write function, so make read_text return an int, and return word_total at the end.
    4. You don't need a separate variable h, reuse i and j (you already save the important info in word_total).
    5. You also don't need to initialize ch since you assign it a value from fgetc before doing anything else with it.



    You were on the right track with strncmp and strncpy, but you should just use strcmp and strcpy (no 'n'), since you want to compare and copy the whole word, no matter it's length. Think about what you're trying to do: take all the words in textArray, and put them in wordArray with no duplicates. That means for every word you come across in textArray, you need to check everything in wordArray so far and make sure it's not there. This will require two (nested) loops. Write out the detailed steps in plain English and run through your algorithm by hand on paper with some small examples. Then translate your English solution to C code. Hopefully that gets you on your way.

  11. #11
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by anduril462 View Post
    No Tater, I think you're misunderstanding. He's passing a 2-d array to the function, which is demoted to a pointer to an array of 21 chars. He could also have written char textArray[][21]. Just like you can do char *foo or char foo[] for a 1-d array.
    OOPS... my bad. Sorry... I don't think I've ever seen it written like that before.

  12. #12
    Registered User
    Join Date
    Jun 2011
    Posts
    19
    Code:
                 else if(in_word ==1)
                 {
                       textArray[i][j] = '\0';
                       i++;
                       j = 0;
                       in_word = 0;
                 }
        }
        first_word_total = i;   
      
        
        for(i = 0; i < first_word_total; i++)
        {
              for(j = 0; j != '\0'; j++)
              { 
                 textArray[i][j] = wordArray[i][j];
              }
        }
        
        for(i = 0; i < first_word_total; i++)
        {
              for(j = 0; j != '\0'; j++)
              {
                    printf("%s\n", wordArray[i]);
              }
        }
        
        //return word_total;
    I went back a put a null character at the end of the line, indicating the end of the string. Now when I run the program, it doesn't seem to copy anything, and only prints a blank list... It doesn't compare anything yet, but I'll get to that after I get the arrays to copy successfully. The bold part of the code is just to display the contents of wordArray, for debug purposes. So far nothing yet.

    I've tried single and double for loops so far, but to no avail...

    I'll try strcpy since there is now '\0' at the end of each line and see where that gets me.

  13. #13
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    The inner loop is not for each character of each word. You have to search wordArray for the current word in textArray, to make sure it's not already there (remember, you're removing duplicates). That j loop needs to go from zero to however many words are already in word array (hint: you'll need to keep a second running total). The idea is something like:
    Code:
    for each word in textArray
        if that word is not in wordArray
            add it to the end of wordArray
            increment the count of words in wordArray
    That bold line is actually your second, inner loop. It scans all the words currently in wordArray for an instance of word (hint: you're comparing strings, use strcmp). If word is nowhere to be found, copy it into the last spot in wordArray (hint: copying strings, use strcpy), and increment the count of words in wordArray (hint: you'll need a second count variable).

  14. #14
    Registered User
    Join Date
    Jun 2011
    Posts
    19
    In the read text function:
    Code:
    int read_text(FILE *fp1, char (*textArray)[21], char (*wordArray)[21])
    {
        int i = 0, j = 0, in_word = 0, h = 0;
        char ch; 
        
        while((ch = fgetc(fp1)) != EOF)
        {
                 if(isalpha(ch))
                 {
                   in_word = 1;  
                   textArray[i][j] = tolower(ch);
                   j++;
                   total_word_len += j;
                 }
                 else if(in_word ==1)
                 {
                       textArray[i][j] = '\0';
                       i++;
                       j = 0;
                       in_word = 0;
                 }
        }
        first_word_total = i;   
      
        
        for(i = 0; i < first_word_total; i++)
        { 
                 strcpy(textArray[i], wordArray[i]);
        }
        
        for(i = 0; i < first_word_total; i++)
        {
              for(j = 0; j != '\0'; j++)
              {
                    if(strncmp(textArray[i], wordArray[i], j) == 0)
                    {
                        i++;
                        duplicates++;
                    }
                    else
                    {
                        strcpy(textArray[i], wordArray[i]);
                        word_total++;
                    }
              }
        }
        
    
        return word_total;
    }
    I cannot get the arrays to copy for some reason. I used a double for loop, that did not work either. This is my latest attempt, but still no luck...

    Code:
     for(i = 0; i < first_word_total; i++)
        { 
                 strcpy(textArray[i], wordArray[i]);
        }
    If someone could point me in the right direction I'd really appreciate it.

  15. #15
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    You aren't thinking this through very well, and I don't think you really know what your code is doing, so I'll break it down

    Code:
        for(i = 0; i < first_word_total; i++)
        { 
                 strcpy(textArray[i], wordArray[i]);
        }
    This loop copies every word from wordArray to textArray. One, you want to copy from textArray, to wordArray. You're totally backwards on this, so go read the docs. Second, you're copying every word, regardless of duplicates. Drop this loop entirely.

    Code:
        for(i = 0; i < first_word_total; i++)
        {
    This code basically says "for each word in textArray". That's fine, no need to change that bit.
    Code:
              for(j = 0; j != '\0'; j++)
              {
    This code says "for j from 0 to '\0'". The only problem is, '\0' has an integer value of 0, so this loop never executes! You want to go from 0 to how ever many words are currently in wordArray. That's from 0 to word_total, which isn't defined or initialized anywhere (neither is first_word_total!), so that tells me you didn't make much effort to compile and run your solution, or you're using global variables (read why that's a bad idea here: Global Variables Are Bad).
    Code:
                    if(strncmp(textArray[i], wordArray[i], j) == 0)
                    {
    You're comparing only the first j letters of textArray[i] with the first j letters of wordArray[i], but wordArray[i] doesn't exist yet, so you're comparing a word from your file with garbage. I told you earlier NOT to use strncmp, so don't. Use strcmp without the n. Also, once you fix your j loop, you'll want to use wordArray[j], since j is looping through each valid word in wordArray.
    Code:
                        i++;
                        duplicates++;
                    }
    You don't need the extra i++, it will always increment i at the end of the outer loop, so you will skip words with this. Drop that line. Also, just set duplicates to 1, there's no need to count them. You'll want to reset this to zero every time, right before your new and improved "for j" loop.
    Code:
                    else
                    {
                        strcpy(textArray[i], wordArray[i]);
                        word_total++;
                    }
              }
        }
        
        return word_total;
    }
    The rest of this looks fine.

    Now, please, for the love of all things good and holy, think about what you're doing! Don't just run around willy-nilly, coding like a drunk two-year-old. Programming is not about typing, it's about problem solving. Think about your problem. Think about your data representation. Think of how to manipulate that data into a solution. Do all of that in English (or your native language). Write it all down on paper and run through some examples by hand. Once you get the idea sorted out on paper, then you can start coding.

    Code:
     for(i = 0; i < first_word_total; i++)
        { 
                 strcpy(textArray[i], wordArray[i]);
        }
    As for the strcpy issue, did you read the strcpy docs? Read this and pay attention to the parameters.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. A C++ program problem.
    By hector_ronado in forum C++ Programming
    Replies: 1
    Last Post: 11-28-2009, 09:26 AM
  2. Having some problem with a GCF program
    By Requinex in forum C++ Programming
    Replies: 2
    Last Post: 08-08-2009, 09:59 AM
  3. Replies: 4
    Last Post: 10-16-2008, 07:30 PM
  4. Math Equation Program (I can't find the problem with my program!)
    By masked_blueberr in forum C Programming
    Replies: 14
    Last Post: 07-06-2005, 11:53 AM
  5. problem with program
    By classicrockcj in forum C Programming
    Replies: 3
    Last Post: 11-21-2003, 01:00 AM