Is this correct point to free char* - c++

I have this code
{
char *filename = createFilename(file, extension);
...
...
delete[] filename;
}
inline char *DataSet::createFilename(LPCSTR file, LPCSTR extension)
{
char *path = new char[strlen(file) + strlen(extension) + 1];
strcpy(path, file);
strcat(path, extension);
return path;
}
Am I right to delete "filename" in the main function? I get ERROR_INVALID_NAME on delete. I have checked the filename and that is correct.
I know I should be using std::string but this is existing code. Please help

If it's existing code and you can't change createFilename to return a std::string, then how about changing the call site to use std::unique_ptr. It is specialized for arrays and would be a much safer bet than doing delete on your own. See this answer.

An error of type ERROR_INVALID_NAME usually occurs when the directory name, file name or volume label is incorrect. On Windows, you might have to take care of escape sequences. For example, if the path to the file is C:\Folder\File.ext you should use the string C:\\Folder\\File.ext. In addition, some characters may not be accepted by the API you're using even though Windows allows them to be used in file and directory names. See this.

Related

C++ CreateDirectory() not working with APPDATA

I want to create a directory inside the %APPDATA% folder. I am using CreateDirectory() for this and it doesn't work. I debugged the code and it seems like the path is correct, but I can't see a new directory in my the APPDATA.
My code for creating dit in appdata:
void setAppDataDir(std::string name)
{
char* path;
size_t len;
_dupenv_s(&path, &len, "APPDATA");
AppDataPath = path;
AppDataPath += "\\"+name;
createDir(this->AppDataPath.c_str());
}
void createDir(const char* path)
{
assert(CreateDirectory((PCWSTR)path, NULL) || ERROR_ALREADY_EXISTS == GetLastError()); // no exception here
}
This is how I call the function:
setAppDataDir("thisistest");
I use Visual Studio 2019 and the debugger tells me, that path is
C:\\Users\\Micha\AppData\Roaming\\thisistest
What am I doing wrong?
CreateDirectory() is a macro that expands to CreateDirectoryW() in your case, which requires strings in UTF-16LE encoding (wchar_t*). You are casting the const char* path param to PCWSTR (const wchar_t*):
CreateDirectory((PCWSTR)path, NULL) ...
But you are not converting that string into a UTF-16LE string.
So, you need to convert your path into a wchar_t* string. There are some methods to do it, see Convert char * to LPWSTR.
The problem was the way I was giving path to CreateDirectory(). As #RemyLebeau pointed out, I should have used CreateDirectoryA(). This change solved the issue.

Segmentation fault when calling fread() c++

