C++ fseek doesn't set to same position - c++

I need to return to a previous position in a file that I'm reading after a certain event. The file is opened in text read mode. So I get the read position of the file before reading the needed segment and after that I'm calling ftell to return me to that position. The problem is that it doesn't go to the position that I specified, it instead jumps ahead by two places.
To get the current position I'm using this simplified function.
I'm not sure if the fflush is necessary but it seems to make no difference in the result.
long GetCurPos(void)
{
return ftell(file);
}
To open the file I'm simply using
void Open(void)
{
file = fopen(path, "r");
}
To return to a previous position I'm using this simplified function.
It return a zero value.
void SetPos(long pos) const
{
if (fseek(file, pos, SEEK_SET)) LOG("ferror %d occured!", ferror(file));
}
And finally for function that causes the problems
bool TryPeekWord(char * value, size_t maxLen) const
{
bool result = false;
long start = GetCurPos();
int c;
size_t len;
for (len = 0; len < maxLen; len++)
{
c = fgetc(file);
if (c == EOF)
{
*(value + len) = '\0';
result = len > 0;
break;
}
if ((c == ' ' || c == '\n') && len > 0)
{
*(value + len) = '\0';
result = true;
break;
}
*(value + len) = static_cast<char>(c);
}
SetPos(start);
return result;
}
If I call fseek again after the SetPos call it will be the same value as start but if I then read from the file it will not return the expected characters. What am I doing wrong?

Over the course of improving my question to a proper standard I found that the file I was working on got corrupt. Maybe from moving to different operating system or something?
I copied over the contents of the old file into a new file and it worked fine again.

Related

How to fix 'Heap has been corrupted 'error in c++?

When I run the program, I get exception "heap has been corrupted" after completion of the function
I have read that this exception may cause if you are using memory that has been freed, or when you are writing to index which is out of array index. But none of the cases applies here. I have read other answers of some problems but it didn't help much.
`char fileNametoExport[26]="d:\\FOlder1\\part1.ipt";
char WorkingFolderName[260] ="d:\\folder";
int start = rFind(fileNametoExport, '\\');
int finish = rFind(fileNametoExport, '.');
if (start == -1)
start = 0;
char partname[260];
strcpy(partname,substr(fileNametoExport, start, finish));
::AfxMessageBox((LPCTSTR)partname);
char xtfile[260];
char xmltxtfile[260];
strcpy(xtfile, strcat(WorkingFolderName, partname));
strcat(xtfile, "__Default.x_t");
strcpy(xmltxtfile, WorkingFolderName);
strcat(xmltxtfile,"_XT_SE_INV_Default_SOLID_0_Solid1_xt.xmt_txt");`
function rfind() to find occurence of char in char array-
int rFind(char* s, char c)
{
int sz = 0;
char *tmp = s;
while (*tmp != '\0')
{
sz++;
tmp++;
}
for (int i = sz - 1; i >= 0; i--)
{
if (*(s + i) == c)
return i;
}
return -1;
}
function substr() to get substring from position x to y (y exclusive)
char* substr(char* s, const int b, const int f)
{
char *str = new char[f - b];
int t = 0;
for (int i = b; i != f; i++)
{
str[t] = s[i];
t++;
}
str[t] = '\0';
return str;
}
P.S- While giving input I ensure that fileNametoExport always contains '.' and '\'.
Your program do not check lengths of input strings. You can receive a string longer than your buffer and program will fail.
If your program get fileNametoExport = "d:\\somefolder\\somefilewithoutdot" , finish will be -1 and program fail at strcpy(partname,substr(fileNametoExport, start, finish)); .
Program writes after buffer in char* substr(char* s, const int b, const int f) at line
str[t] = '\0';
because t at this point equal f-b , size of str buffer.
Function _ASSERTE( _CrtCheckMemory( ) ); from <crtdbg.h> very useful when searching for bugs like this. Put it around suspicious code and it fails after your bug. It works only in debug.

C++ read file until char found

