I'm using the opendir and readdir functions to search for file names containing .txt in the given directory.
Is there any way I can test a certain extension via a function without using a loop? (currently I have to loop through de-> d_filename to check but they are quite complicated, in addition I tried de->d_type however it did not return the extension)
In addition, this function is returning the name of the file name, my desired result is to get the path name from the beginning, is there a function return wchar_t* similar to de->d_fullfilepath?
This is all I have :
DIR* dr = opendir(lpszFolder);
vector<const wchar_t*> names; //get list file with extension .txt then push to this vector
if (dr == NULL) // opendir returns NULL if couldn't open directory
{
printf("Could not open current directory");
return {};
}
// Refer http://pubs.opengroup.org/onlinepubs/7990989775/xsh/readdir.html
// for readdir()
while ((de = readdir(dr)) != NULL)
{
if (de->d_type ... 'txt') // function get just .txt file.
{
wchar_t* pwc =new wchar_t(lpszFolder); //initialize new instance file path
const size_t cSize = de->d_namlen + 1; //get file len
mbstowcs(pwc, de->d_name, cSize); //combine thisfilepath + extension
names.push_back(pwc);
}
}
Best Libc function to search reversely
You might consider strrchr
Locate last occurrence of character in string
Returns a pointer to the last occurrence of character in the C string str.
The terminating null-character is considered part of the C string. Therefore, it can also be located to retrieve a pointer to the end of a string.
Sample Program to find files with specific file extension
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <string>
#include <vector>
using namespace std;
const char *get_filename_ext(const char *filename) {
const char *dot = strrchr(filename, '.');
return (!dot || dot == filename) ? "" : dot + 1;
}
int main(int ac, char **av) {
if (ac != 2)
return 1;
const char *lookup = (ac==3) ? av[2] : "txt";
const char *lpszFolder = av[1];
DIR* dr = opendir(lpszFolder);
vector<const wchar_t*> names; //get list file with extension .txt then push to this vector
if (dr == NULL) // opendir returns NULL if couldn't open directory
{
printf("Could not open current directory");
return (1);
}
struct dirent *ent;
uint32_t len = sizeof(((dirent*)0)->d_name);
char ext[len];
while ((ent = readdir (dr)) != NULL) {
(void)ext;
strncpy(ext, get_filename_ext(ent->d_name), len-1);
if (!strcmp(lookup, ext))
names.push_back(reinterpret_cast < wchar_t*>(ent->d_name));
}
closedir(dr);
for (auto name : names)
printf("%s", (char *)name);
return 0;
}
Main Usage
Test with:
g++ a.cpp && ./a.out myfolder
will look for all files with ".txt" extensions
Or if you want a specific extension like ☠ :
g++ a.cpp && ./a.out myfolder ☠
In modern C++ you should use algorithms from the std::algorithm library to avoid loops. These algorithms prevent many possible problems from the wrong usage of loops, mostly out of bounds problems.
And, C++ can deal with "wide strings" with the base data type wchar_t. You can simply use std::wstring instead of std::string.
Any you should not and never use plain C-Style arrays or pointers to char or wchar_t. These are that error prone that they should really not be used.
Even if you have legacy code with "old" "char*"-strings, put them into a std::string and use those in the future.
Next: You MUST NOT use raw pointers for owned memory. You should try to avoid pointers in general and use smart pointers instead. And you should not use new in C++. There is nearly no need for it any longer. Use containers from the STL.
Now back to your original question:
How to check char array contain any char without loop in C++?
Yes, by using std::algorithmsand iterators
Is there any way I can test a certain extension via a function without using a loop?
Yes, ths std::filesystem will help you. It has all the functionality you need and is superior to all handcraftedt solutions. It can especially also deal with wchar_t and wide stringsstd::wstring
In the following code, I generated an example function that returns a std::vector filled with all fule file paths in a specified directory with a given string.
#include <iostream>
#include <string>
#include <filesystem>
#include <vector>
#include <algorithm>
// Name space alias for saving typing work
namespace fs = std::filesystem;
// A function, that gets a path to a director as wstring and returns all file paths as wstring with a given extension
std::vector<std::wstring> getFilesWithCertainExtension(const std::wstring& dirPath, const std::wstring& extension = L".txt") {
// Put the wstring with path to the the directory in a generic path variable
fs::path startPath{ dirPath };
// Here we sill store all directory entries having a given extension
std::vector<fs::directory_entry> filesInDirectory{};
// Go thorugh the directory and copy all directory entries with a given extension int our vector
std::copy_if(fs::directory_iterator(startPath), {}, std::back_inserter(filesInDirectory),
[&](const fs::directory_entry& de) { return de.path().extension().wstring() == extension; });
// The result of this function should be a vector of wstrings
std::vector<std::wstring> result(filesInDirectory.size());
// Convert directory entries to wstrings
std::transform(filesInDirectory.begin(), filesInDirectory.end(), result.begin(),
[](const fs::directory_entry& de) { return de.path().wstring(); });
return result;
}
int main() {
// Read all files from c:\\temp with the default extension ".txt"
std::vector<std::wstring> files = getFilesWithCertainExtension(L"c:\\temp");
// Show full paths to user
for (const std::wstring& ws : files) std::wcout << ws << L"\n";
return 0;
}
This is one of many possible solutions. This could even be optimized, if I would understand your requirements better.
I would explain the function in more detail. But, becuase anyway nobody will read this, I save the time.
Related
I've got a deceptively complex one for y'all.
I am attempting to make a program which makes use of an INI config file (I am using the libconfini C library), which looks like this:
[General]
output_directory = /scratch/miles/trans_assembly_pipeline/
[SRA accessions]
SRR18328591
SRR28481881
It parses the information therein into a map, index-able by section, and then by key, which looks like this (the only important bit really is the char* option in the variant object):
map<string, map<string, boost::variants<int, bool, double, string, char*>>
Since keys in INI files can have various types, I am utilizing Boost's 'Variants' library to allow for multiple value types. Finally, for convenient file management, I am using Boost's 'Filesystem' library.
I have an INI parsing implementation file, which basically just stores the INI data into that map type, defined thus (the header for which, merely containing function declarations and definition directives, can be found at the bottom):
#include "ini_parse.h"
namespace fs = boost::filesystem;
// Dispatch INI data to a map, indexable by sections, then by keys
static int ini_callback(IniDispatch * const dispatch, void * map_pt) {
#define thismap (reinterpret_cast<INI_MAP*>(map_pt))
if (dispatch->type == INI_COMMENT) {
return 0;
}
if (dispatch->type == INI_SECTION) {
INI_MAP_ENTRY newSec;
thismap->insert(std::pair<std::string, INI_MAP_ENTRY>(dispatch->data, newSec));
return 0;
}
if (dispatch->type == INI_KEY) {
(*thismap)[dispatch->append_to].insert(std::pair<std::string, BOOST_VAR>(dispatch->data, dispatch->value));
}
return 0;
}
// Given a FILE object, return a buffer containing its contents
char * make_ini_buffer(FILE * iniFile) {
char * iniBuffer;
long sz;
fseek(iniFile, 0L, SEEK_END);
sz = ftell(iniFile);
rewind(iniFile);
iniBuffer = (char*)malloc(sz + 1);
fread(iniBuffer, 1, sz, iniFile);
return iniBuffer;
}
// Given the path/name of an INI config file, return a map of its data
// which can be indexed by sections, and then by keys
INI_MAP make_ini_map(const char * configPath) {
FILE * configIni = fopen(configPath, "r");
fs::path configPathObj(configPath);
try {
if (!configIni) {
std::string fileError = "ERROR: Cannot open config file: ";
throw std::runtime_error(fileError);
}
} catch (std::runtime_error& e){
std::cerr << e.what() << configPathObj.filename() << std::endl;
return {};
}
INI_MAP iniMap;
char * iniBuffer = make_ini_buffer(configIni);
strip_ini_cache(iniBuffer, strlen(iniBuffer), INI_DEFAULT_FORMAT,
NULL, ini_callback, &iniMap);
delete [] iniBuffer;
return iniMap;
}
INI_MAP cfgIni = make_ini_map("../config.ini");
Note the final line, outside of any other function, defining 'cfgIni'. The idea is to define a global INI data storage object that can be used externally by other files -- for example, like this:
#include "ini_parse.h"
int main() {
extern INI_MAP cfgIni;
extern int size_path;
std::cout << cfgIni["General"]["output_directory"] << std::endl;
return 0;
}
Now for my problem: When declaring 'cfgIni' externally in this separate file, it appears that bits of memory are getting lost from where it is defined in my implementation file to where it is declared externally and caught here. I have no issue accessing the keys in the parent/child map, but the values are more illusive.
When printing the contents of the section "General", "output_directory" is returned, no problem.
I would expect the final line in the above code snippet to print the filepath char* array, to which "output_directory" is set in the INI file.
However, I instead get some random characters, like "�U". What is even more confusing is when I print out the size of this return value in memory using sizeof(), it returns '40', the correct number of characters in that filepath.
I have linked the documentation for the libraries I used and their functions. Apologies for the length/complexity of this question.
strip_ini_cache(): https://madmurphy.github.io/libconfini/html/confini_8c.html#a25d648d387f6e8bc36e7965accfca63b
Boost.variant: https://www.boost.org/doc/libs/1_61_0/doc/html/variant.html
Boost.filesystem: https://www.boost.org/doc/libs/1_80_0/libs/filesystem/doc/reference.html
Below is my header file:
#include <iostream>
#include <string>
#include <map>
#include <cstdio>
#include <confini.h>
#include <boost/filesystem.hpp>
#include <boost/variant.hpp>
#define BOOST_VAR boost::variant<int, bool, double, std::string, char*>
#define INI_MAP_ENTRY std::map<std::string, BOOST_VAR>
#define INI_MAP std::map<std::string, INI_MAP_ENTRY>
static int ini_callback(IniDispatch * const dispatch, void * map_pt);
char * make_ini_buffer(FILE * iniFile);
INI_MAP make_ini_map(const char * configPath);
The answer to this is really quite trivial. When passed by value, as I had done in one of my files, a shallow copy of the object was created, wherein the pointers to the char arrays were overwritten with wild addresses.
The solution was to pass by const reference.
Is there a (cross-platform) way to get a C FILE* handle from a C++ std::fstream ?
The reason I ask is because my C++ library accepts fstreams and in one particular function I'd like to use a C library that accepts a FILE*.
The short answer is no.
The reason, is because the std::fstream is not required to use a FILE* as part of its implementation. So even if you manage to extract file descriptor from the std::fstream object and manually build a FILE object, then you will have other problems because you will now have two buffered objects writing to the same file descriptor.
The real question is why do you want to convert the std::fstream object into a FILE*?
Though I don't recommend it, you could try looking up funopen().
Unfortunately, this is not a POSIX API (it's a BSD extension) so its portability is in question. Which is also probably why I can't find anybody that has wrapped a std::stream with an object like this.
FILE *funopen(
const void *cookie,
int (*readfn )(void *, char *, int),
int (*writefn)(void *, const char *, int),
fpos_t (*seekfn) (void *, fpos_t, int),
int (*closefn)(void *)
);
This allows you to build a FILE object and specify some functions that will be used to do the actual work. If you write appropriate functions you can get them to read from the std::fstream object that actually has the file open.
There isn't a standardized way. I assume this is because the C++ standardization group didn't want to assume that a file handle can be represented as a fd.
Most platforms do seem to provide some non-standard way to do this.
http://www.ginac.de/~kreckel/fileno/ provides a good writeup of the situation and provides code that hides all the platform specific grossness, at least for GCC. Given how gross this is just on GCC, I think I'd avoid doing this all together if possible.
UPDATE: See #Jettatura what I think it is the best answer https://stackoverflow.com/a/33612982/225186 (Linux only?).
ORIGINAL:
(Probably not cross platform, but simple)
Simplifying the hack in http://www.ginac.de/~kreckel/fileno/ (dvorak answer), and looking at this gcc extension http://gcc.gnu.org/onlinedocs/gcc-4.6.2/libstdc++/api/a00069.html#a59f78806603c619eafcd4537c920f859,
I have this solution that works on GCC (4.8 at least) and clang (3.3 at least) before C++11:
#include<fstream>
#include<ext/stdio_filebuf.h>
typedef std::basic_ofstream<char>::__filebuf_type buffer_t;
typedef __gnu_cxx::stdio_filebuf<char> io_buffer_t;
FILE* cfile_impl(buffer_t* const fb){
return (static_cast<io_buffer_t* const>(fb))->file(); //type std::__c_file
}
FILE* cfile(std::ofstream const& ofs){return cfile_impl(ofs.rdbuf());}
FILE* cfile(std::ifstream const& ifs){return cfile_impl(ifs.rdbuf());}
and can be used this,
int main(){
std::ofstream ofs("file.txt");
fprintf(cfile(ofs), "sample1");
fflush(cfile(ofs)); // ofs << std::flush; doesn't help
ofs << "sample2\n";
}
Note: The stdio_filebuf is not used in newer versions of the library. The static_cast<>() is somewhat dangerous too. Use a dynamic_cast<>() instead of if you get a nullptr you need that's not the right class. You can try with stdio_sync_filebuf instead. Problem with that class is that the file() is not available at all anymore.
Limitations: (comments are welcome)
I find that it is important to fflush after fprintf printing to std::ofstream, otherwise the "sample2" appears before "sample1" in the example above. I don't know if there is a better workaround for that than using fflush. Notably ofs << flush doesn't help.
Cannot extract FILE* from std::stringstream, I don't even know if it is possible. (see below for an update).
I still don't know how to extract C's stderr from std::cerr etc., for example to use in fprintf(stderr, "sample"), in an hypothetical code like this fprintf(cfile(std::cerr), "sample").
Regarding the last limitation, the only workaround I found is to add these overloads:
FILE* cfile(std::ostream const& os){
if(std::ofstream const* ofsP = dynamic_cast<std::ofstream const*>(&os)) return cfile(*ofsP);
if(&os == &std::cerr) return stderr;
if(&os == &std::cout) return stdout;
if(&os == &std::clog) return stderr;
if(dynamic_cast<std::ostringstream const*>(&os) != 0){
throw std::runtime_error("don't know cannot extract FILE pointer from std::ostringstream");
}
return 0; // stream not recognized
}
FILE* cfile(std::istream const& is){
if(std::ifstream const* ifsP = dynamic_cast<std::ifstream const*>(&is)) return cfile(*ifsP);
if(&is == &std::cin) return stdin;
if(dynamic_cast<std::ostringstream const*>(&is) != 0){
throw std::runtime_error("don't know how to extract FILE pointer from std::istringstream");
}
return 0; // stream not recognized
}
Attempt to handle iostringstream
It is possible to read with fscanf from istream using fmemopen, but that requires a lot of book keeping and updating the input position of the stream after each read, if one wants to combine C-reads and C++-reads. I wasn't able to convert this into a cfile function like above. (Maybe a cfile class that keeps updating after each read is the way to go).
// hack to access the protected member of istreambuf that know the current position
char* access_gptr(std::basic_streambuf<char, std::char_traits<char>>& bs){
struct access_class : std::basic_streambuf<char, std::char_traits<char>>{
char* access_gptr() const{return this->gptr();}
};
return ((access_class*)(&bs))->access_gptr();
}
int main(){
std::istringstream iss("11 22 33");
// read the C++ way
int j1; iss >> j1;
std::cout << j1 << std::endl;
// read the C way
float j2;
char* buf = access_gptr(*iss.rdbuf()); // get current position
size_t buf_size = iss.rdbuf()->in_avail(); // get remaining characters
FILE* file = fmemopen(buf, buf_size, "r"); // open buffer memory as FILE*
fscanf(file, "%f", &j2); // finally!
iss.rdbuf()->pubseekoff(ftell(file), iss.cur, iss.in); // update input stream position from current FILE position.
std::cout << "j2 = " << j2 << std::endl;
// read again the C++ way
int j3; iss >> j3;
std::cout << "j3 = " << j3 << std::endl;
}
Well, you can get the file descriptor - I forget whether the method is fd() or getfd(). The implementations I've used provide such methods, but the language standard doesn't require them, I believe - the standard shouldn't care whether your platform uses fd's for files.
From that, you can use fdopen(fd, mode) to get a FILE*.
However, I think that the mechanisms the standard requires for synching STDIN/cin, STDOUT/cout and STDERR/cerr don't have to be visible to you. So if you're using both the fstream and FILE*, buffering may mess you up.
Also, if either the fstream OR the FILE closes, they'll probably close the underlying fd, so you need to make sure you flush BOTH before closing EITHER.
In a single-threaded POSIX application you can easily get the fd number in a portable way:
int fd = dup(0);
close(fd);
// POSIX requires the next opened file descriptor to be fd.
std::fstream file(...);
// now fd has been opened again and is owned by file
This method breaks in a multi-threaded application if this code races with other threads opening file descriptors.
yet another way to do this in Linux:
#include <stdio.h>
#include <cassert>
template<class STREAM>
struct STDIOAdapter
{
static FILE* yield(STREAM* stream)
{
assert(stream != NULL);
static cookie_io_functions_t Cookies =
{
.read = NULL,
.write = cookieWrite,
.seek = NULL,
.close = cookieClose
};
return fopencookie(stream, "w", Cookies);
}
ssize_t static cookieWrite(void* cookie,
const char* buf,
size_t size)
{
if(cookie == NULL)
return -1;
STREAM* writer = static_cast <STREAM*>(cookie);
writer->write(buf, size);
return size;
}
int static cookieClose(void* cookie)
{
return EOF;
}
}; // STDIOAdapter
Usage, for example:
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/bzip2.hpp>
#include <boost/iostreams/device/file.hpp>
using namespace boost::iostreams;
int main()
{
filtering_ostream out;
out.push(boost::iostreams::bzip2_compressor());
out.push(file_sink("my_file.txt"));
FILE* fp = STDIOAdapter<filtering_ostream>::yield(&out);
assert(fp > 0);
fputs("Was up, Man", fp);
fflush (fp);
fclose(fp);
return 1;
}
There is a way to get file descriptor from fstream and then convert it to FILE* (via fdopen). Personally I don't see any need in FILE*, but with file descriptor you may do many interesting things such as redirecting (dup2).
Solution:
#define private public
#define protected public
#include <fstream>
#undef private
#undef protected
std::ifstream file("some file");
auto fno = file._M_filebuf._M_file.fd();
The last string works for libstdc++. If you are using some other library you will need to reverse-engineer it a bit.
This trick is dirty and will expose all private and public members of fstream. If you would like to use it in your production code I suggest you to create separate .cpp and .h with single function int getFdFromFstream(std::basic_ios<char>& fstr);. Header file must not include fstream.
I ran in that problem when I was faced with isatty() only working on a file descriptor.
In newer versions of the C++ standard library (at least since C++11), the solution proposed by alfC does not work anymore because that one class was changed to a new class.
The old method will still work if you use very old versions of the compiler. In newer version, you need to use std::basic_filebuf<>(). But that does not work with the standard I/O such as std::cout. For those, you need to use __gnu_cxx::stdio_sync_filebuf<>().
I have a functional example in my implementation of isatty() for C++ streams here. You should be able to lift off that one file and reuse it in your own project. In your case, though, you wanted the FILE* pointer, so just return that instead of the result of ::isatty(fileno(<of FILE*>)).
Here is a copy of the template function:
template<typename _CharT
, typename _Traits = std::char_traits<_CharT>>
bool isatty(std::basic_ios<_CharT, _Traits> const & s)
{
{ // cin, cout, cerr, and clog
typedef __gnu_cxx::stdio_sync_filebuf<_CharT, _Traits> io_sync_buffer_t;
io_sync_buffer_t * buffer(dynamic_cast<io_sync_buffer_t *>(s.rdbuf()));
if(buffer != nullptr)
{
return ::isatty(fileno(buffer->file()));
}
}
{ // modern versions
typedef std::basic_filebuf<_CharT, _Traits> file_buffer_t;
file_buffer_t * file_buffer(dynamic_cast<file_buffer_t *>(s.rdbuf()));
if(file_buffer != nullptr)
{
typedef detail::our_basic_filebuf<_CharT, _Traits> hack_buffer_t;
hack_buffer_t * buffer(static_cast<hack_buffer_t *>(file_buffer));
if(buffer != nullptr)
{
return ::isatty(fileno(buffer->file()));
}
}
}
{ // older versions
typedef __gnu_cxx::stdio_filebuf<_CharT, _Traits> io_buffer_t;
io_buffer_t * buffer(dynamic_cast<io_buffer_t *>(s.rdbuf()));
if(buffer != nullptr)
{
return ::isatty(fileno(buffer->file()));
}
}
return false;
}
Now, you should be asking: But what is that detail class our_basic_filebuf?!?
And that's a good question. The fact is that the _M_file pointer is protected and there is no file() (or fd()) in the std::basic_filebuf. For that reason, I created a shell class which has access to the protected fields and that way I can return the FILE* pointer.
template<typename _CharT
, typename _Traits = std::char_traits<_CharT>>
class our_basic_filebuf
: public std::basic_filebuf<_CharT, _Traits>
{
public:
std::__c_file * file() throw()
{
return this->_M_file.file();
}
};
This is somewhat ugly, but cleanest I could think off to gain access to the _M_file field.
I encounter a scenario to register arbitrary addresses as char* in a program.I need to pass each one as char* to the third party library for further action.
The third_party_function is describe as such in its header file:
virtual void RegisterFront(char *pszFrontAddress) = 0;
First, the program have to read from a config file with a group of addresses like:
tcp://18.19.20.22:7778; tcp://18.19.20.24:7778; tcp://18.19.20.25:7778;
The procedure to analyze this string and break it to a vector of addresses is simple if I define it as a cstring and use a loop. But then each has to be registered in that function in order for the library to connect to another address if current failed. Currently the configuration has 3 addresses but an arbitrary number of them should be allowed.
A static way to assign char* variables would be like this:
...
#include third_party_lib;
char* addr1 = "tcp://18.19.20.22:7778".c_str();
char* addr2 = "tcp://18.19.20.24:7778".c_str();
RegisterFront(addr1);
RegisterFront(addr2);
I omitted the loop to analyze the addresses out from the config, but the essence is clear: I cannot name addr[n]'s in the program since the number of addresses is uncertain - it depends on how many would be written in that config line.
i.e. For the 3 addresses scenario I can assign addr1 addr2 addr3 in the code. But once it is compiled, what if the config line now contains only two addresses? What about changing to 5?
How to improve the above to achieve dynamically assigning an arbitrary number of char* variables and pass each one of them to the third party function RegisterFront? - Of course you could replace it by some print function to try out, but the input type shall be the same.
BTW: Replacement for RegisterFront function:
void printFront(char *addr){
cout << addr <<endl;
}
Let's say your config line is this:
std::string s = "tcp://18.19.20.22:7778; tcp://18.19.20.24:7778; tcp://18.19.20.25:7778;"
s can also be a char*, it doesn't matter. At some point in your code, you've got a string representation of that config line that you've read from file or wherever.
Then to loop through that string for each URL and all your RegisterFront function is just this.
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
void trim(std::string& s) {
size_t start = 0;
size_t end = s.size();
while ((start < end) && isspace(s[start]))
{
start++;
}
while ((end > start) && isspace(s[end - 1]))
{
end--;
}
s = s.substr(start, end - start);
}
void RegisterAddresses(const std::string& config_line) {
std::istringstream ss(config_line);
std::string address;
while (std::getline(ss, address, ';')) {
trim(address);
// address[0] returns a reference to the first char in the string
// hence, &address[0] is the char* to the front of the string
RegisterFront(&address[0]);
}
}
Then when you have your config_line (either defined as a char* or std::string instance), you just invoke it either way:
std::string s = "tcp://18.19.20.22:7778; tcp://18.19.20.24:7778; tcp://18.19.20.25:7778;";
RegisterAddresses(s);
This also works (a temporary std::string is passed to RegisterAddresses - constructed from the char* passed in)
const char* s = "tcp://18.19.20.22:7778; tcp://18.19.20.24:7778; tcp://18.19.20.25:7778;";
RegisterAddresses(s);
I am new to c++, i am on a check scanner's project and i am using an API that was provided with the scanner. Here's my code:
.h file :
#include <iostream>
#include<Windows.h>
#include<vector>
using namespace std;
class Excella
{
public:
vector<char*> getDevicesName();
};
.cpp file :
vector<char*> Excella::getDevicesName()
{
DWORD dwResult;
vector<char*> listeDevices;
char pcDevName[128]="";
int i = 6;
// the device's name is stored in the variable 'pcDevName'
while ((dwResult = MTMICRGetDevice(i, (char*)pcDevName)) != MICR_ST_DEVICE_NOT_FOUND) {
dwResult = MTMICRGetDevice(i, (char*)pcDevName);
i++;
listeDevices.push_back((char*) pcDevName);
}
return listeDevices;
}
main.cpp
vector<char*> liste = excella.getDevicesName();
if (liste.empty()!= true)
{
for (vector<char*>::iterator IterateurListe = liste.begin(); IterateurListe != liste.end(); ++IterateurListe)
{ string str(*IterateurListe);
auto managed = gcnew String(str.c_str());
devices->Items->Add(managed);
}
}
else {
MessageBox::Show("The vector is empty");
}
The problem is that i can get the right device number.. i just have some weird caracters.
Thank u for ur help.
That's not surprising.
char pcDevName[128]=""; will go out of scope at the end of of the function vector<char*> Excella::getDevicesName(). So any pointers to this that you've pushed to the vector will no longer be valid. Formally speaking, the behaviour of your program is undefined.
It's far simpler to use std::vector<std::string> instead. Remarkably, that's the only change you'd have to make: push_back((char*) pcDevName) will take a value copy of pcDevName (that's how the std::string constructor works). Drop the unnecessary (char*) casts though.
Here:
listeDevices.push_back((char*) pcDevName);
you are pushing into listeDevices a pointer to stack array. There are two problems with this - mayor one is that once your getDevicesName function ends, those pointers are invalid and use of them is Undefined, the other is that in each iteration of your loop you overwrite pcDevName and also your stored pointer content.
What you should do is to make listeDevices store std::string, ie. std::vector<std::string>, and then you can use listeDevices.push_back((char*) pcDevName); to safely store your names in a vector.
I have following code:
#include <stdio.h> // For printf()
#include <sys/stat.h> // For struct stat and stat()
struct stat stResult;
if(stat("Filename.txt", &stResult) == 0)
{
// We have File Attributes
// stResult.st_size is the size in bytes (I believe)
// It also contains some other information you can lookup if you feel like it
printf("Filesize: %i", stResult.st_size);
}
else
{
// We couldn't open the file
printf("Couldn't get file attributes...");
}
Now. How can I pass my own string through stat()? Like this
string myStr = "MyFile.txt";
stat(myStr, &stResult)
If you are talking about a C++ std::string, you might want to use
string myStr = "MyFile.txt";
stat(myStr.c_str(), &stResult)
so use the c_str() member-function of your string object in order to get a C string representation.
Use the c_str() member function.
myStr.c_str()
http://www.cplusplus.com/reference/string/string/c_str/