Aside from the complete lack of error handling, you are not adequately differentiating between bytes and integers.
Your size
variable is expressed in bytes, but you are using it as a count when dealing with your vec
array. As such, you are over-allocating your array, reading too many int
s from the file into the array, and iterating through too many elements of the array.
Also, when writing back to the file, you are treating the loop counter i
as a byte offset, which it is not, thus you are writing to the wrong offset in the file.
Try something more like this instead:
#include <cstdio>
#include <cstdint>
#include <vector>
typedef int32_t myint_t; // or int16_t, if needed...
int main()
{
//opening file
FILE *pfile = fopen("file.bin", "r+b");
if (!pFile) return -1
//finding file size
//TODO: use f/stat() or std::filesystem::file_size() instead
if (fseek(pfile, 0L, SEEK_END) < 0) {
fclose(pFile);
return -1;
}
long size = ftell(pfile);
if (size < 0) {
fclose(pFile);
return -1;
}
rewind(pfile);
//reading data
std::vector<myint_t> vec(size / sizeof(myint_t));
size_t numItems = fread(vec.data(), sizeof(myint_t), vec.size(), pfile);
for(size_t i = 0; i < numItems; ++i) {
if (vec[i] == 6664) {
vec[i] >>= 1;
// TODO: it is more efficient for the filesystem to make
// smaller relative seeks using SEEK_CUR than to make
// larger seeks from the beginning using SEEK_SET...
if (fseek(pfile, i * sizeof(myint_t), SEEK_SET) < 0) {
fclose(pFile);
return -1;
}
if (fwrite(&vec[i], sizeof(myint_t), 1, pfile) != 1) {
fclose(pFile);
return -1;
}
}
}
fclose(pfile);
return 0;
}
That being said, consider using C++-style file I/O instead of C-style file I/O, eg:
#include <iostream>
#include <vector>
#include <cstdint>
using myint_t = int32_t; // or int16_t, if needed...
int main()
{
std::fstream fs;
fs.exceptions(std::fstream::failbit | std::fstream::badbit);
try {
//opening file
fs.open("file.bin", std::ios::in | std::ios::out | std::ios::binary | std::ios::ate);
//finding file size
//TODO: use f/stat() or std::filesystem::file_size() instead
long size = fs.tellg();
fs.seekg(0);
//reading data
std::vector<myint_t> vec(size / sizeof(myint_t));
fs.read(reinterpret_cast<char*>(vec.data()), sizeof(myint_t) * vec.size());
size_t numItems = fs.gcount() / sizeof(myint_t);
for(size_t i = 0; i < numItems; ++i) {
if (vec[i] == 6664) {
vec[i] >>= 1;
// TODO: it is more efficient for the filesystem to make
// smaller relative seeks using std::ios::cur than to make
// larger seeks from the beginning...
fs.seekp(i * sizeof(myint_t));
fs.write(reinterpret_cast<char*>(&vec[i]), sizeof(myint_t));
}
}
}
catch(...) {
return -1;
}
return 0;
}
Though, the following would be a little bit simpler and safer:
#include <iostream>
#include <vector>
#include <filesystem>
#include <cstdint>
using myint_t = int32_t; // or int16_t, if needed...
int main()
{
std::ifstream ifs;
std::ofstream ofs;
ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
ofs.exceptions(std::ofstream::failbit | std::ofstream::badbit);
try {
//opening files
ifs.open("file.bin", std::ios::binary);
ofs.open("file.new", std::ios::binary);
//reading data
myint_t value;
bool found = false;
while (ifs.read(reinterpret_cast<char*>(&value), sizeof(value))) {
if (value == 6664) {
value >>= 1;
found = true;
}
ofs.write(reinterpret_cast<char*>(&value), sizeof(value));
}
ifs.close();
ofs.close();
if (found) {
std::filesystem::rename("file.bin", "file.bak");
std::filesystem::rename("file.new", "file.bin");
std::filesystem::remove("file.bak");
}
else {
std::filesystem::remove("file.new");
}
}
catch(...) {
return -1;
}
return 0;
}