0

For my programming course I have to make a program that copies a file.

This program asks for the following:

  • an input file in the command prompt
  • a name for the output file

The files required to copy are .WAV audio files. I tried this with an audio sample of 3 seconds.

The thing is that I do get a file back, for it to be empty. I have added the fclose and fopen statements

while((ch = fgetc(input)) != EOF)
{
  fputc(ch, output);
}

I hope someone can point out where I probably made some beginners mistake.

MwBakker
  • 498
  • 5
  • 18
Neuquert
  • 59
  • 7
  • 2
    If it's a binary file, and you're running the code on windows, you need to open the file with [...]. In other words, see [mcve]. – user3386109 Nov 23 '22 at 18:38
  • @user3386109 My first idea as well -- but if both files are open in text mode the read/write conversions should cancel each other out, shouldn't they? – Peter - Reinstate Monica Nov 23 '22 at 18:40
  • 1
    The first thing to do is to check for error conditions. does fgetc *ever* read anything? (You are reading up to the first EOF, but that return value can occur immediately, indicating an I/O error.) The same is true for putc whose return value you don't check at all. – Peter - Reinstate Monica Nov 23 '22 at 18:42
  • @Peter-ReinstateMonica The control-Z character, when present in a file being read in text mode, will signal EOF. It is surprising that OP claims the output is empty. – user3386109 Nov 23 '22 at 18:43
  • @user3386109 Oh. Really? No time to check, but that would of course lead to short files. But a valid WAV's first byte should be 'R', apparently. – Peter - Reinstate Monica Nov 23 '22 at 18:47
  • Opening the files in binary mode `"rb"` and `"wb"` should prevent that, especially if `ch` is an `int`, right? – Dash Nov 23 '22 at 18:48
  • 1
    The problem is a bit before the lines you show, I believe. Could also be after these lines, actually. – hyde Nov 23 '22 at 18:50
  • I'll do some more research myself. The rest of the code is written by the course, so I'm not sure if I can share that here. That is why I left it out in the first place. I thought the mistake must have been in the part that I wrote. I understand it is not a lot of information to go off. – Neuquert Nov 23 '22 at 18:53
  • 2
    No, the mistake is not in the code you posted. – user3386109 Nov 23 '22 at 18:57
  • Just share the link to the CS50 problem to save us from having to look it up. It's public so there is no issue posting it. I suspect it is [Lab 4: Volume - CS50](https://cs50.harvard.edu/college/2022/spring/labs/4/) – David C. Rankin Nov 23 '22 at 18:57
  • The code is not displayed in the link, on the site you have to make an account. https://cs50.harvard.edu/x/2022/labs/4/ I'll first just watch some more videos and do some more research. After which I'll then ask a better question. – Neuquert Nov 23 '22 at 19:00
  • 1
    There was a question [Spoiler CS50 lab4](https://stackoverflow.com/questions/66843519/spoiler-cs50-lab4/66844780#66844780) that is now closed (owner deleted it when he got his answer thinking it hides his question -- it doesn't). You may or may not be able to read it. Bottom line, better approach is `fread` / `fwrite` the binary data. For the code, you can simply download the .zip with `wget https://cdn.cs50.net/2021/fall/labs/4/volume.zip` -- you don't need an account -- if that is in fact your CS50 problem you are working on. – David C. Rankin Nov 23 '22 at 19:06
  • I am working on that problem. I thought you needed an account – Neuquert Nov 23 '22 at 19:07
  • Another reason `getchar()` alone won't work (without shifting and Or'ing) is `"Your program should then read the rest of the data from the WAV file, one 16-bit (2-byte) sample at a time. "` which means reading 1-byte at a time, just the first step in then reading and combining booth bytes in order to apply the volume adjustment. – David C. Rankin Nov 24 '22 at 01:24

1 Answers1

3

The little while loop you show should in principle work if all prerequisites are met:

  • The files could be opened.
  • If on a Microsoft operating system, the files were opened in binary mode (see below).
  • ch is an int.

In other words, all problems you have are outside this code.

Binary mode: The CR-LF issue

There is a post explaining possible reasons for using a carriage return/linefeed combination; in the end, it is the natural thing to do, given that with typewriters, and by association with teletypes, the two are distinct operations: You move the large lever on the carriage to rotate the platen roller or cylinder a specified number of degrees so that the next line would not print over the previous one; that's the aptly named line feed. Only then, with the same lever, you move the carriage so that the horizontal print position is at the beginning of the line. That's the aptly named carriage return. The order of events is only a technicality.

DOS C implementations tried to be smart: A C program ported from Unix might produce text with only newlines in it; the output routines would transparently add the carriage return so that it would follow the DOS conventions and print properly. Correspondingly, CR/LF combinations in an input file would be silently converted to only LF when read by the standard library implementations.

The DOS file convention also uses CTR-Z (26) as an end-of-file marker. Again, this could be a useful hint to a printer that all data for the current job had been received.

Unfortunately, these conventions were made the default behavior, and today are typically a nuisance: Nobody sends plain text to a printer any longer (apart from the three people who will comment under this post that they still do that).

It is a nuisance because for files that are not plain text silent data changes are catastrophic and must be suppressed, with a b "flag" indicating "binary" data passed in the fopen mode argument: To faithfully read you must specify fopen(filename, "rb"), and in order to faithfully write you must specify fopen(filename, "wb").

Empty file !?

When I tried copying a wave file without the binary flags the data was changed in the described fashion, and the copy stopped before the first byte with the value 26 (CTRL-Z) in the source. In other words, while the copy was corrupt, it was not empty. By the way, all wave files start with the bytes RIFF, so that no CTR-Z can be encountered in the first position.

There are a number of possibilities for an empty target file, the most likely of which:

  • You didn't emit or missed an error message regarding opening the files (does your editor keep a lock on the output?), and the program crashed silently when one of the file pointers was null. Note that error messages may fail to be printed when you make error output on standard out: That stream is buffered, and buffered output may be lost in a crash. By contrast, output to stderr is unbuffered exactly to prevent message loss.
  • You are looking at the wrong output file. This kind of error is surprisingly common. You could perform a sanity check by deleting the file you are looking at, or by printing something manually before you start copying.

Generally, check the return value of every operation (including your fputc!).

Peter - Reinstate Monica
  • 15,048
  • 4
  • 37
  • 62