array pointer's vector c++ - c++

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.

Related

How to check char array contain any char without loop in C++?

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.

How to create a vector around a buffer?

I have a code which is similar to the following:
myLibFunc(std::vector<char > &data)
{
// dosomthing with data
}
myFunc(char *buffer,int bufferSize)
{
std::vector<char > mydata(buffer,buffer+bufferSize);
myLibFunc(mydata);
}
The code works, but the vector allocates memory for itself and not using a memory that is already available.
How can I change the code in such a way that the vector uses the memory that already available and not allocating an extra memory?
Note that I can not change the signature of functions.
Update
I have two functions:
In one of them, I receive a buffer and I need to manipulate the memory and pass it to the next function as a vector. The function that I am trying to implement is part of an interface so I can not change it. Another function is a library that I need to call, so I can not change the signature of functions.
The problem is that the above code allocates new memory and copies the data from the buffer to it which is not optimal.
std::vector is designed to exclusively own the data it holds so doing the memory copy is the only safe way for std::vector to work. That leaves only unsafe hacks. If we can assume the function does not change the vector size, you can abuse std::vector. In my compiler (tested on g++4.8 and cpp.sh) std::vector is implemented as three pointers (to begin data, end used data and end alloc) therefore I can abuse the vector as:
#include <vector>
#include <iostream>
void myLibFunc( std::vector< char > & a )
{
for( char c : a )
{
std::cout << '[' << c << ']';
}
a[0] = 'B'
std::cout << '\n';
}
void myFunc(char *buffer,int bufferSize)
{
std::vector<char > mydata;
// cast to alterable pointers, cast should also keep
// mydata in scope until after the last assignment.
char ** abuser = (char**)&mydata;
// save old values and substitute new values
char *tmp0 = abuser[0];
abuser[0] = buffer;
char *tmp1 = abuser[1];
abuser[1] = buffer+bufferSize;
char *tmp2 = abuser[2];
abuser[2] = buffer+bufferSize;
myLibFunc(mydata);
// return old values to avoid crash when mydata goes out of scope.
abuser[0] = tmp0;
abuser[1] = tmp1;
abuser[2] = tmp2;
}
int main()
{
char p[] = "Hello World";
myFunc( &p[0] + 2, 5 );
std::cout << p << '\n';
return 0;
}
Note this abuse is likely to be non-portable and lead to unexplained crashes.
If you can not change the signature of your function it is not possible without the copy.
But a better way is to think about your interface. If you build myLibFunc on random access iterators, your problem is solved:
template <class CharRandomAccessIterator>
myLibFunc(CharRandomAccessIterator& begin, CharRandomAccessIterator& end )
{
// dosomthing with data
size = end - begin;
begin[xyz]; // access elements
}
myFunc(char *buffer,int bufferSize)
{
std::vector<char > mydata(buffer,buffer+bufferSize);
myLibFunc(mydata.begin(), mydata.end()); // This will work
myLibFunc(buffer, buffer+size); // This will work too
}

Vector iterator is not dereferencable, while try to read from file

