Search code examples
cio

Splitting rows of a file in half (C)


Using just I/O system calls, I should write I program in C that takes a file as input and prints in output its contents splitting each line in half. More specifically, if a line is n characters long, the program must print the first n/2 characters of a line, followed by a '\n' print, followed by its second n/2 characters. I wrote down a possible solution but it doesn't working very well, splitting the correct lines for a half of the file content and ignoring the rest.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#define LEN 5000

void half_rows (char* f);
void freebuf (char arr[], int n);

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

    if (argc != 2)
        fprintf (stderr, "Usage %s: <file>\n", argv[0]), exit(1);

    char* file = argv[1];
    half_rows (file);

    return 0;

}

void half_rows (char* f){

    char c;
    char buf[LEN];
    int fd, nread, n, rest, up;
    if (( fd = open (f, O_RDONLY)) < 0)
        perror("opening error"), exit(1);
    int cur = lseek (fd, 0, SEEK_CUR);
    int finalpos = lseek (fd, 0, SEEK_END);
//  lseek (fd, cur, SEEK_SET);

    do{
        lseek (fd, cur, SEEK_SET);
        if ((nread = read (fd, &c, sizeof(c))) < 0)
            perror("reading error"), exit(1);
        buf[cur] = c;
        if ( buf[cur] == '\n' || buf[cur] == '\0'){
            rest = cur % 2;
            if (rest == 0)
                n = cur / 2;
            else{
                up = cur + 2 - rest;
                n = up / 2;
            }

            buf[n] = '\n';
            buf[n+1] = '\0';

        }
        ++cur;
    }while (cur < finalpos);

    write (STDOUT_FILENO, buf, finalpos);


}

Solution

  • Well, you can let printf do it all for you, without a copy or injection or you can copy or inject, or do it char-by-char as @WilliamPursell shows (all are fine), e.g.

    With Printf

    #include <stdio.h>
    #include <string.h>
    
    #define MAXC 1024       /* if you need a constant, #define one (or more) */
    
    int main (void) {
    
        char line[MAXC];    /* buffer to hold entire line */
    
        while (fgets (line, MAXC, stdin)) {     /* read/validate line */
            int len = strlen(line);             /* get length of line */
    
            if (len == 1) {                     /* if line only 1-char */
                putchar (line[0]);              /* can't split 1 - output char */
                continue;                       /* get next line */
            }
    
            /* output first 1/2 and second 1/2 */
            printf ("%.*s\n%s", len/2, line, line + len/2);
        }
    }
    

    Using a 2nd Buffer

    #include <stdio.h>
    #include <string.h>
    
    #define MAXC 1024       /* if you need a constant, #define one (or more) */
    
    int main (void) {
    
        char line[MAXC];    /* buffer to hold entire line */
    
        while (fgets (line, MAXC, stdin)) {     /* read/validate line */
            size_t len = strlen(line);          /* get length of line */
            char first[MAXC/2 + 1];             /* buffer to hold 1st 1/2 */
    
            if (len == 1) {                     /* if line only 1-char */
                putchar (line[0]);              /* can't split 1 - output char */
                continue;                       /* get next line */
            }
    
            memcpy (first, line, len/2);        /* copy 1st 1/2 to first */
            first[len/2] = '\n';                /* add newline (or just use puts) */
            first[len/2+1] = 0;                 /* nul-termiante */
    
            fputs (first, stdout);              /* output 1st 1/2 */
            fputs (line + len/2, stdout);       /* output rest */
        }
    }
    

    Both will give equivalent output, e.g.

    Example Input File

    $ cat dat/tosplit.txt
    1234
    56789
    123
    
    bc
    

    Example Use/Output

    $ ./bin/splitline < dat/tosplit.txt
    12
    34
    567
    89
    12
    3
    
    b
    c
    

    There is always more than one way to skin-the-cat in C. Let me know if you have further questions.