0

My code is as shown below:

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

int main()
{
    FILE *fp = fopen("text.txt", "r");
    char c;
    int d = 0;
    char arr[2000];

    do {
        c = fgetc(fp);
        d = d + 1;

        if (c == '\n') {
            arr[d] = ' ';
        } else
            arr[d] = c;
    } while (c != EOF);

    int z = strlen(arr);
    arr[0]= '\0';

    for (int i = 0;i < z; i++) {
        arr[i] = arr[i +1];
    }

    fclose(fp);

    return 0;
}

the code reads a string from a textfile and ands them to an array arr[2000](there are a lot of words in the text file). I wanted to ask if anybody knows a way for the code to read the textfile by each word separated by a space not by character.

So for example if i had an array arr with string : "Jack is a boy"

arr[0] would equal "Jack" not "J"

p.s(The reason for the for loop at the end that removes index 0 is because i keep getting a "(" character at the beginning of the array)

any help would be much appreciated.

Dappa jack
  • 145
  • 1
  • 2
  • 12
  • You might wan to make sure that the character you read is not `EOF` *before* you use it. Maybe doing like `while ((c = fgetc(fp)) != EOF) { ... }` instead. – Some programmer dude Nov 11 '15 at 19:26
  • Oh, and the string terminator should be the *last* character, without it the string functions like `strlen` will not work and you will get *undefined behavior*. – Some programmer dude Nov 11 '15 at 19:28
  • 1
    Also, the first character that you store should be `arr[0]`, so you should increment your index `d` after, not before, assignment to `arr[d]`. – M Oehm Nov 11 '15 at 19:28
  • As above, you need to move `d = d + 1;` below your `if` test (or just use e.g. `arr[d++] = ' ';` within the `if` test). There is also no need to call `strlen` to null-terminate. `d` already holds the index to the next char, so just `arr[d] = 0;`. – David C. Rankin Nov 11 '15 at 19:50
  • `char c;` --> `int c;` – chux - Reinstate Monica Nov 11 '15 at 21:07

3 Answers3

7

You said:

So for example if i had an array arr with string : "Jack is a boy"

arr[0] would equal "Jack" not "J"

To do that, arr[0] needs to be a pointer to a null terminated string. That means, arr has to be an array of pointers, not an array of chars.

char* arr[SOME_SIZE] = {0}; // Make SOME_SIZE large enough for your needs.

Now you have to figure out where to store the characters that you read from the file. You can use the method used in Easiest way to get file's contents in C to read the entire contents of the file. Assuming you got the code to read the contents of the file, let's you have:

char* fileContents = readFileContents("text.txt");

and now, fileContents points to an array that looks like:

+---+---+---+---+---+---+---+---+---+---+---+---+---+----+
| J | a | c | k |   | i | s |   | a |   | b | o | y | \0 |
+---+---+---+---+---+---+---+---+---+---+---+---+---+----+

Now, you'll need to traverse that array and make sure that:

  1. arr[0] - arr[3] point to the right locations in the array.
  2. The whitespace characters are replace by the null character so that arr[0] - arr[3] point to a null terminated string.
arr[0]              arr[1]       arr[2]   arr[3]
|                    |            |        |
v                    v            v        v
+---+---+---+---+----+---+---+----+---+----+---+---+---+----+
| J | a | c | k | \0 | i | s | \0 | a | \0 | b | o | y | \0 |
+---+---+---+---+----+---+---+----+---+-- -+---+---+---+----+

I hope that gives you enough information to implement the functionality you need.

Community
  • 1
  • 1
R Sahu
  • 204,454
  • 14
  • 159
  • 270
4

You get your extra character at the start because you start filling your array at arr[1].

Furthermore, you can make life even easier by using the fread function: size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); to read in a whole block of text at once. You can then separate it into words at your leisure.

Now if you also want to have an array "containing" all the separate words, you should look into an array of pointers to char, or char *array[100] (for an appropriate size of course). C doesn't handle strings automatically (as you seem to expect from the last bit of your question "arr[0] would equal "Jack" not "J"".

  • I would be wary of suggesting learning users use `fread` instead of the basic `fgetc`. While it is good to suggest other available functions, it is far more important to help them understand how to correctly do what it is they have questions about first. `fread`ing the entire file at once is faster, and so is `mmap`ing the file, but neither will help the OP use `fgetc` correctly. – David C. Rankin Nov 11 '15 at 20:11
2

There are three additional subtle issues you will want to look at:

int c = 0;  /* note: 'c' should be 'int' */

While char will work for normal characters, you will run into problems if you attempt to read a file containing multi-byte characters.

When you open a file with fopen, you need to check that the file is really open before you attempt to read from it. A simple test is all that is required:

if (!fp) {  /* validate file open succeeded */
    fprintf (stderr, "error: file open failed 'text.txt'.\n");
    return 1;
}

(note: if (!fp) is just shorthand for if (fp == NULL))

The next is the way you read c, assign it to array, and then test if c = EOF. What gets added to the array when c is EOF?

You need to test whether c = EOF before you assign c to arr and not assign it in the case of EOF (which is -1 generally). A quick change to your loop will work:

/* test c before you add it to the array */
while ((c = fgetc (fp)) != EOF)
{
    if (c == '\n') {
        arr[d++] = ' ';
    } else
        arr[d++] = c;
}
arr[d] = 0; /* null-terminate, note '\0' = 0 */
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85