I'm writing data (structure) into file using vector, and when I attempt to retrieve data using vector iterator and it gives me: "Vector iterator is not dereferenceable."
This is my code:
void CProgram_1_STLDlg::OnBnClickedBtnView()
{
// TODO: Add your control notification handler code here
CFile file;
CFileException e;
studentVector::iterator sit;
studentVector::iterator sBegin = sVector.begin();
studentVector::iterator sEnd = sVector.end();
CString path = _T("D:\\Student.txt");
if ( file.Open(path, CFile::modeRead, &e) ) {
while ( file.Read( (char *)&sVector, sizeof(sVector)) ) {
AfxMessageBox(_T("File opened in read mode."), MB_ICONINFORMATION);
AfxMessageBox(_T("ID:\t")+sit->id+L"\nName:\t"
+sit->name+L"\nMarks:\t"+sit->marks+L
"\nPercentage:\t"+sit->per+L"\nState:\t"+sit->state);
sit++;
}
//file.Read( (char *)&sData, sizeof(sData));
/*for ( sIterator = sVector.begin(); sIterator != sVector.end(); sIterator++ ) {
//AfxMessageBox(_T("ID:\t")+sIterator->id+L
"\nName:\t"+sIterator->name+L"\nMarks:\t"
+sIterator->marks+L"\nPercentage:\t"+sIterator->per+L
"\nState:\t"+sIterator->state);
//AfxMessageBox(_T("Hello..Testing...!"));
}
*/
} else {
AfxMessageBox(_T("Error! Unable to open file."), MB_ICONERROR);
}
}
Now I don't know how to resolve this error.
Note: Some of links I refer which google gave me, but I couldn't able to solve my problem.
You cannot simply overwrite the memory of a vector. That is pretty much guaranteed to corrupt your process.
Furthermore, you never assign anything to sit and yet expect it to contain something sensible.
You need to parse the data in Student.txt and use vector's member functions to fill it with sensible data. The assignment will probably tell you what the file looks like so that you can parse it.
A simple vector like
vector<char> cvec
could be overwritten
so something like
vector<char> cvec;
cvec.resize(100);
for(char i=0;i<100;i++)
cvec[i]=i;
will work.
If you resize to correct size. Otherwise you will corrupt memory
sizeof(sVector) will deliver the size of the vector class.
this is not related to the data since data inside the vector class is nothing more than a pointer.
example:
class simpleVector;
{
public:
simpleVector(unigned int size)
{
p=new int[size];
}
int* p;
}
func()
{
simpleVector v1(10);
simpleVector v2(100000);
printf("size v1= %d, Size v2= %d", sizeof(v1),sizeog(v2));
}
I have not checked, what sizeof will deliver for this class, but it definitely will be constant. Independent from the size that is given to constructor
An Iterator is an accessor to the Vector
but it needs to be initialized.
In the code above sit is not assigned to something. So you are not able to access something valid.
from the code line
AfxMessageBox(_T("ID:\t")+sit->id+L"\nName:\t"+sit->name+L"\nMarks:\t"+sit->marks+L"\nPercentage:\t"+sit->per+L"\nState:\t"+sit->state);
I see the vector shall contain a complex data type build from several strings.
so a vector element probably looks like
class student
{
std::string id;
std::string name;
std::string marks;
std::string per;
std::string state;
};
this is in minimum the information hold by each vector element.
usually strings have the property to have different length.
While id might be always of same length name probably don't.
Since it is not fixed length
even
file.Read( (char *)&sVector, sizeof(student))
would not work.
so I would suggest to add a reader to the 'Student' Class:
class student
{
std::string id;
std::string name;
std::string marks;
std::string per;
std::string state;
bool ReadElemFromFile(CFile& file)
{
id=ReadStringFromFile(file);
name=ReadStringFromFile(file);
marks=ReadStringFromFile(file);
per=ReadStringFromFile(file);
state=ReadStringFromFile(file);
if(id.empty()||name.empty()||marks.empty()||per.empty()||state.empty())
return false;
return true;
}
std::string ReadStringFromFile(CFile% file)
{
char c;
std::string s;
do
{
file.read(&c,1);
s+=c;
}
while(c!='\0')
return s;
}
};
I know reading that way is not the most performant way to do it, but it shows,that the string terminator stored to file indicates the length of each string
now back to your code
void CProgram_1_STLDlg::OnBnClickedBtnView()
{
// TODO: Add your control notification handler code here
CFile file;
CFileException e;
student* sit=new Student;
studentVector.clear();
CString path = _T("D:\\Student.txt");
if ( file.Open(path, CFile::modeRead, &e) ) {
while ( sit->ReadElemFromFile(CFile& file)) {
AfxMessageBox(_T("File opened in read mode."), MB_ICONINFORMATION);
AfxMessageBox(_T("ID:\t")+sit->id+L"\nName:\t"+sit->name+L"\nMarks:\t"+sit->marks+L"\nPercentage:\t"+sit->per+L"\nState:\t"+sit->state);
studentVector.push_back(*sit);
}
} else {
AfxMessageBox(_T("Error! Unable to open file."), MB_ICONERROR);
}
delete stud;
}
..."attempt to retrieve data using vector iterator and it gives me Vector iterator is not dereferenceable"...
Iterators are pointer-like objects, however unlike raw pointers, they prevent dereferencing (accessing of the value they point to) if they are "dangling".
In your case iterator sit is not initialized, not as, for example iterator sBegin = sVector.begin();, that is assigned to point to the beginning of the vector sVector.
Thus when you try to access an iterator that does not point to a valid value, you get an error.
In addition to that, to store an element to a vector you should use its member functions, not passing its address, as you do in your while loop.

