Hello my question is why the following function fails to delete the file whose name is specified in dir1;
I use the function remove but it seems that there is some kind of a problem with it.
Please help me.
#include <stdio.h>
void test(char* dir1,char* dir2)
{
FILE * file1,* file2;
file1=fopen(dir1,"r");
file2=fopen(dir2,"w");
if(!file1){ return;}
int inpch;
char* string = new char[10];
string[9]='\0';
int br=0;
do
{
while((inpch=fgetc(file1))!=EOF)
{
string[br]=char(inpch);
br++;
if(br==9)break;
}
if(br!=9)
{
string[br]='\0';
fputs(string,file2);
return;
}
else
{
fputs(string,file2);
br=0;
}
}while(true);
fclose(file1);
remove(dir1);/// I DON"T UNDERSTAND WHY IT DOESN"T DELETE THE FILE.
fclose(file2);
}
I guess at some point before exiting the do-while loop, the following if condition becomes true, and the function returns before it reaches to the end of the function, without even calling the remove function.
if(br!=9)
{
string[br]='\0';
fputs(string,file2);
return; //<------------ here you're returning!
}
Did you want to write return or break? Looks like its there the problem lies.
Why don't you check for the return value and error code (errno) that tells you exactly why the function didn't succeed?
Replace your remove call with this :
if( remove( "myfile.txt" ) != 0 )
perror( "Error deleting file" );
else
puts( "File successfully deleted" );
and it should tell you what happened.
Related
I'm currently working on a project with MFC and I noticed something weird that apparently has been there for a couple of years. When I launch the .exe of the program, it will do n number of things including reading a .DAT file and storing it as well. If the file doesn't exists, the program will try to find it with no luck throwing this CFile exception: The file could not be located. Which is correct because it doesn't exists. I have to do some operations first to generate that file, the storing process works fine. When the file exists and I run the program again, it's supposed read the file but this CArchive exception shows up: Invalid file format. And I don't understand why.
This is the Serialize():
//Fruits.cpp
void CFruits::Serialize(CArchive &ar)
{
int nVersion = 0;
CObject::Serialize(ar);
ar.SerializeClass(GetRuntimeClass());
if(ar.IsStoring())
{
ar.Write(&m_bInit,sizeof(bool));
ar.Write(&m_bYummy,sizeof(bool));
ar.Write(&m_bAcid, sizeof(bool));
ar.Write(&m_bFresh,sizeof(bool));
...
...
...
ar<<m_cType;
ar<<m_cColour;
ar<<m_cFlavor;
ar<<m_cPrice;
ar<<m_cQuantity;
}
else
{
nVersion = ar.GetObjectSchema();
ar.Read(&m_bInit,sizeof(bool));
ar.Read(&m_bYummy,sizeof(bool));
ar.Read(&m_bAcid, sizeof(bool));
ar.Read(&m_bFresh,sizeof(bool));
...
...
...
if( nVersion >= 2 || nVersion < 0)
ar<<m_cType;
else
m_cType=0;
if (nVersion >= 3 || nVersion < 0)
ar<<m_cColour;
else
m_cColour=0;
if (nVersion >= 4 || nVersion < 0)
ar<<m_cFlavor;
else
ar<<m_cFlavor=0;
if( nVersion >= 5 || nVersion < 0)
{
ar<<m_cPrice;
ar<<m_cQuantity;
}
else
{
m_cPrice=0;
m_cQuantity=0;
}
}
m_oSales.Serialize(ar);
m_oAdmin.Serialize(ar);
...
...
}
IMPLEMENT_SERIAL(CVehiculo,CObject,VERSIONABLE_SCHEMA | 6)
This is the SerializeElements:
//Fruits.cpp
void AFXAPI SerializeElements(CArchive &ar,CFruits * fruits,int ncount)
{
try
{
for(cont=0;cont<ncount;cont++)
fruits[cont].Serialize(ar);
}
catch(CArchiveException *AE)
{
//Here it stores the exception in a Log. Exception 5
}
}
The serializeElements is used to store and read the file n times, as declared here in the header file of fruits:
//Fruits.h
class CFruits : public CObject
{
public:
CFruits();
CFruits(const CFruits &O);
virtual ~CFruits();
void operator = (const CFruits &O);
void Serialize(CArchive &ar);
protected:
DECLARE_SERIAL(CFruits)
};
void AFXAPI SerializeElements(CArchive &ar,CFruits * fruits,int ncount);
typedef CArray<CFruits, CFruitso&> TArrayFruits;
The values of this Array, and the methods used to call the serialize are defined here in my main function:
//main.h
#include "CFruits.h"
class CMain : public CDialog
{
// Construction
public:
enum T_Fruits { eFruitsOnLine, eFruitsIng, eFruitsTra, eFruitsAnt, eFruitsP3, eFruitsP2, eFruitsP1, eFruitsC1, eFruitsC0, eFruitsEscape, eFruitsVideo};
private:
void StoreFruits();
void ReadFruits();
The SerializeElements for-loop is supposed to run 11 times, but I noticed that it only does it 1 time, then the Schema version changes to -1, (originally 6 cause I managed to trace the value). This happens only when reading the file.
I've tried the following:
I can't use debug so I have to use Logs, I placed a Log after every sentence in the Serialize() function, I found what seems to be the issue, this line:
ar.SerializeClass(GetRuntimeClass());
I used a try-catch and found that when that sentence happens, it throws the exception so, it doesn't continue reading. That is the moment where the version changes to -1. I tried to change that to:
ar.SerializeClass(RUNTIME_CLASS(CFruits));
Is the same result, I've read many forums trying to find the answer but I can't seem to do so. I've read the documentation and I found this here:
https://learn.microsoft.com/en-us/cpp/mfc/reference/carchive-class?view=vs-2019#serializeclass
Like ReadClass, SerializeClass verifies that the archived class
information is compatible with your runtime class. If it is not
compatible, SerializeClass will throw a CArchiveException.
But it doesn't make sense to me, because it doesn't fail storing. Should I look into something else?
Thank you
EDIT:
I'm posting the Store and Read methods
void CMain::ReadFruits()
{
CString CSerror, sFileName;
CString sDebug;
try
{
sFileName.Format("FRUITS%03d.DAT",GetNumT());
CFile fFruitsTag(sFileName,CFile::modeRead);
CArchive ar(&fFruitsTag,CArchive::load);
m_vFruits.Serialize(ar);
ar.Close();
fFruitsTag.Close();
}
catch(CFileException *FE)
{
...
}
catch(CArchiveException *AE)
{
...
}
}
void CMain::StoreFruits()
{
CString CSerror, sFileName;
try
{
if(!m_bStoringFruits)
{
sFileName.Format("FRUITS%03d.DAT",GetNumT());
m_bStoringFruits=true;
CFile fFruitsTag(sFileName,CFile::modeCreate|CFile::modeWrite);
CArchive ar(&fFruitsTag,CArchive::store);
m_vFruits.Serialize(ar);
ar.Close();
fFruitsTag.Close();
m_bStoringFruits=false;
}
}
catch(CFileException *FE)
{
...
}
catch(CArchiveException *AE)
{
...
}
catch(CException *e)
{
...
}
}
I am using ifstream to open a file and read line by line and print to console.
Now, I also want to make sure that if the file gets updated, it reflects. My code should handle that.
I tried setting fseek to end of the file and then looking for new entries by using peek. However, that did not work.
Here's some code I used
bool ifRead = true;
while (1)
{
if (ifRead)
{
if (!file2read.eof())
{
//valid file. not end of file.
while (getline(file2read, line))
printf("Line: %s \n", line.c_str());
}
else
{
file2read.seekg(0, file2read.end);
ifRead = false;
}
}
else
{
//I thought this would check if new content is added.
//in which case, "peek" will return a non-EOF value. else it will always be EOF.
if (file2read.peek() != EOF)
ifRead = true;
}
}
}
Any suggestions on what could be wrong or how I could do this.
I have the following code which returns ERROR in many lines:
bool func()
{
if (acondition)
{
return 0;
}
return 1;
}
int cmdfun()
{
other_funcs;
if (func()) return ERROR#NUMBER;
other_funcs;
if (func()) return ERROR#NUMBER;
}
But I found its becoming longer and longer. How can I encapsulate return ERROR#NUMBER into func() also? Or any way to encapsulate if (func()) return ERROR; into another independent function?
You can't really achieve this using return on its own.
But you could throw an exception in func which will bubble up the call stack, in the way you seem to want program control to:
struct myexception{}; /*ToDo - inherit from std::exception?*/
bool func()
{
if (acondition){
return 0; /*normal behaviour, perhaps make `func` void if not needed?*/
}
throw myexception();
}
cmdfun then takes the form:
int cmdfun()
{
other_funcs;
func();
other_funcs;
func();
/* don't forget to return something*/
}
Finally, make sure you catch the exception in the caller to cmdfun.
As I said it is not an exception and cannot be handled by std::exception, it is just an error message and ERROR#NUMBER is just another macro. And I cannot access to the caller to cmdfun(). So unable to adopt the first answer. But after asked someone else, it is possible to encapsulate returns and save time when typing them, though it's not recommended, but in this particular case, I can use macro. A complete example is given below:
#include <iostream>
using namespace std;
#define CHECK_VEC(acondition)\
if(checkcondition(acondition)) return -1;
bool checkcondition(bool acondition)
{
if (acondition) return 1;
return 0;
}
int fun_called_by_main()
{
int a = 5 + 4;
bool acondition = a;
CHECK_VEC(acondition);
return 1;
}
int main()
{
int a = fun_called_by_main();
cout << a << endl;
cin.get();
return 0;
}
If I understood corectly your question, you are asking for an 'error reporter' for your own errors. There are 2 solutions for 2 separate cases:
Case 1 - you still want to use a return statement to make an 'error reporter':
To do this, you'll have to make another function or just learn how to use goto. However, you don't need to - your function returns a boolean(bool) - which means you only have 2 possible results: 0 (False) and 1 (True)
bool func()
{
if (acondition)
{
return (bool)0; // False (no error)
}
return (bool)1; // True (error)
// Note: I used (bool)0 and (bool)1 because it is
// more correct because your returning type is bool.
}
void errorcase(bool trueorfalse)
{
switch(trueorfalse)
{
case False:
... // your code (func() returned 0)
break;
default:
... // your code (func() returned 1)
break;
// Note that you will not need to check if an error occurred every time.
}
return;
}
int cmdfun()
{
... // your code
errorcase(func());
... // again - your code
return 0; // I suppouse that you will return 0...
}
But I think that the second case is more interesting (unfortunetly it is also preety hard to understand as a beginner and the first solution might be a lot easier for you):
Case 2 - you decided to do it somehow else - that's by learning throw and catch - I won't repeat the answer because it is already given: #Bathsheba answered preety good...
When testing my code (static analysis) to see if i respect misra c++ 2008, i get the following error
Function does not return a value on all paths.
The function looks like
int* Dosomething(string v)
{
int* retvalue = NULL;
if( 0 == exists(v) )
{
throw("error: value doesn't exist");
}
else
{
retvalue = dosomecomputations(v);
}
return retvalue;
}
I really need to throw an exception, because depending of the error the caller shall do something. The possible list of errors can be big and it is not just that the value doesn't exist as in this sample of code.
How can i manage it? I think that in this case the tool i'm using should not see it as a non-compliance to misra.
Thanks for your advise.
rony.
The following code should not report any warnings/errors with MISRA C++ 2008 rules applied. So most likely it's an issue with your tool - or the posted code is not the affected part.
#include <string>
int exists(std::string v){ (void)v; return 1; }
int* dosomecomputations(std::string v){ (void)v; return NULL; }
int* dosomething(std::string v){
int* retvalue = NULL;
if( 0 == exists(v) ){
throw("error: value doesn't exist");
}else{
retvalue = dosomecomputations(v);
}
return retvalue;
}
Try to check just the snippet above with your MISRA checker and see if it's still reporting anything. If the problem persists I would just contact the toolvendor and ask him about that issue.
Hey I want to delete a node from my binary tree. I know a node cannot be deleted if it has both right and left children. So I have written code accordingly. But every time the program runs, it crashes.
void btdel(btree *b, char d)
{
if (b->lchild->data!=d&&b->lchild!=NULL)
btdel(b->lchild,d);
if (b->rchild->data!=d&&b->rchild!=NULL)
btdel(b->rchild,d);
if (b->lchild!=NULL&&b->lchild->data==d)
{
if (b->lchild->rchild==NULL)
b->lchild=b->lchild->lchild;
else if (b->lchild->lchild==NULL)
b->lchild=b->lchild->rchild;
else {cout<<"cannot delete"; exit(1);
}
}
else if (b->rchild!=NULL&&b->rchild->data==d)
{
if (b->rchild->rchild==NULL)
b->rchild=b->rchild->lchild;
else if (b->rchild->lchild==NULL)
b->rchild=b->rchild->rchild;
else
{cout<<"Cannot delete. "; exit(1);}
}
}
Quick look:
if (b->lchild->data!=d && b->lchild!=NULL)
should be:
if (b->lchild!=NULL && b->lchild->data!=d)
you need to check b->lchild if it has a valid address before reading its data.