0

My program reads a txt file and can print all the contents one by one to the console but I have to store every variable in a different string and then print them out seperatly to the console.

Expected output is :

///////////
First word: Grep
Second word: danger
Third word: <
////////////  
First word: ls
Second word: -a
Third word : -
/////////

Output of the program:

 grep
 danger
 <
ls
-a
-

Input file content:

grep danger <
ls -a wc hw2 . c >
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <ctype.h>

#include <sys/types.h>

#include <sys/stat.h>

int main(int argc, char* argv[])
{
    FILE * file;
    file = fopen("commands.txt","r");
    char *token;
    const char s[2] = " ";
    
    fseek(file,0,SEEK_END);
    int length = ftell(file);
    fseek(file,0,SEEK_SET);
    
    char*string = malloc(sizeof(char) * (length+1));
    
    char c;
    int i = 0 ;
    
    while( (c= fgetc(file)) != EOF) {
        string[i]=c;
        i++;
    }
   
    string[i]='\0';
    
    token = strtok(string, s);
    while( token != NULL ) {
        printf( " %s\n", token );
        token = strtok(NULL, s);
    }
    
    return 0;
}
Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
  • 2
    Please note that [`fgetc`](https://en.cppreference.com/w/c/io/fgetc) returns an **`int`**. This is actually rather important when you want to compare with the `int` value `EOF`. – Some programmer dude Dec 08 '22 at 13:42
  • OT: You should check out `fread` See https://man7.org/linux/man-pages/man3/fread.3.html – Support Ukraine Dec 08 '22 at 13:44
  • 1
    To me it's unclear what prevents you from printing the currently missing output. – Support Ukraine Dec 08 '22 at 13:45
  • All I need is add First word: to the start of the words but because I am in a while loop I dont know how to do it – Eren Beno Beno Dec 08 '22 at 13:50
  • Do you have to save file contents to variables? is this compulsory? – mlwn Dec 08 '22 at 13:53
  • Actually its not compulsory but I cant add Second word: Third word:, so I thought if ı save to variables ı can print them more easily like first word: variable1; – Eren Beno Beno Dec 08 '22 at 13:57
  • Whenever you can avoid saving char arrays to variables, avoid it... I have a solution in mind, but I am doing something else now... I'll post it later, I promise. – mlwn Dec 08 '22 at 13:59
  • Can you put the content of the txt file as well?? I feel "///////////" comes on each new line... – mlwn Dec 08 '22 at 14:00
  • Content of txt file I am reading: grep danger < ls -a wc hw2 . c > – Eren Beno Beno Dec 08 '22 at 14:01
  • 1
    is it a single line?? then why first, second, third, then again first, second ... why not "forth" – mlwn Dec 08 '22 at 14:08
  • they are on different lines grep danger < is the first line 2. line is the ls -a – Eren Beno Beno Dec 08 '22 at 14:21
  • All I need is how I can add First word: before each first word and Second word: before 2.words of each line because I am in while loop I couldnt find a way to do it – Eren Beno Beno Dec 08 '22 at 14:22
  • take it easy :))))) – mlwn Dec 08 '22 at 14:22
  • Please add the input to the question itself, where you can also write several lines. In comments, you can only write a single line. The question itself should contain all important information. It should not be necessary to read the entire comments section to be able to understand the question. – Andreas Wenzel Dec 08 '22 at 14:22
  • There are no inputs for this program it only reads a file which it already exists in OS – Eren Beno Beno Dec 08 '22 at 14:25
  • Aside: This entire Q&A, comments included, reads as an [XY Problem](https://xyproblem.info/), with an uncertainly around the actual expectations of this program. The evidence here (the preemptive headers, the contents of the file, etc.) point to this being a preliminary exercise towards building a simple shell. If so, you will surely want to learn how to store the file contents, or it will be very difficult to solve the *next* problem(s) (executing the commands, piping data). The exercise of printing them out afterwards is likely just a way to test that you have done the first part correctly. – Oka Dec 08 '22 at 15:22

2 Answers2

0

I suggest that you create a loop which reads and processes one line at a time. In order to read a single line at once, you can use the function fgets. This is easier than reading a single character at a time using fgetc.

You can define an array which maps the numbers 1 to 10 to the individual string literals "First", "Second", "Third", etc:

const char *map[] = {
    "Zeroth",
    "First", "Second", "Third", "Fourth", "Fifth",
    "Sixth", "Seventh", "Eighth", "Ninth", "Tenth"
};

Now you can then change the lines

while( token != NULL ) {
    printf( " %s\n", token );
    token = strtok(NULL, s);
}

to:

for ( int i = 1; i < 11 && token != NULL; i++ ) {
    printf( "%s word: %s\n", map[i], token );
    token = strtok(NULL, s);
}

That way, it will print:

First word: Grep
Second word: danger
Third word: <

After making these changes, your program should look like this:

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

#define NUM_MAPPINGS 11

int main( void )
{
    FILE *file;
    char line[200];
    char *token;
    const char *delimiter = " ";
    const char *separator = "///////////";

    const char *map[NUM_MAPPINGS] = {
        "Zeroth",
        "First", "Second", "Third", "Fourth", "Fifth",
        "Sixth", "Seventh", "Eighth", "Ninth", "Tenth"
    };

    //attempt to open file
    file = fopen( "commands.txt", "r" );
    if ( file == NULL )
    {
        fprintf( stderr, "Error opening file!\n" );
        exit( EXIT_FAILURE );
    }

    //print separator
    printf( "%s\n", separator );

    //process one line per loop iteration
    while ( fgets( line, sizeof line, file ) != NULL )
    {
        //remove newline character from input, if it exists
        line[strcspn(line,"\n")] = '\0';

        //find first token
        token = strtok( line, delimiter );

        for ( int i = 1; i < NUM_MAPPINGS && token != NULL; i++ )
        {
            //print current token
            printf( "%s word: %s\n", map[i], token );

            //find next token
            token = strtok( NULL, delimiter );
        }

        //print separator
        printf( "%s\n", separator );
    }

    //cleanup
    fclose( file );
    
    return 0;
}

For the input specified in the question, this program has the following outptu:

///////////
First word: grep
Second word: danger
Third word: <
///////////
First word: ls
Second word: -a
Third word: wc
Fourth word: hw2
Fifth word: .
Sixth word: c
Seventh word: >
///////////
Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
  • I'll parrot my other comment about using `perror` to avoid inexact error messages (*""Error opening file!"*). – Oka Dec 08 '22 at 15:23
  • @Oka: Yes, on most platforms, it would probably be better to use `perror`. On the other hand, in contrast to POSIX, ISO C does not require `fopen` to set `errno` when it fails. Therefore, using `perror` could yield a misleading error message such as `fopen: No error`. The best solution would probably be to set `errno` to `0` before the call to `fopen` and then, if `fopen` fails, to check `errno == 0` before calling `perror`. However, I will not do that in my answer, because that is not related to the issue that OP is having. – Andreas Wenzel Dec 08 '22 at 15:29
0

Good answer...

I expanded it a bit :)