End process error code -1 if acess to string field of structure

#include <cstdlib>
#include <string>
#include <iostream>
#define S 10
using namespace std;
struct List
{
string name;
bool male;
int year;
string addr;
string diag;
bool hosp;
};
main()
{
struct List *l=NULL;
int n=0;
for(int i=0;i<10000;i++)
{
if(!(n%S))
{
l=(List*)realloc(l,(n/S+1)*S*sizeof(struct List));
cout<<"realloc ok\n";
};
l[n].male=rand()%2;
l[n].year=1900+rand()%100;
l[n].hosp=rand()%2;
//!l[n].name="abc";
n++;
cout<<l[rand()%n].male<<" "<<l[rand()%n].year<<" "<<l[rand()%n].hosp<<endl;
}
}
If l[n].name="abc" remarked then program works fine.
If i try put string value to this field the programm compiled without warnings nay, but crash with error code -1 after first realloc.
Any way to solve it?
Since your structure is non-trivial - it contains members of class type, std::string, which need to be initialised by calling their constructors - you can't simply allocate raw memory and pretend that contains a valid object.
The simplest solution is to use a type-aware dynamic array
std::vector<List> l;
which can be resized, perserving its contents, with
l.resize((n/S+1)*S);
Tip! Using "new" operator to allocate this structure will automatically create string object for each field.
List *l=new struct List[S];
It fix this issue, l[n].name="abc" will works, but it not implements reallocation functional.

Pointer to Element in Vector

I am farily new to c++ and have already read some topics about storing pointers to objects or the objects themselves in a vector.
I decided to store the objects in the vector, because I do not push_back many objects at runtime, the vector is just created once and leaved like this.
My problem now is, that I have another object that gets a vector as argument and searches for a certain object in the passed vector. If it finds this object, it stores a pointer to it, if not, the variable is set to NULL.
Eventhough I do not push_back any items, the pointer seems to point to a wrong location in other functions.
The object that searches for the element in the vector has a public function in which the pointer should be returned. It would be very slow if I search for the object at every function call, so this should not be an option.
Are there other solutions or do I have to switch to a vector of pointers?
Some code snippets:
Constructor of the object that searches the vector:
MySearch::MySearch(QVector<Obj> objVector)
:objVector(objVector) {
found = NULL
foreach(Obj o, this->objVector) {
if(..found..) {
found = &o;
break;
}
}
}
Getter function:
Obj* MySearch::getObject() {
return found;
}
The problem is because the variable o is local and will be out of scope as soon as the loop ends. If you take the address of the vector element instead of the o, it will works.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class MySearch
{
public:
MySearch(const vector<string> &items)
: items_(items)
{
// Skipping validation
found_ = &(items_[5]);
}
string *getObject() {return found_;}
private:
vector<string> items_;
string *found_;
};
int main()
{
string str = "test#";
vector<string> aux;
for (int i = 0; i < 10; ++i)
aux.push_back(str + (char)('0' + i)); // test#0 ... test#9
MySearch ms(aux);
cout << *(ms.getObject()) << endl; // test#5
return 0;
}
foreach(Obj o, this->objVector) {
if(..found..) {
found = &o;
break;
}
} // life time of o ends here.
o resides on stack and it's life-time is limited to the loop only. Having reference to it and later returning causes undefined behavior.
If you were to use BOOST_FOREACH (from the boost C++ libraries), then you could use a non-const reference to the objects in the vector. Q_FOREACH does not support non-const references:
BOOST_FOREACH(Obj& o, this->objVector) {
if(..found..) {
found = &o;
break;
}
}
Alternatively use iterators and a for loop.