0

I'm trying to read a file and a lines next line, to see if it starts with a space, for instance:

First line
 second line 
Third line
 fourth line

Where when I'm reading the file in, I want to check and see if the following line, has a space, if it does, I want to strcat the two lines (in this case the first and second line).

So for the first example:

1.) Read in the first line, read ahead to the second, see that their is a space, and strcat both strings, making "First linesecond line" (Repeat for any other lines that follow this pattern).

Here's my go at it:

int main(void) {
    FILE * file = fopen("file.txt","r");

    if(file==NULL) { return 0; }

    char * fileBuffer = malloc(sizeof(char)*100);
    char * temp = malloc(sizeof(char)*100);

    while(fgets(fileBuffer,100,file) != NULL) {
        if(isspace(fileBuffer[0])) {

            strcpy(temp,fileBuffer);

            //store line that has a space in static temporary variable
        }
        else {
            if(strcmp(temp,"") != 0) { //if temp is not empty
                strcat(fileBuffer,temp);
            }
        }
    }
    free(fileBuffer);
    free(temp);

    return 0;
}

However this doesn't work. What happens is when fgets gets executed, it reads the first line, it sees there is no white space, and then goes to the next line, sees there is white space, stores it, but now fileBuffer doesn't contain the first line anymore, but the second.

So when I strcat the next time,I don't get the right result of "First linesecond line".

Instead i get the result of the third line mixed with the second, which is not what I want.

I'm not exactly sure how to fix my logic here, any ideas?

TTEd
  • 309
  • 1
  • 10

3 Answers3

2

fix your logic like this:

#define LINE_SIZE 100

int main(void) {
    FILE * file = fopen("file.txt","r");

    if(file==NULL) { perror("fopen"); return -1; }

    char * fileBuffer = malloc(LINE_SIZE);
    char * temp = malloc(LINE_SIZE * 2);//Binding of the string is only once

    while(fgets(fileBuffer, LINE_SIZE, file) != NULL) {
        if(isspace(fileBuffer[0])) {
            temp[strcspn(temp, "\n")] = 0;//remove newline
            strcat(temp, &fileBuffer[1]);
            printf("%s", temp);
        }
        else {
            strcpy(temp, fileBuffer);
        }
    }
    fclose(file);
    free(fileBuffer);
    free(temp);

    return 0;
}
BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70
1

You have several additional considerations you will need to deal with. The first being, you need to remove the trailing '\n' include in the read by fgets. To do that, you will need the length of the line read. You can then remove the trialing '\n' by overwriting it with a nul-terminating character. e.g.:

while (fgets (buf1, MAXC, fp)) {
    size_t len1 = strlen (buf1);  /* get length */
    if (len1 && buf1[len1-1] == '\n') buf1[--len1] = 0; /* remove \n */

Another consideration is how to manage allocation and freeing of the memory you use for the combined line. Since you are reading both the first part and then second part of your final line from relatively fixed length strings, it would make more sense to use 2 static buffers, one for reading the line, and one for holding a copy of the first. You can allocate for the final result. e.g.

enum { MAXC = 100 };  /* constant for max characters */
...
int main (int argc, char **argv) {

    char buf1[MAXC] = {0};
    char buf2[MAXC] = {0};
    char *both = NULL;

Once you have both parts of your line ready to combine, you can allocate exactly the space needed, e.g.

        if (*buf1 == ' ' && *buf2) {
            both = malloc (len1 + strlen (buf2) + 1);
            strcpy (both, buf2);
            strcat (both, buf1);
            ...

Don't forget to free both after each allocation. Putting the pieces together, and fixing the logic of your comparisons, you could end up with a solution like the following:

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

enum { MAXC = 100 };

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

    char buf1[MAXC] = {0};
    char buf2[MAXC] = {0};
    char *both = NULL;
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
    if (!fp) {
        fprintf (stderr, "error: file open failed '%s'.\n,", argv[1]);
        return 1;
    }

    while (fgets (buf1, MAXC, fp)) {
        size_t len1 = strlen (buf1);
        if (len1 && buf1[len1-1] == '\n') buf1[--len1] = 0;
        if (*buf1 == ' ' && *buf2) {
            both = malloc (len1 + strlen (buf2) + 1);
            strcpy (both, buf2);
            strcat (both, buf1);
            printf ("'%s'\n", both);
            free (both);
            *buf2 = 0;
        }
        else
            strcpy (buf2, buf1);
    }
    if (fp != stdin) fclose (fp);

    return 0;
}

Output

$ ./bin/cpcat ../dat/catfile.txt
'First line second line'
'Third line fourth line'

Look it over and let me know if you have any questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • Sure you know I'm not a fan of `fgets (buf1, MAXC, fp)) { size_t len1 = strlen (buf1); buf1[len1-1] = 0;` as it is a hacker exploit to make the first `char` `fgets()` reads a null character. [other ideas](http://stackoverflow.com/q/2693776/2410359) Further, last line of file may not have \n – chux - Reinstate Monica Feb 16 '16 at 22:55
  • 1
    Yes, I appreciate that. The intent was not to stray too far off the concatenation rabbit trail. However, you are 100% correct. The general check on `if (len1)` should have been included and the normal checks on the last char being a `newline` should be there as well. Fixed `:)` – David C. Rankin Feb 16 '16 at 23:27
0

Really a quick and dirty way

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

int main(void) {

    FILE * file = fopen("file.txt", "r");

    if (file == NULL) { return 0; }

    char fileBuffer[100];
    char temp[100];
    int first = 1;

    while (fgets(fileBuffer, 100, file) != NULL) {
        if (isspace(fileBuffer[0])) {

            strcat(temp, fileBuffer);
            //store line that has a space in static temporary variable
        }
        else {
            if (first == 1){
                strncpy(temp, fileBuffer, sizeof(temp));

                // Remove the end line
                temp[strlen(temp) - 1] = 0;
                strcat(temp, " ");
                first = 0;
            }
            else{
                if (strcmp(temp, "") != 0) { //if temp is not empty
                    strcat(temp, fileBuffer);

                    // Remove the end line
                    temp[strlen(temp) - 1] = 0;
                    strcat(temp, " ");
                }

            }

        }
    }
    printf("%s", temp);
    free(fileBuffer);
    free(temp);

    return 0;
}

Output: enter image description here

HoKy22
  • 4,057
  • 8
  • 33
  • 54