#include <stdio.h>
#include <stdint.h>

void my_print(int num, char *s)
{
  char level_0[19][12] =
  {
    "First",
    "Second",
    "Third",
    "Forth",
    "Fifth",
    "Sixth",
    "Seventh",
    "Eighth",
    "Nineth",
    "Tenth",
    "Eleventh",
    "Twelveth",
    "Thirteenth",
    "Forteenth",
    "Fifteenth",
    "Sixteenth",
    "Seventeenth",
    "Eighteenth",
    "Nineteeth"
  };

  char level_1[8][7] =
  {
    "Twent",
    "Thirt",
    "Fort",
    "Fift",
    "Sixt",
    "Sevent",
    "Eight",
    "Ninet"
  };

  if (num < 20)
  {
    printf("%s word: %s\n", level_0[num - 1], s);
  }

  else if (num % 10 == 0)
  {
    printf("%sieth word: %s\n", level_1[num/10 - 2]);
  }

  else
  {
    printf("%sy-%s word: %s\n", level_1[num/10 - 2], level_0[num%10 - 1], s);
  }

}

int get_token(FILE *fp, char *s, int max_length)
{
  char c;
  int counter = 0;

  s[0] = '\0';

  while (!feof(fp))
  {
    if (counter == max_length) { return -2; }

    c = getc(fp);

    if (c == ' ') { return 1; }
    if (c == '\n') { return 2; }
    *s = c;
    s++;
    *s = '\0';
    counter++;
  }

  return -1;
}

int main(int argc, char *argv[])
{
  if (argc != 2)
  {
    printf("Arguments Error.\nUsage: parse_words [filename].\n");
    
    return 1;
  }

  const char *fname = argv[1];
  FILE *fp;
  char token[80];
  size_t len = 80;
  int word_count = 0;
  int get_token_state;

  fp = fopen(fname, "r");

  if (fp == NULL)
  {
    printf("Error opening file %s!\n", fname);
    
    return 1;
  }

  printf("///////////\n");

  while ((get_token_state = get_token(fp, token, len)) != -1)
  {
    if (get_token_state == -2)
    {
      printf("Warning, overflow near %s\n.", token);
    }

    else if (get_token_state == 1)
    {
      word_count++;
      my_print(word_count, token);
    }

    else if (get_token_state == 2)
    {
      word_count++;
      my_print(word_count, token);
      word_count = 0;
      printf("///////////\n");
    }
  }

  fclose(fp);

  return 0;
}
mlwn
  • 1,156
  • 1
  • 10
  • 25
  • 1
    [Why is “while( !feof(file) )” always wrong?](https://stackoverflow.com/q/5431941/2505965) – Oka Dec 08 '22 at 15:09
  • 1
    Errors should be printed to `stderr`. Use `perror` to avoid canonically useless error messages like *"Error opening file"*. – Oka Dec 08 '22 at 15:13