0

The input text file is like so:

Hello my
name is 
mark.
and
im 
going
to
love
c!

Code:

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

 int main(int argc, char *argv[]){
FILE *pFile;
char x[60];

pFile = fopen("test0.txt","r");

if(pFile != NULL){
    while(fscanf(pFile, " %60s", x) == 1){
        printf("%s",x);
 }

}
}

Output text file is:

Hellomynameismark.andimgoingtolovec!

I want the Output to be like:

Hello my name is mark. and im going to love c!

Very new C programmer so only know the basics.

Edit----

   int main(int argc, char *argv[]){
FILE *pFile;
char x[60],line[60];

pFile = fopen("test0.txt","r");

while(!feof(pFile)){

        fgets(line, 60, pFile);
        strtok(line, "\r\n");
        printf("%s", line );
    }
    fclose(pFile);

Output:

 Hello myname is mark.andim goingtolovec!

This does not leave spaces between new lines. However if I take out the strtok line the output will be like this:

Hello my
name is 
mark.
and
im 
going
to
love
c!

--Edit

 .sp 2
 .ce
 This is an example file for formatting.
 .sp 1
 The above line
 was formatted using a .ce 1 command, which means 'centre
 the following line',
 so it should appear in the 
 centre of the page.
 The paragraph was separated from the heading using
 a .sp 1 command to create a single blank line.
 There should also be two blank lines above the centred heading to make            reading it slightly easier.
bob9123
  • 725
  • 1
  • 9
  • 31

3 Answers3

4

The simple answer is:

while(fscanf(pFile, " %59[^\n]%*c", x) == 1)

Here %[^\n] uses the character class [stuff] to read everything up to the newline. %*c simply reads and discards the newline without adding it to the match count for fscanf.

However for line-oriented input, you should really use one of the line-oriented functions provided by the standard library (e.g. fgets or POSIX getline).

Using fgets & strtok

As you have taken from the comment, the use of feof is going to cause you nothing but grief. You will want to simply use the return of fgets to determine end of file. Here is an example that puts all the pieces of the puzzle together:

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

#define MAXWDS  20
#define MAXCHR  60

int main (int argc, char **argv) {

    char line[MAXCHR] = {0};
    char *words[MAXWDS] = {NULL};
    FILE *pFile = NULL;
    size_t i, index = 0;

    /* open file for reading (if provided), or read from stdin */    
    if (!(pFile = argc > 1 ? fopen (argv[1], "r") : stdin)) {
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    while (fgets (line, 60, pFile)) 
    {
        char *p = line;

        /* split line into tokens, stored in words[] */
        for (p = strtok (p, " \r\n"); p; p = strtok (NULL, " \r\n")) {
            words[index++] = strdup (p); /* allocate & copy */

            if (index == MAXWDS)    /* check pointer limit */
                break;
        }

    }
    if (pFile != stdin) fclose (pFile);

    /* output in a single line */
    for (i = 0; i < index; i++) {
        printf (" %s", words[i]);
        free (words[i]);            /* free allocated memory */
    }

    putchar ('\n');

    return 0;
}

Compile

gcc -Wall -Wextra -o bin/fgets_strtok fgets_strtok.c 

Output

$ ./bin/fgets_strtok dat/hellomark.txt
 Hello my name is mark. and im going to love c!

Note: to simply print the line out with spaces between the words, as long as there is already a space between each of the words in each line, there is no reason to go to the trouble to separate each line into individual words, you can simply print the contents of each line out in a space separate fashion. The only issue you run into using fgets is that it will also read the newline (or carriage return, newline) as part of the string. That is simple to remove. You can replace the entire read loop with:

while (fgets (line, 60, pFile)) 
{
    size_t len = strlen (line);

    /* strip trailing newline (or carriage return newline ) */
    while (len && (line[len-1] == '\n' || line[len-1] == '\r'))
        line[--len] = 0;  /* overwrite with null-terminating char */

    words[index++] = strdup (line); /* allocate & copy */

    if (index == MAXWDS)    /* check pointer limit */
        break;
}

Output

$ ./bin/fgets_mark <dat/hellomark.txt
 Hello my name is mark. and im going to love c!

Standard Way to Read from File Only (not File or stdin)

I apologize for the getting ahead of you a bit by including a way to either open a file (if provided on the command line) or read from stdin (if no filename was provided). The standard way is to first check that the correct number of arguments were provided on the command line, and then open the filename provided, validate it is open, and then process input. What I did was throw a ternary operator into the fopen command that said.

pFile = argc > 1 ? fopen (argv[1], "r") : stdin

The right side of the '=' sign is a ternary operator, which is simply a shorthand for if -> then -> else. What it does is ask is argc > 1? If that tests true, then pFile = fopen (argv[1], "r");. If argc > 1 tests false, then pFile = stdin;

See if the standard way makes more sense:

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

#define MAXWDS  20
#define MAXCHR  60

int main (int argc, char **argv) {

    char line[MAXCHR] = {0};
    char *words[MAXWDS] = {NULL};
    FILE *pFile = NULL;
    size_t i, index = 0;

    /* validate sufficient input */
    if (argc < 2 ) {
        fprintf (stderr, "error: insufficient input, usage: %s filename\n", argv[0]);
        return 1;
    }

    /* open file provided on command line for reading */
    pFile = fopen (argv[1], "r");
    if (!pFile) {
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    while (fgets (line, 60, pFile)) /* read each line in file */
    {
        size_t len = strlen (line);

        /* strip trailing newline (or carriage return newline ) */
        while (len && (line[len-1] == '\n' || line[len-1] == '\r'))
            line[--len] = 0;  /* overwrite with null-terminating char */

        words[index++] = strdup (line); /* allocate & copy */

        if (index == MAXWDS)    /* check pointer limit */
            break;
    }
    if (pFile != stdin) fclose (pFile);

    /* output in a single line */
    for (i = 0; i < index; i++) {
        printf (" %s", words[i]);
        free (words[i]);            /* free allocated memory */
    }

    putchar ('\n');

    return 0;
}
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • Thanks for the answer. I was using fgets earlier for line by line analyse. Can it work similarly for word by word? – bob9123 Nov 03 '15 at 02:12
  • Yes/no, what you do is read the entire line and then use `strtok` to break the line into individual tokens. – David C. Rankin Nov 03 '15 at 02:13
  • Should the line begin with whitespaces, `fscanf(pFile, " %59[^\n]%*c", x)` will not retain them. – chux - Reinstate Monica Nov 03 '15 at 02:18
  • Good catch, to preserve leading whitespace, remove the space in the format string before the first `%` (e.g. `fscanf(pFile, "%59[^\n]%*c", x)` – David C. Rankin Nov 03 '15 at 02:24
  • Hold on, I'll give it a look. OH NO NO see [**Why is “while ( !feof (file) )” always wrong?**](http://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong?s=1|2.6418), I'll update the answer. – David C. Rankin Nov 03 '15 at 02:24
  • `fscanf(pFile, "%59[^\n]%*c", x)` fails to read _anything_ should the line consists of only `'\n'`. The short story is that `fscanf()` is challenging to read _lines_. Suggest `fgets()` or `fgetc()`. – chux - Reinstate Monica Nov 03 '15 at 02:40
  • 1
    There is always grief to be had trying to shoehorn a line into a `Xscanf` format string -- no question about it `:)` – David C. Rankin Nov 03 '15 at 02:51
  • @DavidC.Rankin Thanks for the through answer! Now when I run the program the output just flickers like it's waiting for an input. Am I supposed to add anything to the code? Sorry if this is a trivial question. Very new to C and tired – bob9123 Nov 03 '15 at 03:06
  • Umm, yes -- sorry, you either provide the filename to read on the command line (see my **Output** examples) or you read the file from `stdin` (e.g. `cat filename | ./progname` or redirect it `./progname – David C. Rankin Nov 03 '15 at 03:09
  • The textfile I have is called "test0.txt" It is saved in the same directory as the C program. After I type in cprogram.exe in CMD to run the program do I just put test0.txt for the input? – bob9123 Nov 03 '15 at 03:19
  • Yes, just type `./yourprogname test0.txt` - I'll add the standard way to specify a file so it is more clear. – David C. Rankin Nov 03 '15 at 03:20
  • Thanks so much. However there is another major problem. Using testfile.txt with the small text file is fine. However when I use it with a bigger textfile with many lines it crashes. 1 [main] x 7336 cygwin_exception::open_stackdumpfile: Dumping stack trace to x.exe.stackdump – bob9123 Nov 03 '15 at 03:26
  • @DavidC.Rankin I will edit post and add the textfile. – bob9123 Nov 03 '15 at 03:26
  • I added an explanation and then standard way of opening a file. Look at the addition under **Standard Way to Read from File Only (not File or stdin)**. Good luck with C. C takes time to learn, so don't get frustrated, just keep at it. Learn C, and you will never need to learn another language, but if you do, you will understand programing from such a fundamental level, learning an additional language is a piece of cake. – David C. Rankin Nov 03 '15 at 03:30
  • @DavidC.Rankin Also a dump file if need it. – bob9123 Nov 03 '15 at 03:30
  • @DavidC.Rankin Thanks for the words of encouragement. Literally spent 6-8 hours with hardly any progress, kind of frustrating. – bob9123 Nov 03 '15 at 03:31
  • Sure, you can just open a second file and write to it with `fprintf` instead of `printf`. Also note: there is no need to `free` the memory where I did - you can do it later and keep the memory around until you are done with it. Sure - on the encouragement, I beat my head into many a wall before it all made sense. Who knows, you may be the next Linus Torvalds, and I'm just doing my part to help `:)` – David C. Rankin Nov 03 '15 at 03:32
  • @DavidC.Rankin Sorry so to resolve the error I have to change the printf? – bob9123 Nov 03 '15 at 03:40
  • No, let me see what you are doing, there should be no error at all. I went for a snack. OK, I don't quite know what code you are using now. Do me a favor and just copy/paste the bottom full-code I posted and let me know if you still have an error. I am using your same input file... And.. are you saying you are getting the mess at the bottom of your questions as output? It looks like you are trying to input a MS-word (or other formatted file). Make sure your input file is `plain-text` (e.g. notepad on windows). – David C. Rankin Nov 03 '15 at 03:43
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/94045/discussion-between-david-c-rankin-and-bob9123). – David C. Rankin Nov 03 '15 at 03:50
1

A simple state machine does the trick - no line length limitation.

#include <stdio.h>

 int main(void) {
   FILE *pFile = fopen("test0.txt","r");
   if(pFile != NULL) {
     int previous_isspace = 0;
     int ch;
     for (;;) {
       ch = fgetc(pFile);
       if (ch == EOF) break;
       if (isspace(ch)) {
         previous_isspace = 1;
       } else {
         if (previous_isspace == 1) {
           fputc(' ', stdout);
         }
         previous_isspace = 0;
         fputc(ch, stdout);
       }  
     }
     fclose(pFile);
     fputc('\n', stdout);   // If code should have a \n at the end
   }
 }
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Thanks for the answer however I'm not sure if I can fully use this. Later in the program I need to get the lengths of specific words. So I need to read word by word and get the length of each word and increment a counter. Can I implement this feature with this code? – bob9123 Nov 03 '15 at 02:43
  • #bob9123 That is another question. Best to post all your goals in one post or use them in a subsequent post. And yes- modify the code to create a counter - resetting to 0 on each space. When a space or EOF occurs, assess the length of the word as needed - your comment is fuzzy on the requirements. IMO, code does not need to read word-by-word. – chux - Reinstate Monica Nov 03 '15 at 02:50
0

I think, It is sufficient take a look am i miss anything.

if(pFile != NULL){
      //  while(fscanf(pFile, " %60s", x) == 1){
            while (fgets(x, sizeof(x), pFile) != NULL) {
             token = strtok(x,"\r\n");
             if(token != NULL)
                    printf("%s ",x);
             else
                    printf("%s",x);
            }
            fclose(pFile);
    }
13krn
  • 541
  • 4
  • 9
  • Mostly arcane problems- not usually encountered: 1) should the word exceed `sizeof(x)-1` in length, then an uncalled for space will be injected. 2) Should the file end with a non-`"\r\n"`, code will print out a trailing `' '`. 3) an embedded `'\0'` in the line will not print all the word in `printf("%s",x)` – chux - Reinstate Monica Nov 03 '15 at 03:09