这是Brian在cs50 week4 lab4中解释的代码
// Modifies the volume of an audio file
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
// Number of bytes in .wav header
const int HEADER_SIZE = 44;
int main(int argc, char *argv[])
{
// Check command-line arguments
if (argc != 4)
{
printf("Usage: ./volume input.wav output.wav factorn");
return 1;
}
// Open files and determine scaling factor
FILE *input = fopen(argv[1], "r");
if (input == NULL)
{
printf("Could not open file.n");
return 1;
}
FILE *output = fopen(argv[2], "w");
if (output == NULL)
{
printf("Could not open file.n");
return 1;
}
float factor = atof(argv[3]);
// TODO: Copy header from input file to output file
uint8_t header[HEADER_SIZE];
fread(header, HEADER_SIZE, 1,input))
fwrite(header,HEADER_SIZE, 1, output);
// TODO: Read samples from input file and write updated data to output file
int16_t buffer;
while(fread(&buffer, sizeof(int16_t), 1, input))
{
buffer *= factor;
fwrite(&buffer, sizeof(int16_t ), 1 ,output);
}
// Close files
fclose(input);
fclose(output);
}
我对什么是fread()和fwrite()感到困惑。它说:
while(fread(header, HEADER_SIZE, 1, input))
不应该是:
while(fread(header,sizeof(uint8_t), HEADER_SIZE, input))
因为语法是:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
ptr,这是要读取数据的内存的地址(第一个字节),
size,这是要读取的数据类型的大小(以字节为单位),
nmemb,这是一次读取的类型的数量,和
流,它是指向fopen返回的FILE的指针。
为什么我们在fwrite()和fread()中使用缓冲区的地址,而不是在fwrite()和fread()中使用header地址?缓冲区的值会在每次循环后被覆盖吗?
看情况。
如果你想接收一个完整的报头,然后把它作为一个报头来处理,带有报头的各个部分的含义,那么你应该请求一个你想要处理的报头的副本:
fread(header, HEADER_SIZE, 1, input)
如果你想接收一些字节(恰好是头的大小),然后将它们作为单独的字节处理(即忽略它们一起构成头的事实),那么你应该请求许多字节:
fread(header,sizeof(uint8_t), HEADER_SIZE, input)
(经明确许可,我添加了WeatherVance的贡献。它为我试图解释语义的方法增加了技术结果的细节。
fread(header, 1, 44, input)
和fread(header, 44, 1, input)
都将尝试读取到44字节。
如果只能读取2个字节,那么fread
将在第一种情况下返回2,在第二种情况下返回0。因为第一个程序试图读取44个大小为1的元素,第二个程序想读取1个大小为44的元素