2
votes

Write a program that receives three arguments from the command line: week09_1 file1.txt file2.txt file3.txt

Your program should open files file1.txt and file2.txt for reading and to create
file file3.txt as follows:

The first line of file3.txt is the first line of file1.txt
The second line of file3.txt is the first line of file2.txt
The third line of file3.txt is the second line of file1.txt
The fourth line of file3.txt is the second line of file2.txt

... When one input file reaches the EOF, the remaining lines in the other file
should be copied to the output file and the program terminates. Your
program should print appropriate error messages if fewer than 3 file names
are provided on the command line or if the files cannot be opened.

So as of right now i have been able to do what the prompt is asking me to do; however, when one file runs out of lines to print and then it only prints from the other file the printing is on the same line, i am wondering how i can make it start a new line when its only printing from 1 file.

Also i do not understand how i am suppose to implement in the command line arguments the way the prompt is asking.

#include <stdio.h>
char line1[256] = { };
char line2[256] = { };
char check;
int END = 0, END1 = 0, END2 = 0;

int main(int argc, char *argv[]) {
  if (argc != 4) {
    printf("Error: Wrong amount of arguments\n");
    return 0;
  }
  FILE *file1 = fopen("argv[1]", "r");
  FILE *file2 = fopen("argv[2]", "r");
  FILE *file3 = fopen("argv[3]", "w");
  if (argv == NULL) {
    printf("Error: file could not be opened.\n");
    return 0;
  }

  while (END != 2) {
    check = fgets(line1, 256, file1);
    if (check != NULL) {
      fprintf(file3, "%s", line1);
    } else if (check == NULL) {
      END1 = 1;
    }

    check = fgets(line2, 256, file2);
    if (check != NULL) {
      fprintf(file3, "%s", line2);
    } else if (check == NULL) {
      END2 = 1;
    }
    END = END1 + END2;
  }
  return 0;
}
3
Please take into account that lines can be quite long.Deduplicator
While you're indenting your code: remove magic numbers (e.g. 256), move the “global” variables (actually file scope) into main(), check the return values of fopen(), and fclose() your files when you're done with them.Emmet
The command-line arguments will be in argv[1], argv[2], and argv[3] if they're there; in this case, argc will be 4. You should validate (at least) how many arguments have been given, and exit with a usage message if argc is not exactly 4.Emmet
How long are the input lines? If some of the input lines are longer than 256 characters, then the code has to deal with lines being truncated by fgets. Either that, or you need to use bigger line buffers.user3386109
Now your code is worse (char line[] = {}; etc) - I'm not sure it even compiles. 256 is a bit small, but not unreasonably so. You could use 4096 and ignore the issue, or use POSIX getline() and cease having to worry about line length for most purposes.Jonathan Leffler

3 Answers

1
votes

I think the code is easier to manage, especially if the last line in the file doesn't have a newline, if you use a function to process one line a file, and call it repeatedly.

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

static int read_and_print_line(FILE *ifp, FILE *ofp)
{
  char buffer[64];
  int eol_needed = 0;
  while (fgets(buffer, sizeof(buffer), ifp) != 0)
  {
    fputs(buffer, ofp);
    if (strchr(buffer, '\n') != 0)
      return 0;
    /* Either more to read in current line or EOF without newline */
    eol_needed = 1;
  }
  if (eol_needed)
    putc('\n', ofp);
  return EOF;
}

int main(int argc, char **argv)
{
  if (argc != 4)
  {
    fprintf(stderr, "Usage: %s in-file1 in-file2 outfile\n", argv[0]);
    return 1;
  }
  FILE *if1 = fopen(argv[1], "r");
  FILE *if2 = fopen(argv[2], "r");
  FILE *ofp = fopen(argv[3], "w");
  if (if1 == 0)
    fprintf(stderr, "Failed to open %s for reading\n", argv[1]);
  if (if2 == 0)
    fprintf(stderr, "Failed to open %s for reading\n", argv[2]);
  if (ofp == 0)
    fprintf(stderr, "Failed to open %s for reading\n", argv[3]);
  if (if1 == 0 || if2 == 0 || ofp == 0)
    return 1;
  int r1 = 0;
  int r2 = 0;
  while ((r1 = read_and_print_line(if1, ofp)) != EOF &&
         (r2 = read_and_print_line(if2, ofp)) != EOF)
    ;

  assert(r1 == EOF || r2 == EOF);
  assert(r1 != r2);

  while (read_and_print_line(if1, ofp) != EOF)
    ;
  while (read_and_print_line(if2, ofp) != EOF)
    ;

  fclose(if1);
  fclose(if2);
  fclose(ofp);
  return 0;
}

I'm satisfied that this works on its own source code, and also on one 'line' files with no newline at the end (echo -n Gobbledygook >file1), and so on. The buffer is shown as 64 bytes to aid in testing (you could reduce it to 32 or even lower if you like). Once tested, I'd compile with a size like 4096.

1
votes

I'll get you part of the way there.

Given this file as file1.txt:

File 1, Line 1
File 1, Line 2
File 1, Line 3
File 1, Line 4
File 1, Line 5
File 1, Line 6
File 1, Line 7
File 1, Line 8

And this file as file2.txt:

File 2, Line 1
File 2, Line 2
File 2, Line 3
File 2, Line 4
File 2, Line 5
File 2, Line 6
File 2, Line 7
File 2, Line 8
File 2, Line 9
File 2, Line 10

You can read them and print them out interleaves like so:

#include <stdio.h>

int main(int argc, char *argv[]){
    char buffer[4096];
    char *ptr;
    int i=0;

    FILE *file1 = fopen("/tmp/file1.txt", "r");
    FILE *file2 = fopen("/tmp/file2.txt", "r");

    // while there is something from either file, do...
    while (!feof(file1) || !feof(file2)){
            // use modulo to switch file1, file2, etc
        if (i%2 == 0) {
            ptr=fgets(buffer, sizeof(buffer), file1);
        }   
        else {
            ptr=fgets(buffer, sizeof(buffer), file2);
        }
            // test if the last fgets actually read something by testing ptr vs NULL
        if (ptr)
            printf("%s", buffer);
        ++i;
    }   
    return 0;
}

Prints:

File 1, Line 1
File 2, Line 1
File 1, Line 2
File 2, Line 2
File 1, Line 3
File 2, Line 3
File 1, Line 4
File 2, Line 4
File 1, Line 5
File 2, Line 5
File 1, Line 6
File 2, Line 6
File 1, Line 7
File 2, Line 7
File 1, Line 8
File 2, Line 8
File 2, Line 9
File 2, Line 10 

You will need to add the printing to file3, appropriate fclose on the files, reading argv, and appropriate error testing/reaction.

0
votes

Some UB - code needs fixing

//char check;
void * check;

Suggest:

char line1[256] = { 0 };
char line2[256] = { 0 };

Change error check. Could expand on which file is bad

if (file1 == NULL || file2 == NULL || file3 == NULL) {
  printf("Error: file could not be opened.\n");
  return 0;
}

But others have a good "rest of the answer".