I am trying to use a C Library, which requires that I pass in dynamically allocated c-strings for the functions to modify. However, I want to avoid using new/delete operators because I feel it is better practice to have memory management done under the hood by STL libraries, rather than by me.
Below, I'm trying to use std::string (and vectors) to solve this problem, and preallocating them before passing them to the C function. The examples with one string (CChar, CVoid) work, but I'm still unsure if this is the correct way, or even if it is a safe way (bug-free) to do it. Using vectors does not seem to work at all.
I have included the "C"-way of doing what I want to achieve for both strings and vectors.
#include <string>
#include <iostream>
#include <vector>
// ----------------------------------------------------
// Example C library Code
void CChar(char* data, int len)
{
int i;
for (i = 0; i < len; ++i)
data[i] = 'A' + (i % 26);
}
void CVoid(void* data, int len)
{
char* d = (char*)data;
int i;
for (i = 0; i < len; ++i)
d[i] = 'Z' - (i % 26);
}
void CStrings(char** strings, int count, int lengths)
{
int i, j;
for (i = 0; i < count; ++i)
for (j = 0; j < lengths; ++j)
strings[i][j] = 'A' + ((i * j + i) % 26);
}
// ----------------------------------------------------
// C++ code
int main()
{
// Traditional way, using new/delete.
char* c = new char[11];
CChar(c, 10);
c[10] = '\0';
std::cout << c << std::endl; // ABCDEFGHIJ
delete [] c;
std::string s(10, '\0');
CChar(&s[0], 10);
std::cout << s << std::endl; // ABCDEFGHIJ
CVoid(&s[0], 10);
std::cout << s << std::endl; // ZYXWVUTSRQ
std::vector<std::string> v(5, std::string(10, '\0'));
// Traditional way with arrays of arrays.
char** cc = new char*[5];
for (int i = 0; i < 5; ++i)
{
cc[i] = new char[11];
cc[i][10] = '\0';
}
CStrings(cc, 5, 10);
for (int i = 0; i < 5; ++i)
{
std::cout << cc[i] << std::endl; // AAAAAAAAAA, BCDEFGHIJK, CEGIKMOQSU, DGJMPSVYBE, EIMQUYCGKO
delete [] cc[i];
}
delete [] cc;
// Doesn't compile
// CStrings(&v[0], 5, 10);
// for (int i = 0; i < 5; ++i)
// std::cout << v[i] << std::endl;
return 0;
}
Summary: Is there a good way to use C++'s STL libraries so that I don't need to do my own resource management when trying to use C libraries.
edit: Error cleaning up array of arrays
Sure, you can just use std::vector<char> is you don't want to think about allocation. Here's how you do it:
#include <vector>
int main()
{
std::vector<char> str(100, 0); //Allocate an array of 100 chars and initialize them to 0
SomeFunction(&str[0], str.size()); //Pass the address to the array and its size
return 0;
}
For arrays of arrays, can store a vector<char*> which refers to the starts of the already dynamically allocated std::vector<std::string>.
int main()
{
std::vector<std::string> v(5, std::string(10, '\0'));
std::vector<char*> vc(5);
for (int i = 0; i < 5; ++i)
vc[i] = &(v[i])[0];
CStrings(&vc[0], 5, 10);
for (int i = 0; i < 5; ++i)
std::cout << v[i] << std::endl;
return 0;
}
Related
I am facing problems to make this piece of code work:
char **createCharArray() {
char **charArray = new char*[PARAM_COUNT];
for (int i = 0; i < PARAM_COUNT; ++i) {
charArray[i] = new char[MAXSIZE];
}
return charArray;
}
void deleteCharArray(char **charArray) {
for (int i = 0; i < PARAM_COUNT; ++i) {
delete[] charArray[i];
}
delete[] charArray;
}
int main(){
char ** test = createCharArray();
char *asd = new char[MAXSIZE];
cin >> asd;
for (int i = 0; i < PARAM_COUNT; ++i) {
strcpy_s(test[i], asd);
}
for (int i = 0; i < PARAM_COUNT; ++i) {
cout << i << " " << test[i] << endl;
}
deleteCharArray(test);
return 0;
}
How do I copy that string into the char array, where am I mistaking?
Edit: As answered by Igor Tandetnik and user17732522 in the comments and Joseph Larson in the reply below, this was solved by adding the buffer argument to the strcpy_s function, making it a total of 3 arguments.
There are a few things I find troublesome. First, you've seen people say you should use std::string instead of char arrays, and that's true. But new programmers should understand the entire language, and so understanding how to use char arrays has value.
So let's ignore C++ strings and look at your code:
char ** test = createCharArray(); // array of pointers to char arrays
char *asd = new char[MAXSIZE];
cin >> asd;
for (int i = 0; i < PARAM_COUNT; ++i) {
strcpy_s(test[i], asd);
}
for (int i = 0; i < PARAM_COUNT; ++i) {
cout << i << " " << test[i] << endl;
}
deleteCharArray(test);
return 0;
Let's start with this. We don't know what createCharArray() does. Is it doing everything it should? Not only should it create an array of char pointers, but the way you're using it, it also needs to create the buffers they each point to. So it might look something like this:
char ** createCharArray() {
char ** array = new char *[PARAM_COUNT];
for (int index = 0; index < PARAM_COUNT; ++index) {
array[index] = new char[MAXSIZE];
}
return array;
}
If yours looks remarkably different, you may have issues.
After that, let's look at this:
for (int i = 0; i < PARAM_COUNT; ++i) {
strcpy_s(test[i], asd);
}
As others have said, this version of strcpy_s takes three arguments:
strcpy_s(test[i], asd, MAXSIZE);
Note that you're copying the same string into place multiple times. I wonder if your code should really do this:
for (int i = 0; i < PARAM_COUNT; ++i) {
cin >> asd;
strcpy_s(test[i], asd, MAXSIZE);
}
And finally, the delete method needs to delete the individual pointers and then the array of pointers.
Bellow is a simple program that works fine. It contains a function that is able to return a string of arbitrary size. The size of which is determined by the function input.
#include <iostream>
using namespace std;
string strFunc(int a){
string toBeReturned;
for(int i=0; i < a; i++){
toBeReturned += '!';
}
return toBeReturned;
}
int main(){
int x = 5;
cout << strFunc(x) << endl;
return 0;
}
If instead I wanted a function (or a single process to call in main) to return a 1-D array (int toBeReturned[size to be determined]) I had to use a function that returns a pointer and then include that function in a macro that constructs the array.
Is there a simpler way of doing this in c++?
If not can someone please explain why this only works for type string? I thought that a string is simply a 1-D array of type 'char'.
Thank you,
Daniel
A function can return any POD or class type by value.
A C++-style std::array is a fixed-sized array wrapped in a class type, and thus can be returned by value. However, a C-style fixed-sized array cannot be returned by value (but it can be stored as a member of a class type, which can then be returned by value, like std::array does).
A C-style array can't be sized dynamically (without using a non-standard compiler extension), which is why you would have to new[] it, return it by pointer, and then delete[] it when you are done using it.
Since you want your function to return a dynamic-sized array, you should use std::vector instead of a new[]'ed pointer, eg:
#include <iostream>
#include <vector>
using namespace std;
vector<int> strFunc(int a){
vector<int> toBeReturned(a);
for(size_t i = 0; i < a; ++i){
toBeReturned[i] = ...;
}
return toBeReturned;
}
int main(){
int x = 5;
vector<int> returned = strFunc(x);
for(size_t i = 0; i < x; ++i){
cout << returned[i] << ' ' << endl;
}
return 0;
}
You can use a vector of whatever type you need, and pass it into your function by reference.
#include <vector>
#include <chrono>
#include <iostream>
using namespace std;
void by_reference(vector<size_t>& v, size_t s)
{
v.clear();
v.resize(s, 0);
for (size_t i = 0; i < s; i++)
v[i] = i;
}
vector<size_t> by_return(size_t s)
{
vector<size_t> v(s, 0);
for (size_t i = 0; i < s; i++)
v[i] = i;
return v;
}
// Where s is large, by_reference is faster
// Where s is small, by_return is faster
// Use whichever works best for you and your situation
int main(void)
{
std::chrono::high_resolution_clock::time_point start_time, end_time;
std::chrono::duration<float, std::milli> elapsed;
start_time = std::chrono::high_resolution_clock::now();
for (size_t i = 0; i < 1000; i++)
{
vector<size_t> v;
const size_t s = 10000000;
by_reference(v, s);
for (size_t i = 0; i < s; i++)
v[i] = i;
}
end_time = std::chrono::high_resolution_clock::now();
elapsed = end_time - start_time;
cout << "Duration: " << elapsed.count() / 1000.0f << " seconds" << endl;
start_time = std::chrono::high_resolution_clock::now();
for (size_t i = 0; i < 1000; i++)
{
const size_t s = 10000000;
vector<size_t> v = by_return(s);
for (size_t i = 0; i < s; i++)
v[i] = i;
}
end_time = std::chrono::high_resolution_clock::now();
elapsed = end_time - start_time;
cout << "Duration: " << elapsed.count() / 1000.0f << " seconds" << endl;
return 0;
}
For starters, total C++ and coding noob here, apologies in advance. I've been working on a program that creates a concordance of a text file with the number of times a word occurs and on what lines the word occurs on. Brief example of the intended output:
A occurs 9 time(s) on lines 1 3 5
AND occurs 3 time(s) on lines 2 4
I first wrote the program using only arrays, which I've got running successfully. I'm now trying to rewrite it using vectors instead of arrays, and basically I have no idea what I'm doing past declaring the vectors. I've got my vector version to compile and link without errors, but when I run it I get a "segmentation fault 11" error. From what I understand, the reason this error is occurring because I'm trying to access memory that hasn't been allocated yet. I'm pasting my entire code that I've written so far below. If someone can help me out, or point me in the right director of what I need to do to make this happen, that'd be so awesome. I know I'll need to push the push_back method, but I just have no idea where. I realize this probably rudimentary to most of you, but I'm just trying to wrap my head around all of this. Again, thanks so much -
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
void copy(vector<int> fromarr, vector< vector<int> > toarr, int index)
{
for (int i = 0; i <= fromarr[0]; i++)
{
toarr[index][i] = fromarr[i];
}
}
void copy(vector< vector<int> > fromarr, vector<int> toarr, int index)
{
for (int i = 0; i <= fromarr[index][0]; i++)
{
toarr[i] = fromarr[index][i];
}
}
int search(vector<string> array, int len, string target)
{
for(int i = 0; i < len; i++)
{
if(array[i] == target) return i;
}
return -1;
}
void sort(vector<string> wordarray, vector<int> linecount, vector< vector<int> > linenumbersarray, int length)
{
int minpos = 0;
for(int i = 0; i < length; i++)
{
minpos = i;
for (int j = 0; j < length; j++)
{
if(wordarray[j] > wordarray[minpos]) minpos = j;
string tempword = wordarray[i];
int tempcount = linecount[i];
vector<int> tempnums;
copy(linenumbersarray, tempnums, i);
wordarray[i] = wordarray[minpos];
linecount[i] = linecount[minpos];
copy(linenumbersarray[minpos], linenumbersarray, i);
wordarray[minpos] = tempword;
linecount[minpos] = tempcount;
copy(tempnums, linenumbersarray, minpos);
}
}
}
int main(int argc, char* argv[])
{
vector<string> wordarray;
vector<int> linecount;
vector< vector<int> > linenumbersarray;
int arrayposition = 0;
int linenumber = 1;
int wordlength = 0;
ifstream infile;
infile.open(argv[1]);
string aline;
while (getline(infile, aline))
{
istringstream theline(aline);
string aword;
while (theline >> aword)
{
int isupdated = search(wordarray, wordlength, aword);
if (isupdated == -1)
{
wordarray[wordlength] = aword;
linecount[wordlength] = 1;
linenumbersarray[wordlength][0] = 1;
linenumbersarray[wordlength][1] = linenumber;
wordlength = wordlength + 1;
}
else
{
linecount[isupdated] = linecount[isupdated] + 1;
if (linenumbersarray[isupdated][linenumbersarray[isupdated][0]] != linenumber)
(linenumbersarray[isupdated][++linenumbersarray[isupdated][0]] = linenumber);
}
}
linenumber = linenumber + 1;
}
sort(wordarray, linecount, linenumbersarray, wordlength);
for (int i = 0; i < wordlength; i++)
{
ostringstream out;
for (int j = 1; j <= linenumbersarray[i][0]; j++)
{
out << linenumbersarray[i][j];
j != linenumbersarray[i][0] ? out << " " : out << ".";
}
cout << wordarray[i] << " occurs " << linecount[i] << " time(s) on lines " << out.str() << endl;
out.flush();
}
}
How do you populate your vectors? Use push_back function to fill them in.
vector<int> v; // an empty container
v.push_back(10); // now it has one element - an integer 10
Use size() function to access a vector size, do not pass length parameter as you do in few functions (sort, search).
Another way to iterate through an stl container (vector is a container) is to use iterators.
for (vector<int>::iterator it = v.begin(); it != v.end(); ++it)
{ int a = *it; /*gives you an element of the container*/ }
Using size or iterators will prevent you from accessing unallocated memory - this is your problem.
Do not use operator [] without checking vector boundary.
if (i < v.size()) {v[i]; //an element}
Here are two variants of your search function
int search(vector<string> const &array, string const &target)
{
for(int i = 0; i < array.size(); i++)
{
if(array[i] == target) return i;
}
return -1;
}
vector<string>::const_iterator search(vector<string> const &array, string const &target)
{
for(vector<string>::const_iterator it = array.begin(); it != array.end(); ++it)
{
if(*it == target) return it;
}
return array.end();
}
A better way of searching is to use std::find function, but you may leave that for later when you are more comfortable with STL. std::find does the same as second variant of search above.
vector<string>::iterator it;
it = find (myvector.begin(), myvector.end(), target);
if (it != myvector.end())
std::cout << "Element found in myvector: " << *it << '\n';
else
std::cout << "Element not found in myvector\n";
So i would like to know how to save characters in a char array. something like this.
int const l=100;
char a[l];
char b[l]
cin.getline(a,l);
int d;
d=strlen (a);
int i=0;
for(i=0;i<d;i++)
{
if(a[i]=='a')
{do something so i can save only the items that match the
criteria in the new char array}
I don't know if there is a function to do this or even how i should approach it .
First of all, if you really write in C++, avoid arrays. They are tougher to handle than objects really created for array or string handling, such as std::string.
Try this one:
#include <string>
#include <iostream>
int main(int argc, char * argv[])
{
std::string s, s1;
std::getline(std::cin, s);
for (int i = 0; i < s.length(); i++)
{
if (s[i] == 'a')
s1.push_back(s[i]);
}
std::cout << "Processed string: " << s1;
}
This may help if you don't use STL:
int j = 0; // index for b. An array will be filled from the zero element
for (int i = 0; i < d; i++)
{
if (a[i] == 'a') // or any filter criter
{
b[j] = a[i];
++j;
}
}
b[j] = '\0';
With STL (and C++11):
auto it = std::copy_if(&a[0], &a[d], &b[0], [](char c){ return c == 'a'; });
*it = '\0';
I'm pretty new to C++ and I have some problems with getting into all that pointer stuff. Basically I am passing a pointer to a Function, creating an Array at that pointer. Back in the main function I can't access this array.
Here's my code:
#include <iostream>
using namespace std;
void createArray(char** dict, int* arraysize)
{
*arraysize = 26*26*26*26;
delete dict;
dict = 0;
//Initialisiere character array of character
//char **wortliste = 0;
dict = new char*[*arraysize];
for(int i = 0; i < *arraysize; i++)
dict[i] = new char[5];
int ctr = 0;
//Erstelle Einträge (sortiert)
for (char i = 'A'; i <= 'Z'; i++)
{
for (char j = 'A'; j <= 'Z'; j++)
{
for (char k = 'A'; k <= 'Z'; k++)
{
for (char l = 'A'; l <= 'Z'; l++)
{
dict[ctr][0] = i;
dict[ctr][1] = j;
dict[ctr][2] = k;
dict[ctr][3] = l;
dict[ctr][4] = '\0';
ctr++;
}
}
}
}
}
int main(void)
{
char** dict = 0;
int arraysize;
createArray(dict, &arraysize);
cout << dict[0] << endl << dict[arraysize-1] << endl;
return 0;
}
I can't figure out my error thank you very much in advance.
In C++ parameters are pass by value (unless explicitly marked as being reference parameters), so when you pass dict, a pointer (to a pointer to char) to createArray, the dict inside your function is a different object, albeit with the same initial value, as the dict in main. If you want to see changes to dict in main you would have to pass it by reference, or pass the address of it into a function taking a char ***.
E.g.
void createArray(char**& dict, int* arraysize)
or
void createArray(char*** pdict, int* arraysize)
{ // use (*pdict) instead of dict ...
and
// ...
createArray(&dict, &arraysize);
A more "C++" way to achieve what you want would be to have:
void createArray( std::vector<std::string>& dict );
and to simply have createArray resize the vector to the required size. Using standard containers like vector and string also frees you of the obligation to explicity deallocate that memory that you allocate which is currently missing from your code.
There are a couple of mistakes.
To delete an array:
char **array = /* new with whatever */;
/* do your work */
for (i = 0; i < array_size; ++i)
delete[] array[i];
delete[] array;
To new an array:
char **array = new char *[array_size];
for (i = 0; i < array_size; ++i)
array[i] = new char[array_size_2];
When deleteing, to make sure you don't iterate over a not-newed array, check it against NULL:
for (i = 0; i < array_size; ++i)
{
if (array[i] != NULL) /* Or simply if (array[i]) */
delete[] array[i];
array[i] = NULL;
}
if (array != NULL)
delete[] array;
array = NULL;
alternatively, since delete makes a check for NULL anyway, you can simplify this to:
if (array != NULL)
for (i = 0; i < array_size; ++i)
delete[] array[i]; /* no need to set to NULL after if going to delete the array */
delete[] array;
array = NULL;
Note: delete deletes a single object while delete[] deletes an array.
I can't imagine what you would do with such data, but you can at least use modern techniques.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
vector<string> create() {
vector<string> result;
for (char i = 'A'; i <= 'Z'; ++i) {
for (char j = 'A'; j <= 'Z'; ++j) {
for (char k = 'A'; k <= 'Z'; ++k) {
for (char l = 'A'; l <= 'Z'; ++l) {
result.push_back(string() + i + j + k + l);
}
}
}
}
return result;
}
int main() {
vector<string> data = create();
cout << data.front() << endl << data.back() << endl;
}