I dont understand the mistake I am making.
I tryed alot but I am unable to read my FILE.
Basically I write an structure into a file named 0.txt / 1.txt / 2.txt ... based of account amound.
I realy seached hours to fix my problem but I dont understand how I can fix and why I get the ERROR.
Also I have no problem in complining my code (with dev c++) but when I press on Load Accounts Button I get the ERROR "Segmentation Fault" (using windows 7).
I noticed that the problem is at fread() line in function ladeAccounts().
The name of my Structure is "iAccount".
The variable infoma is as iAccount typed and the "number of accounts existing" typed as int anzahl in newAccount() decides the path.
iAccount looks like this:
struct iAccount
{
string ID;
string password;
int level;
};
This is how I write my STRUCT into the FILE:
void Account::newAccount(int anzahl, string username, string pw, int lvl)
{
iAccount neu;
neu.ID = username;
neu.password = pw;
neu.level = lvl;
ss.str("");
ss<<anzahl;
s = ss.str();
s = "Accounts/"+s+".txt";
f1 = fopen(s.c_str(), "w");
fseek(f1, 0, SEEK_SET);
fwrite(&infoma, sizeof(iAccount), 1, f1);
fclose(f1);
}
This is how I read the File (ERROR APPEARS when I call fread()
void Account::ladeAccount(int nummer)
{
stringstream sa;
iAccount account_geladen;
sa.str("");
sa<<nummer;
s = sa.str();
s = "Accounts/"+s+".txt";
f2 = fopen(s.c_str(), "r");
fseek(f2, 0, SEEK_SET);
fread(&infoma, sizeof(infoma), 1, f2);
fclose(f2);
}
Thank you for your help. I have no clue where my problem is and as I said I am searching for hours.
EDIT:
The file gets opened I tryed it (f2 is true!).
EDIT":
ERRNO = 0 !!!
SEE HERE:
ostringstream Str;
Str << errno;
infoma.ID = Str.str();
Just did this to see the result of errno in my wxtextlabel.
Reason
You are most probably calling fread on a NULL file handle. So you have two problems here:
In your code (you don't check if fread succeeds or returns a NULL value)
Your file can't be opened for some reason (this, you should investigate...)
Explication
fopen (see documentation) can return a NULL handle for different reasons. If you don't check the validity of the handle before calling fread you will have a segmentation fault.
Tips
As you can read in the official documentation I linked above, on most library implementations the errno variable can help you giving the system-specific error code on failure. This could help you debugging your error in opening the file.
Side Issues
Once you solve this bug in our code you will have other issues. As people (notably #Christophe) remarked in other answers, there is a structural problem in your code because you try to serialize/deserialize on your file objects non POD (aka your strings). Since string are complex objects you can't serialize them directly.
The approach of using an array of characters will work correctly, as simple types can be handled the way you coded.
For this reason, you can use the std::string c_str() method to obtain a null terminated array of chars from your string and store it in the file.
The opposite operation is even more straightforward, as you can initialize a std::string simply passing the deserialized array of chars:
std::string str(the_array);
You have a problem because you use fread() to load binary data. But this works only with plain old data (POD) objects.
It uses to give desastrous results with less trivial objects especially if the internals of these manage dynamic memory allocaton and/or pointers like it's the case here with strings.
By the way:
If you read/write binary data, you should really use "rb"/"wb" as mode for fopen(). If you don't you would'nt necessary have a seg.fault, but your data might be incorrect on some systems.
Edit:
Sorry, I didn't read well enough: if it happens right at fread() the reason provided by Alex will certainly help. However I leave this answer because as soon as you've solved your fopen() issue, you might get segmentation errors if you try to work with the object that you've read. If you're not conviced, look at sizeof(iAccount) and compare it to the size your string content.
EDIT
if(f2) is true so I am wrong and file got opened successfull right?
I found out that the file is not opened/the fopen can not handle with the path for example 0.txt .
Also I tryed to enter the path directly without building it (without stringstream and so on). Still I have the problem of the segmentation fault. I checked everything the file exists in the folder Accounts. I have an other file called "Accounts.txt" in the same folder and there I have no problem reading the amound of accounts existing (also using a struct). There I dont even check if the fopen had success but it works anyway I will write the code for the file-open-check later.
The code for the reading/writing into Accounts/Accounts.txt is:
struct init{
int anzahl_1;};
init anzahl;
FILE* f;
static string ss = "Accounts/Accounts.txt";
int account_anzahl1()
{
f = fopen(ss.c_str(), "r");
fread(&anzahl, sizeof(init), 1, f);
fseek(f, 0, SEEK_END);
fclose(f);
return anzahl.anzahl_1;
}
void account_anzahl_plus()
{
anzahl.anzahl_1 = anzahl.anzahl_1 +1;
f = fopen(ss.c_str(), "w");
fwrite(&anzahl, sizeof(init), 1, f);
fclose(f);
}
There I have no problem!

Trash characters when using buffers in c++

I have a DLL that I need to handle in C++. I'm using WxWidgets (standard compilation, but I also tried Unicode on/off) and NetBeans. I also tried dealing with this without WxWidgets (windows.h) and had same problems.
Here is how I access the DLL functions using WxWidgets:
// -------------------- POINTERS TO FUNCTIONS
typedef bool(*TYPE_DLL_SetLicense)(char*, char*);
typedef bool(*TYPE_DLL_PingConnection)(char*);
typedef char*(*TYPE_DLL_ERR_DESCRIPTION)(void);
class DLL_Library
{
public:
// pointers to functions inside dll
TYPE_DLL_SetLicense DLL_SetLicense; //initialize - will wor fine as it returns only true/false (buffer only provide data)
TYPE_DLL_PingConnection DLL_PingConnection; //ping to serwer. Will return trahs, becouse it uses buffer to provide data ang get answear back
TYPE_DLL_ERR_DESCRIPTION DLL_ERR_DESCRIPTION; //error description. No buffer, no trouble. Returns correct string.
wxDynamicLibrary dynLib2;
int initialize(void)
{
//patch to dll
wxString path = wxStandardPaths::Get().GetExecutablePath().BeforeLast('\\') + _("\\DLL_dll\\DLLMOK.dll");
if(!wxFile::Exists(path)) return -1;
//load dll
if(!dynLib2.Load(path)) return -2;
//Assign functions in dll to variable
DLL_SetLicense=(TYPE_DLL_SetLicense) dynLib2.GetSymbol(wxT("DLL_SetLicense"));
DLL_PingConnection=(TYPE_DLL_PingConnection) dynLib2.GetSymbol(wxT("DLL_PingConnection"));
DLL_ERR_DESCRIPTION=(TYPE_DLL_ERR_DESCRIPTION) dynLib2.GetSymbol(wxT("DLL_ERROR_DESCRIPTION"));
return 0;
}
};
And here is the function I run. It should return and XML content, that I try to save to the file.
//DLL_PingConnection
//result ping to be save in file
wxFile file_ping_xml;
plik_ping_xml.Open(wxT("C:\\dll\\ping.xml"),wxFile::write);
char buffor_ping_xml[2000];
//I run the function here
bool is_ping = DLL_PingConnection(buffor_ping_xml);
if(is_ping)
{
tex_box->AppendText(wxT("DLL_PingConnection True\n"));
//we save result to file
bool is_write_ping_ok = file_ping_xml.Write(buffor_ping_xml,2000);
if (is_write_ping_ok){tex_box->AppendText(wxT("Save to file is ok ok\n"));}
else {tex_box->AppendText(wxT("Save to file failed :( \n"));}
}
else
{
tex_box->AppendText(wxT("DLL_PingConnection False\n"));
}
std::cout << "Error description: " << DLL_ERR_DESCRIPTION() << "\n"; //will work fine both in saving to file, and in streaming to screen.
The problem is that inside the file instead of good content I get rubbish like this:
NOTE that this only happens in functions that use buffers like:
char buffer[2000] //buffer will contain for example file xml
function do_sth_with_xml(buffer) //buffer containing xml will (should) be overwriten with xml results of the function - in our case DLL_PingCONNECTION should save in buffer xml with connection data
Documentation say that the DLL operates on Windows-1250. File ping.xml I have set to windows ANSI, but I don't think problem lies here.
EDIT: I have written problem without WxWidgets (I load DLL using windows.h) - same problems. Here is the code: Getting trash data in char* while using it as buffer in function . Please help :(
This
DLL_PingConnection=(TYPE_DLL_PingConnection)
shouldn't it be
DLL_PingConnection=(TYPE_DLL_PingConnection) dynLib2.GetSymbol(wxT("DLL_PingConnection"));
?
seems otherwise you will not get a valid pointer to the function in the DLL.
as a general rule you should check return values, especially from a DLL
you load dynamically since it happens that you sometimes get another version
of the DLL which may have a function with same name but other signature or
where is missing entirely.
You named a function
DLL_PingConnection=(TYPE_DLL_PingConnection) dynLib2.GetSymbol(....
and call it with
OSOZ.OSOZ_PingConnection(buffor_ping_xml);
you typedef a function
typedef bool(*TYPE_DLL_PingConnection)(char*);
you create a variable
char buffor_ping_xml[2000];
in your typedef it is char* and your buffor_ping_xml is char
how can that work ?
try
char *buffor_ping_xml = new char[2000];
/* or */
wchar_t *buffor_ping_xml = new wchar_t[2000];
/* or */
wxChar *buffor_ping_xml = new wxchar[2000];
bool is_ping = DLL_PingConnection(buffor_ping_xml);
wxString mystring = wxString::FromUTF8(buffor_ping_xml);
write mystring to file.
To Do:
look in your wxwidgets\libs folder for your libs
are there libwxmsw29ud_* with a 'u' in the name (after version number here 29)?
If not You can not use unicode
If yes next steps
for all different test char *, wchar_t *, wxChar * give the files different name.
for example file_ping_xml.Open(wxT("C:\dll\ping_w_t_FromUTF8.xml"), ...
for wchar_t * in combination with
wxString mystring = wxString::FromUTF8(buffor_ping_xml);
also in combination with
wxString mystring(buffor_ping_xml);
Then check out the look like, of the files in a browser .
To test you can go to your wxWidgets sample folder . Compile in the folder C:\wxWidgets\samples\docview\docview.cpp . Open with docview.exe a unicode file . How does it look.
Unicode download file
Unicode-related compilation settings
You should define wxUSE_UNICODE to 1 to compile your program in Unicode mode. This currently works for wxMSW, wxGTK, wxMac and wxX11. If you compile your program in ANSI mode you can still define wxUSE_WCHAR_T to get some limited support for wchar_t type.
Here is answear: Getting trash data in char* while using it as buffer in function.
Thanks everyone - expecially for patience.

Add a pre-declared path to a filename argument (LPCSTR)

I have a list of files I need to open in a certain function via a LPCSTR argument, but unfortunately they're located in certain folders (subdirectories of the main program root) with a very long path, and I don't want to type it in every time I want to pass the filenames.
To be more precise, I have the function D3DXCreateTextureFromFile() which asks for the filename, and for example, I have the files a.png, b.png, c.png located in the "...\Materials\Textures\Textures_For_This\Textures_For_That\More_Specific_Texture_Location\" subdirectory of the main program. How can I register this path and add it to the filename argument in a lean and mean way?
Like some sort of this:
D3DXCreateTextureFromFile(bla, **DECLARED_DIR** + a.png, bla)
//same for b.png, c.png
Or even a subfunction that unifies the path and the filename:
D3DXCreateTextureFromFile(bla, UnifyText(DECLARED_DIR, a.png), bla)
Yep, easiest to make a function to combine the directory with the filename and include separator if required. Because you want to pass this as an argument, you want to avoid allocating a string and having to clean it up... So use the C++ string class.
I generally do something like this:
string TexturePath( LPCSTR filename = NULL )
{
if( filename == NULL ) return string(TEXTURE_DIR);
return string(TEXTURE_DIR) + "\" + filename;
}
Of course, you'll be relying on that string being implicitly cast to LPCSTR later. If you want to be more explicit then do the (slightly ugly) call to string::c_str():
D3DXCreateTextureFromFile(bla, TexturePath("a.png").c_str(), bla)
[Edit]
Another way, if you are doing this single-threaded, is to use a static buffer:
LPCSTR TexturePath( LPCSTR filename = NULL )
{
static char pathBuf[MAX_PATH];
if( filename == NULL ) return TEXTURE_DIR;
sprintf( pathBuf, "%s\\%s", TEXTURE_DIR, filename );
return pathBuf;
}
String main_dir="C:\\\Materials\\Textures\\Textures_For_This\\Textures_For_That\\More_Specific_Texture_Location\\";
String files[]={"a.png","b.png","c.png"};
String fullpath=main_dir;
fullpath+=files[0];
D3DXCreateTextureFromFile(bla, fullpath.c_str(), bla);
If you're using C++ why not use a stringstream to concatenate the 2 strings together and then call .c_str() on the resulting string. Or you can use the c-style, strcat into a large enough buffer.

How can i get the listing of files and directories of a path using C++?

I am using the directory class to get this information but unable to assign this data to a data member of my own class. i am doing an oop project. Furthermore,I want to use the concept of Dynamism(containment).I have created two class, mydirectory and myfiles as under:
class files
{
string fname[25];
public:
files()
{
fname=NULL;
}
};
class directory
{ private:
directory *d;
string *dname[25]; //* to show there may be a subdirectory,there may be not.
files *ff[25]; // data member string *fname[25];
int numd,numf;
public:
directory()
{
numd=0;numf=0;
}
Now when if I want to use the statment:
Directory::GetDirectories("D:\\");
how can I assign the directory names to "dname" of directory class.
I dont want to include a third party software.
also i need help on the topic: how can a file (doc file/pdf/txt/pwt etc) can be opened from c++ code outside the console? I am very worried. please help me. thanks in advance.
I am new to c++ so please forgive if there are any errors in pointer handling, as I am doing this containment for the first time. I also need some reading stuff.
The simplest way to do it in C++ is using boost::filesystem.
As long as the path is a directory you can iterate over it using either a directory_iterator or a recursive_directory_iterator.
eg:
boost::filesystem::path dirname( "D:\\" );
std::vector<boost::filesystem::path> topLevel( directory_iterator(dirName),
directory_iterator() );
std::vector<boost::filesystem::path> wholeDrive(
recursive_directory_iterator(dirName), recursive_directory_iterator() );
As this is marked homework, we're not going to be helping you much by giving you the correct answer. But I will point you in the right direction.
You've indicated you're doing this under Visual C++. Well without using any third party libraries but just what's built in, you'll need to access the Win32 API.
FindFirstFile() & FindNextFile() are what you need.
You'll call FindFirstFile first off to obtain the directory handle.
The parameter is the D:\ that you're passing into your class.
Then call FindNextFile in a while loop.
e.g. The basic principle of using those API's is
HANDLE h = FindFirstFile("D:\\");
WIN32_FIND_DATA data;
while (FindNextFile(h, &data))
{
// Check if it's a directory or not
if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
// Add to dname
}
}
Consider using std::vector for your dname instead of string*
because you're stuck with 25 entries. Using vector it'll grow for you.
As said CashCow, boost::filesystem
As a general rule, in C++ for such examples, you don't need any pointer. Here a some mistakes you should correct:
string fname[25];
This declares an array of 25 strings. You probably wanted a string of 25 chars ? Well, in std::string, you don't need to care about the length. std::string fname; is enough
std::string file_name;
file_name = "baz.txt";
fname=NULL;
If fname is a string, then it's not a pointer. So you can't assign NULL to it. A std::string is by default initialized as an empty string. You can leave the whole constructor out.
string *dname[25]
I suppose you wanted to have an array of string. Just use :
std::vector<std::string> dnames;
dnames.push_back("foo");
dnames.push_back("bar"); // dnames now contains {"foo","bar"}
And you'll have a dynamically resizable vector of strings.
See : no need of any pointer. No need for any new
Finally I completed the short project.To get the list of files and sub directories, I made use of .NET Framework namespace "System".It has got classes like "FileInfo" and "DirectoryInfo"(both belong to System::IO) which do the above required task.But here,all the string related stuff is of System::String , not of std::string.To convert System::String to std::string, I used the following code(I got this conversion's code from a forum and it worked fine without any error):
string Str2str(String ^a)
{
array<Byte> ^chars = System::Text::Encoding::ASCII->GetBytes(a);
pin_ptr<Byte> charsPointer = &(chars[0]);
char *nativeCharsPointer = reinterpret_cast<char *>(static_cast<unsigned char *>(charsPointer));
string native(nativeCharsPointer, chars->Length);
return native;
}
Here is a short code for getting list of sub directories from a drive(D: drive is going to be searched):
#include<iostream>
#using<mscorlib.dll>
using namespace strd;
using namespace System;
using namespace System::IO;
int main()
{int count=50;
string name[count];//to hold directories names
string b;
int s=0;
DirectoryInfo^ di = gcnew DirectoryInfo("d:\\");
if(di->Exists)
{array<DirectoryInfo^>^diArr = di->GetDirectories();
Collections::IEnumerator^ myEnum = diArr->GetEnumerator();
while ( myEnum->MoveNext() )
{DirectoryInfo^ dri = safe_cast<DirectoryInfo^>(myEnum->Current);
String ^a=(dri->Name->ToString());
int n=b.size();
b=Str2str(a); `// code given in the starting`
if (s<count)
{name[s]=b;
s++;}
}
This involves Managed C++ knowledge. Visit these:
.NET Programming Guide
C++: The Most Powerful Language for .NET Framework Programming
I compiled this on Visual Studio 2008. I will be very grateful if you appriciate my effort.Further suggestions are most welcomed.