I want to create a function that can read a file char by char continuously until some specific char encountered.
This is my method in a class FileHandler.
char* tysort::FileHandler::readUntilCharFound(size_t start, char seek)
{
char* text = new char;
if(this->inputFileStream != nullptr)
{
bool goOn = true;
size_t seekPos = start;
while (goOn)
{
this->inputFileStream->seekg(seekPos);
char* buffer = new char;
this->inputFileStream->read(buffer, 1);
if(strcmp(buffer, &seek) != 0)
{
strcat(text, buffer); // Execution stops here
seekPos++;
}
else
{
goOn = false;
}
}
}
//printf("%s\n", text);
return text;
}
I test this function and it actually works. This is an example to read a file content until new line character '\n' found.
size_t startPosition = 0;
char* text = this->fileHandler->readUntilCharFound(startPosition, '\n');
However, I am sure that something not right is exists somewhere in the code because if I use those method in a loop block, the app will just hangs. I guess the 'not right' things are about pointer but I don't know exactly where. Could you please point out for me?
C++ provides some easy-to-use solutions. For instance:
istream& getline (istream& is, string& str, char delim);
In your case, the parameter would be the equivalent of your text variable and delim would be the equivalent of your seek parameter. Also, the return value of getline would in some way be the equivalent of your goOn flag (there are good FAQs regarding the right patterns to check for EOF and IO errors using the return value of getline)
The lines
if(strcmp(buffer, &seek) != 0)
and
strcat(text, buffer); // Execution stops here
are causes for undefined behavior. strcmp and strcat expect null terminated strings.
Here's an updated version, with appropriate comments.
char* tysort::FileHandler::readUntilCharFound(size_t start, char seek)
{
// If you want to return a string containing
// one character, you have to allocate at least two characters.
// The first one contains the character you want to return.
// The second one contains the null character - '\0'
char* text = new char[2];
// Make it a null terminated string.
text[1] = '\0';
if(this->inputFileStream != nullptr)
{
bool goOn = true;
size_t seekPos = start;
while (goOn)
{
this->inputFileStream->seekg(seekPos);
// No need to allocate memory form the heap.
char buffer[2];
this->inputFileStream->read(buffer, 1);
if( buffer[0] == seek )
{
buffer[1] = '\0';
strcat(text, buffer);
seekPos++;
}
else
{
goOn = false;
}
}
}
return text;
}
You can further simplify the function to:
char* tysort::FileHandler::readUntilCharFound(size_t start, char seek)
{
// If you want to return a string containing
// one character, you have to allocate at least two characters.
// The first one contains the character you want to return.
// The second one contains the null character - '\0'
char* text = new char[2];
text[1] = '\0';
if(this->inputFileStream != nullptr)
{
this->inputFileStream->seekg(start);
// Keep reading from the stream until we find the character
// we are looking for or EOF is reached.
int c;
while ( (c = this->inputFileStream->get()) != EOF && c != seek )
{
}
if ( c != EOF )
{
text[0] = c;
}
}
return text;
}
this->inputFileStream->read(buffer, 1);
No error checking.
if(strcmp(buffer, &seek) != 0)
The strcmp function is used to compare strings. Here you just want to compare two characters.

Seeking file using c++

void Test(Packets& packet)
{
char buf[BUFLEN];
char* offset = buf;
unsigned int foo;
for(;!gzeof(file_handle);){
int len = gzread(file_handle, offset, sizeof(buf)-(offset-buf));
char* cur = buf;
char* end = offset+len;
for (char* eol; (cur<end) && (eol = std::find(cur, end, '\n')) < end; cur = eol + 1)
{
string string_array = string(cur, eol);
if(string_array[0] == 'L'){
packet.foo = blah;
}else{
packet.foo = bar;
}
//After readnig a line.. how do I make sure it quits this function (does another job in some other function) and continous from the next line?
}
#ifdef ROTATION
offset = std::rotate(buf, cur, end);
#else
offset = buf + (end-cur);
std::rotate(buf, cur, end);
#endif
}
std::cout<<std::string(buf, offset) ;
}
After readnig a line.. how do I make sure it quits this function (does another job in some other function) and continous from the next line?
I tried to make buf, offset as global variables and read the file only when the buffer is empty.. it still doesn't work.
Why you want to quit the function and continue from the next line?
Change your functions the way that one read a line and the other does whatever with it
somewhere you probably want to do something like or am i wrong?
{
Packets myPacket;
Test(packet);
OtherFunction(packet);
}

C File I/O bug in my code

