1

I need to write a program which reverses the order of the bytes in a given binary file. It accepts the file name in the command line. In addition it can use file positioning functions such as fseek no more than a fixed number of times.

Here is a code which I wrote which does not use it a fixed number of times:

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

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

    if (argc>2) {
        printf("Please enter a valid file name");
        return 1;
    } else {
        FILE* file;
        file=fopen(argv[1], "r");
        if (file==NULL) {
            printf("Please enter a valid file name");
            return 1;
        } else {
            FILE* fileBackUp;
            fileBackUp=fopen("c:\backupFile.txt", "w+");
            fseek(file, 0, SEEK_END);
            fseek(file, -1, SEEK_CUR);
            while (ftell(file)>=0) {
                int c= fgetc(file);
                fputc(c, fileBackUp);
                fseek(file, -2, SEEK_CUR);
            }

            fseek(fileBackUp, 0, SEEK_SET);

            int c;
            while (!feof(fileBackUp)) {
                c=fgetc(fileBackUp)
                fputc(c,file);
            }

            fclose(fileBackUp);
            fclose(file);
        }
    }
    return 1;
}

It uses an extra file for it. I surely believe that there's a shorter elegant way to do that with a fewer steps as requested. Any suggestions?

Another thing: It seems that the first condition is always being filled, how come?

user751630
  • 17
  • 3
Numerator
  • 1,389
  • 3
  • 21
  • 40
  • 4
    should this be tagged 'homework'? if not, why do you have the restriction on how many fseek's you can call? – mfsiega Jul 17 '12 at 15:50
  • 1
    You want to reverse the *bits* or reverse the *bytes* ? – Paul R Jul 17 '12 at 15:53
  • @mfrankli: Homework on July? :) No, it's a question from a past test I'm trying to answer. – Numerator Jul 17 '12 at 15:53
  • You only seem to be reversing the order of the *bytes* in the above code though ? – Paul R Jul 17 '12 at 15:55
  • Oh! I should change the last while loop. – Numerator Jul 17 '12 at 15:57
  • 1
    No - you're still just reversing the order of the bytes - if you want to reverse all the bits then you need to do a bit reversal on each byte as well. – Paul R Jul 17 '12 at 16:00
  • @PaulR: Doesn't fgetc give me bit by bit considering a Binary File? – Numerator Jul 17 '12 at 16:04
  • @PaulR: I read that it's not. What should I do then? – Numerator Jul 17 '12 at 16:05
  • When you write out each byte you need to reverse the order of the bits within the byte - there are plenty of examples of how to do this on SO - just use the search option to find "bit reversal", e.g. http://stackoverflow.com/questions/746171/best-algorithm-for-bit-reversal-from-msb-lsb-to-lsb-msb-in-c – Paul R Jul 17 '12 at 16:06
  • @PaulR : Thank you.I see, another question- Declaring "rb" in fopen function or using fread or fwrite won't change in this case? – Numerator Jul 17 '12 at 16:08
  • 1
    No - file I/O works at the byte level. – Paul R Jul 17 '12 at 16:27

1 Answers1

2
#include <stdio.h>

long max(long v1, long v2) { return v1 >= v2 ? v1 : v2; }
long min(long v1, long v2) { return v1 >= v2 ? v2 : v1; }
void invert_bits(char *arr, size_t size);

int main(int argc, char *argv[]) {
  size_t  read_sz;
  FILE * infile = fopen(argv[1], "r");
  fseek(infile, 0, SEEK_END);
  long file_sz = ftell(infile);
  long offset  = file_sz;
  long total_read = 0;
  long num_seeks  = 10;
  size_t  buffer_sz = (file_sz + num_seeks - 1) / num_seeks;
  char    buffer[buffer_sz];
  while (file_sz > total_read) {
    if ((offset + num_seeks - 1) / num_seeks < buffer_sz) {
      buffer_sz = offset / num_seeks;
    }
    offset = max(0, offset - buffer_sz);
    fseek(infile, offset, SEEK_SET);
    read_sz = fread(buffer, 1,
        min(buffer_sz, file_sz - total_read), infile);
    total_read += read_sz;
    invert_bits(buffer, read_sz); 
    num_seeks--;
  }
  fclose(infile);
}

void invert_bits(char *arr, size_t size) {
  size_t i;
  int j;
  for (i = size; i > 0; i--) {
    char v = arr[i - 1];
    char o = 0;
    for (j = 0; j < 8; j++) {
      o |= v & 1;
      v >>= 1;
      o <<= 1;
    }
    printf("%c", o);
  }
}
perreal
  • 94,503
  • 21
  • 155
  • 181
  • Thank you for the answer. file_sz is the number of bytes from the beginning of the file,right? why do you subtract the buffer value each time? – Numerator Jul 17 '12 at 16:37
  • Are you sure that " file_sz -= buffer_sz;" at the end of the while loop is correct? it doesn't work for me. – Numerator Jul 17 '12 at 17:36
  • even without it, it's not correct. there is a problem. we read the same bytes again. try file-size=10, buffer-size=4. – Numerator Jul 17 '12 at 17:45
  • 3
    This still calls `fseek` and `fread` a variable number of times in the while() loop, based on the file size. Instead of using a constant buffer size of 1024, use a constant fraction of the file size. I'm not sure why you'd want to do that, but it's a constraint from the question (possibly to test student's knowledge of dynamic memory allocation and file IO?) – Kevin Vermeer Jul 17 '12 at 18:04