0

Would please somebody tell me why i constantly get coredump segmentation? when i choose n=1 work correctly but the problem is n=2 and n=3 but i have no idea why.I want to read a text file and return a text, binary or hex file.

I edited the code and i compile it and i get just one warning which is referring to %x but i do not care about it cause first i have to solve n==2. Now I do not have coredump error. it seems there is no error but my second file is empty.

int main(int argc, char *argv[])
{    
    if (argc != 3){
        printf("Use this scheme: ./executabel read_file write_file -option(-b,-t,-x)\n");
        exit(EXIT_FAILURE);
    }
    
    int fd1=open(argv[1], O_RDONLY);
        int fd2=open(argv[2], O_WRONLY | O_CREAT);
        char buffer[1024];
        int rd_count = 0;
        int wr_count = 0;
        int n;
        FILE * fpw;
        fpw = fdopen (fd2, "w");
        
        if (fd1 == -1){
        printf("Failed to open the read-file.\n");
        exit(EXIT_FAILURE);
    }
    
    if (fd2 == -1){
        printf("Failed to open the write-file.\n");
        exit(EXIT_FAILURE);
    }
    
    printf("Please choose one:\n");
    printf("1. –t forces the output file to be a text one.\n");
    printf("2. –b forces the output file to be binary.\n");
    printf("3. –x forces the output file to be a hexadecimal representation.\n");
    scanf("%d", &n);
    
    
    while ((rd_count = read(fd1, (void*) buffer, 1024)) > 0){
        int bytes_wr = 0;
        while (bytes_wr != rd_count){
            if (n==1){
                    wr_count = write(fd2, (void*) (buffer+bytes_wr), rd_count-bytes_wr);
                }else if (n==2){
                    wr_count = fwrite( (void*) (buffer+bytes_wr), sizeof(float), rd_count-bytes_wr, fpw);
                }else{
                    fprintf(fpw,"%x",(void*) (buffer+bytes_wr));
                }
            if (wr_count < 0) {
                perror("Failed to write to file");
                exit(EXIT_FAILURE);
            } else {
                bytes_wr += wr_count;
            }
        }
        }

        if (rd_count < 0) {
            perror("Failed to read from file");
            exit(EXIT_FAILURE);
        }
    

    close(fd1);
        close(fd2);
        chmod(argv[2],777);
    
        exit(EXIT_SUCCESS);
        
        
}

By the way this is the warning

mahsa@mahsa-G53SW:~$ gcc -o ex4.o ex4.c -Wall -Wextra
ex4.c: In function ‘main’:
ex4.c:55:23: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘void *’ [-Wformat=]
   55 |         fprintf(fpw,"%x",(void*) (buffer+bytes_wr));
      |                      ~^  ~~~~~~~~~~~~~~~~~~~~~~~~~
      |                       |  |
      |                       |  void *
      |                       unsigned int
      |                      %p

I change this line

 fprintf(fpw,"%x",(void*) (buffer+bytes_wr));

to this

fprintf(fpw,"%02x",buffer[bytes_wr]);