I attempted writing a thesaurus program which reads a thesaurus file, for example:
drink:beverage
clever:smart,witty
and a .txt document, changing up the words it finds from the thesaurus and creating a new document with the modified text. However there appears to be a bug, I have narrowed it down to the while loop in getReplacement(), by checking a print operation before and after. I would really appreciate someone finding why it won't work.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <iostream>
char* getReplacement(char* original, FILE* file);
int main(int argc, char* argv[])
{
using namespace std;
FILE* thes = fopen(argv[1], "r");
FILE* text = fopen(argv[2], "r+");
FILE* nText = fopen("temp.txt", "w");
if(thes == NULL || text == NULL || nText == NULL)
return 1;
char word[20] = {};
char c;
int bytesW=0;
while((c = fgetc(text)) != EOF)
{
fputc(c, nText);
bytesW++;
if(isalpha(c))
{
int len = strlen(word);
word[len] = c;
word[len + 1] = '\0';
}
else
{
if(word == "")
continue;
cout << 7<<endl;
char* replacement = getReplacement(word, thes);
if(replacement == NULL)
continue;
fseek(nText,bytesW-1-strlen(word),SEEK_SET);
for(int i=0;i<strlen(replacement);i++)
fputc(replacement[i],nText);
int diff = strlen(word) - strlen(replacement);
while(diff-- >0)
fputc(' ', nText);
bytesW = bytesW-1-strlen(word)+strlen(replacement);
fseek(nText, bytesW, SEEK_SET);
}
}
fclose(thes);
fclose(text);
fclose(nText);
return 0;
}
char* getReplacement(char* const original, FILE* file)
{
using namespace std;
char* line="";
const short len = strlen(original);
int numOfOptions=1;
int toSkip=0; // number of commas to skip over
outer: while(fgets(line,1000,file) != NULL)
{
for(int i=0;i<len;i++)
if(line[i] != original[i])
{
goto outer;
}
if(line[len] != ':')
goto outer;
for(int i=0;i<len;i++)
line++;
for(int i=0;i<strlen(line);i++)
if(line[i] == ',')
numOfOptions++;
toSkip = rand()%numOfOptions;
while(toSkip >0)
{
if(line[0] == ',')
toSkip--;
line++;
}
return line;
}
return NULL;
}
char* line="";
// ... snip ...
outer: while(fgets(line,1000,file) != NULL)
Here's your problem. You are trying to read into a literal string; you instead need to allocate an array, on the stack or via malloc() to read into.
A string that you write in quotes in C is known as a literal. This means that this string gets embedded in the code of your program, and later loaded into memory when your programs is loaded. Usually it gets loaded into memory that's marked read-only, but that's platform dependent. That string that you wrote has room only for the null terminator. But you are trying to read up to 1000 characters into it. This will either lead to a segmentation fault because you were writing to read-only memory, or will lead to you writing all over some other memory, producing who knows what behavior.
What you want to do instead is allocate a buffer that you can read into:
char line[1000];
or, if you have limited stack space:
char *line = malloc(1000 * sizeof(char));
Furthermore, in your main() function, you do:
char c;
while((c = fgetc(text)) != EOF)
fgetc() returns an int, not a char. This way, it can return a value corresponding to a valid character if a value is read, or a value that is outside that range if you hit the end of file.
You can't compare strings in C using ==; what that does is compare whether they are the same pointer, not whether they have the same contents. It doesn't really make sense to recalculate the length of the current word each time; why not just keep track of len yourself, incrementing it every time you add a character, and then when you want to check if the word is empty, check if len == 0? Remember to reset len to 0 after the end of the word so you'll start over on the next word. Also remember to reset if len goes over sizeof(word); you don't want to write more than word can hold, or you will start scribbling all over random stuff on your stack and lots of things will break.

why its going in infinite loop?

I have a class that takes a html file and formats it. Here is my code.
void FormatHtml::Format(const std::string &formattedFile, const std::string &inputFile) const
{
string str;
ifstream inputfileObj(inputFile.c_str());
//ofstream formattedFileObj(formattedFile.c_str());
if(inputfileObj.is_open() /*&& formattedFileObj.is_open()*/)
{
while(inputfileObj.good())
{
getline(inputfileObj,str);
//cout<<str<<endl;
//formattedFileObj<<str;
int pos = str.find(">");
int pos3;
while(pos != string::npos)
{
pos3 = str.find("<",pos);
if(str.length() >= pos3+1)
{
if(str.at(pos3+1) == '/')
{
pos = str.find(">",pos3);
}
}
cout<<str.substr(0,pos+1)<<endl;
//formattedFileObj<<str.substr(0,pos+1)<<endl;
str = str.substr(pos+1,string::npos);
pos = str.find(">");
}
}
inputfileObj.close();
//formattedFileObj.close();
}
else
cout<<"could not open file";
}
}
but if i use this function with small file it works fyn, but for larger html file like google's home page source it goes to infinite loop.
following is call stack.
ntdll.dll!76f99a94()
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]
ntdll.dll!76f98d94()
ntdll.dll!76fa9522()
kernel32.dll!7588cb6c()
kernel32.dll!7588cbfc()
kernel32.dll!7588c964()
msvcr90d.dll!_write_nolock(int fh=14548992, const void * buf=0x77004cc0, unsigned int cnt=4074376) Line 335 + 0x3c bytes C
ffffffff()
And when i pause the execution it always stops in one file called write.c and at following code:
/* write the lf buf and update total */
if ( WriteFile( (HANDLE)_osfhnd(fh),
lfbuf,
(int)(q - lfbuf),
(LPDWORD)&written,
NULL) )
{
charcount += written;
if (written < q - lfbuf)
break;
}
Any one having clue what could be the reason, why it always happens with large unformatted file.
This line:
pos = str.find(">",pos3);
If pos == string::npos, then you carry on to do this:
str = str.substr(pos+1,string::npos);
pos = str.find(">");
string::npos == -1, so pos+1 == 0, so str.substr returns all of str. You are now in an infinite loop.