now i do not have even warning. it seems everything works correctly but when i open the second file is empty.

  • In case `n==2` how many bytes will you write via `fwrite`? Where are those bytes stored? How many bytes are you allowed to access at that location? – Gerhardh Dec 20 '20 at 10:38
  • Not related to the segfaults: Where is the hex conversion for anything but the first byte? Also the return type of `main` is `int`, not `void` unless you are in a freestanding environment. – Gerhardh Dec 20 '20 at 10:40
  • Also please explain: If the input is a text file, what is your expected output for a binary file? – Gerhardh Dec 20 '20 at 10:42
  • ```wr_count = fwrite( (void*) (buffer+bytes_wr), sizeof(float), rd_count-bytes_wr, fd2);``` check this part.i want to read from the buffer and write everything.in the buffer maximum can be 1024. – Mahsa Abdolrezaei Dec 20 '20 at 10:42
  • I saw that line. I know what it does. That is why I asked. Do **you** know how many bytes it will write? Check again. – Gerhardh Dec 20 '20 at 10:43
  • i compile the code in the terminal therfore i have something like this ```./code.o a.txt b.txt – Mahsa Abdolrezaei Dec 20 '20 at 10:44
  • A file descriptor is not the same thing as a `FILE *`. You are not allowed to use them interchangably. The functions `fwrite` and `fprintf` require a `FILE *`, but you are passing a file descriptor. You may want to read this: [What's the difference between a file descriptor and file pointer?](https://stackoverflow.com/q/2423628/12149471) That link also specifies how to convert between the two. – Andreas Wenzel Dec 20 '20 at 10:45
  • and as i do not expect to show me anything i do not think so that int main is necessary.void is enough I'm not 100% sure that fwrite is correct. i know for writing in binary i have to use fwrite – Mahsa Abdolrezaei Dec 20 '20 at 10:46
  • please go through these once [fwrite](https://man7.org/linux/man-pages/man3/fwrite.3.html) [fprintf](https://man7.org/linux/man-pages/man3/fprintf.3.html) [open](https://man7.org/linux/man-pages/man2/open.2.html) and check how they are accessing files – IrAM Dec 20 '20 at 10:47
  • As Andras Wenzel pointed out you also have a severe mismatch in types for your output functions. You compiler should tell you. If not, turn up your warnings. For GCC you can use `-Wall -Wextra` – Gerhardh Dec 20 '20 at 10:49
  • As stated in the link I posted for you, you should use [`fdopen`](https://man7.org/linux/man-pages/man3/fdopen.3.html) to convert a file descriptor to a `FILE *`. By instead attempting to open the same file twice with write permissions, the second open attempt is probably failing. As a general rule, you should always check the return value of `fopen` and `open` to verify that the function succeeded. – Andreas Wenzel Dec 20 '20 at 11:20
  • You didn't answer what the expected output for case 2 (binary file) is. – Gerhardh Dec 20 '20 at 11:31
  • 1
    I just noticeed your changed question. Please don't change your code after comments and answers are given. This will make part of them invalid and confuse future readers off your questiton. If you adapt according to comments, you can add it to your question but don't remove the wrong code. – Gerhardh Dec 20 '20 at 11:33
  • the first file is floating point number and i expect that the binary file to be a represent of the first file to 0 and 1 – Mahsa Abdolrezaei Dec 20 '20 at 11:37
  • If the text file contains float values, you should parse them using `fscanf` (or `sscanf` if you parse from `buffer`) instead of reading just raw bytes. – Gerhardh Dec 20 '20 at 11:48

1 Answers1

1

You have multiple issues in your code:

  1. The signature for main has to be int main(void) or int main(int argc, char *argv[]).

  2. You access your buffer out of bounds.

wr_count = fwrite( (void*) (buffer+bytes_wr), sizeof(float), rd_count-bytes_wr, fd2);

When you start with bytes_wr being 0 and you have a full buffer (rd_count holds 1024) you will write 1024 * sizeof(float) bytes while your buffer is only 1024 bytes large. Accessing any memory location after these 1024 bytes causes undefined behaviour.

  1. You have incorrect types for your files: Initially pointed out by Andreas Wenzel.
    int fd2=open(argv[2], O_WRONLY | O_CREAT);
...
    wr_count = fwrite( (void*) (buffer+bytes_wr), sizeof(float), rd_count-bytes_wr, fd2);
...
    fprintf(fd2,"%x",(void*) (buffer+bytes_wr));

Functions fwrite and fprintf require a parameter of type FILE* to identify the file. You pass a file descriptor of type int. When the called function will try to dereference the expected pointer you cause undefined behaviour.

There are two sets of I/O functions:

  • fopen, fprintf, fscanf, fflush, fwrite, fclose etc.
  • open, write, close etc. One set takes FILE* while the other takes int. Don't mix that.

Your compiler should warn you about that. If that didn't happen you need to turn up your warnings. For GCC you can use -Wall -Wextra

  1. You don't print hex dump correctly:
    fprintf(fd2,"%x",(void*) (buffer+bytes_wr));

You pass an address which is not correct here. You probably want to pass a single byte to fprintf. This would be the way to do it:

    fprintf(fd2,"%02x", buffer[bytes_wr]);

Also note the format string containing 02 to specify the width of the field. Without this you could end up with 1 digit and would not be able to see bye boundaries in the output. You should also change buffer to unsigned char to prevent sign extension.

Gerhardh
  • 11,688
  • 4
  • 17
  • 39