Dynamically Set Array Size C++ - c++

I don't know any C++ at all but I am trying to make a very small update to a C++ library that my application is using. Before I start hacking away at this, I am hoping someone can tell me the proper syntax for the following:
I have the following lines of code:
#define A_NUMBER 100
#define ANOTHER_NUMBER 150
enum {
type1,
type2,
};
static int someMethod(int type)
{
char command[A_NUMBER];
//...more code
}
What I need to be able to do is based on the type argument (type1 or type2) I need to be able to set the size of the array to be either A_NUMBER or ANOTHER_NUMBER.
In pseudo code it would be something like:
if (type == type1) {
char command [A_NUMBER]
}
else if (type == type2) {
char command [ANOTHER_NUMBER]
}
Is there a way to dynamically define the size?

Yes, you can use an std::vector<char>:
if (type == type1) {
std::vector<char> x(A_NUMBER);
} else if (type == type2) {
std::vector<char> x(ANOTHER_NUMBER);
}
Remember to include the header with:
#include <vector>
While your example code matches the "pseudo code" in the question, I think part of the question is how to decide the size via type and then use the resulting storage unconditionally, i.e. outside the conditional blocks.
Then it gets as simple as:
std::vector<char> x;
if (type == type1) {
x.resize(A_NUMBER);
} else if (type == type2) {
x.resize(ANOTHER_NUMBER);
}

I believe this is what you want
std::vector<char> x; // x is empty, with size 0
if (type == type1) {
x.resize(A_NUMBER); // change size to A_NUMBER
} else if (type == type2) {
x.resize(ANOTHER_NUMBER); // change size to ANOTHER_NUMBER
}

Yes and no. In standard C++, you cannot keep the array on the stack and have its size determined in runtime.
However, you can turn the array into a dynamically-allocated one (i.e. on the heap). In C++, the standard way to do this is to use std::vector:
std::vector<char> command(A_NUMBER); // or ANOTHER_NUMBER
Indexing will work just as before: command[5]
However, if you need to pass the array to something which expects a C-style array (i.e. a char *), you'll have to use one of these:
command.data(); // if your compiler supports C++11
&command[0]; // if it does not
And of course, to use std::vector, you'll have to #include <vector>.

Here's an example that works in C and C++:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(int argc, char *argv[])
{
char *opt;
if(argc == 2) {
opt = *++argv;
}
else {
printf("Usage: %s [small|large]\n", *argv);
return EXIT_FAILURE;
}
int *arr;
int arrlen = 0;
if (strcmp(opt, "small") == 0) {
arrlen = 3;
arr = (int *) malloc(arrlen*sizeof(int));
int i;
for(i = 0; i < arrlen; i++)
arr[i] = i+1;
}
else if (strcmp(opt, "large") == 0) {
arrlen = 5;
arr = (int *) malloc(arrlen*sizeof(int));
int i;
for(i = 0; i < arrlen; i++)
arr[i] = i+1;
}
if (arrlen > 0) {
int i;
for(i = 0; arr[i]; i++)
printf("%i, ", arr[i]);
printf("\n");
free(arr);
}
return EXIT_SUCCESS;
}
Example:
[gyeh#gyeh stackoverflow]$ ./dynarr
Usage: ./dynarr [small|large]
[gyeh#gyeh stackoverflow]$ ./dynarr small
1, 2, 3,
[gyeh#gyeh stackoverflow]$ ./dynarr large
1, 2, 3, 4, 5,

The raw C++ way is new and delete
char * command = new char[A_NUMBER];
// and later delete it like this
delete[] command;
Of course you'll have to manage the memory, and it is not recommended to use this approach because of many reasons you should be able to find online. So in conclusion... don't use this method if vector is an option
If using a big array the best way would be to use C++ vector, you could even consider other data structures like list based on your needs (for example a lot of insert, deletions operations on your array).

Related

C++ templated function to add int at the end of an array [duplicate]

I have the following array:
int a1[] = {1,2,3,4,5,6};
I would like to know how can I append any number to the front, and to the back of this array. In JavaScript, there is unshift() and push(). Is there anything like that in C++?
In C++, arrays are a kind of type, and the array size is part of the type. Therefore, the size of an array object is part of this object's type and not modifiable at runtime.
To manage dynamic collections of objects in C++, you would usually use a container class. There are several useful containers included in the standard library; the most important one is std::vector, which manages a dynamic, contiguously stored sequence of elements — essentially a resizable array!
A JavaScript array is much closer to a C++ vector (or perhaps to a hash map) than to a C++ array.
Unlike Javascipt arrays, which are all-purposed arrays, C++ gives you few types of consecutive containers.
In your example, you demonstrated the use of built-in arrays also known as C-arrays. they are basically size-immutable arrays, and other than being a line of bytes which holds up variables value, they have no special features.
For flexible high-level arrays, use either std::vector, or the less known-but-really-awsome std::deque.
Also, get familiar with std::array which is a good subsitute for built-in arrays.
You can't do it directly, but if you like, you can write a simple code to manage it:
#include <stdlib.h>
#include<stdarg.h>
#include <iostream>
using namespace std;
typedef struct int_array
{
int *ptr;
int len;
int_array(int n_args, ...)
{
ptr = NULL;
len = 0;
va_list ap;
va_start(ap, n_args);
for (int i = 1; i <= n_args; i++) {
push(va_arg(ap, int));
}
va_end(ap);
}
int operator[](int idx) const
{
return ptr[idx];
}
void push(int value)
{
ptr = (int*)(len ? realloc(ptr, (len + 1)*sizeof(int)) : malloc(sizeof((len + 1))));
ptr[len++] = value;
}
void unshift(int value)
{
ptr = (int*)(len ? realloc(ptr, (len+1)*sizeof(int)) : malloc(sizeof(len+1)));
for (int i = len++; i > 0; i--)
{
ptr[i] = ptr[i-1];
}
ptr[0] = value;
}
}IntArray;
int main(int argc, char** argv)
{
IntArray arr(6/* initial len */, 1, 2, 3, 4, 5, 6);
arr.push(7);
arr.push(8);
arr.unshift(0);
arr.unshift(-1);
for (int i = 0; i < arr.len;i++)
{
cout << arr[i] << endl;
}
return 0;
}

Returning Array in C++ returns unaccessable elements

I am working on a project where I parse a string in to an array and then return it back to the main function. It parses fine but when I return it to the main function I can't get access to the array elements.
//This is from the Main function. It calls commaSeparatedToArray which returns the array.
for (int i = 0; i < numberOfStudents; i++) {
string * parsedToArray = mainRoster->commaSeparatedToArray(studentData[i]);
Degree degreeType = SOFTWARE;
for (int i = 0; i < 3; i++) {
if (degreeTypeStrings[i] == parsedToArray[8])
degreeType = static_cast<Degree>(i);
}
mainRoster->add(parsedToArray[0], parsedToArray[1], parsedToArray[2], parsedToArray[3], stoi(parsedToArray[4]), stoi(parsedToArray[5]), stoi(parsedToArray[6]), stoi(parsedToArray[7]), degreeType);
}
//Here is the commaSeparatedToArray function
string * roster::commaSeparatedToArray(string rowToParse) {
int currentArraySize = 0;
const int expectedArraySize = 9;
string valueArray[expectedArraySize];
int commaIndex = 0;
string remainingString = rowToParse;
while (remainingString.find(",") != string::npos) {
currentArraySize++;
if (currentArraySize <= expectedArraySize) {
commaIndex = static_cast<int>(remainingString.find(","));
valueArray[currentArraySize - 1] = remainingString.substr(0, commaIndex);
remainingString = remainingString.substr(commaIndex + 1, remainingString.length());
}
else {
cerr << "INVALID RECORD. Record has more values then is allowed.\n";
exit(-1);
}
}
if (currentArraySize <= expectedArraySize) {
currentArraySize++;
commaIndex = static_cast<int>(remainingString.find(","));
valueArray[currentArraySize - 1] = remainingString.substr(0, commaIndex);
remainingString = remainingString.substr(commaIndex + 1, remainingString.length());
}
if (currentArraySize < valueArray->size()) {
cerr << "INVALID RECORD. Record has fewer values then is allowed.\n";
exit(-1);
}
return valueArray;
}
1) You can't return arrays in C++. Your code (as I'm sure you know) returns a pointer to an array. That's an important difference.
2) The array is declared locally in the function and therefore no longer exists after the function has exitted.
3) Therefore once you have returned from the function you have a pointer to something which no longer exists. Bad news.
4) You must always consider the lifetime of objects when you program C++. One solution to this problem is to dynamically allocate the array (using new[]). This means that the array will still exist when you exit the function. But it has the signifcant disavantage that you must remember to delete[] the array at a suitable later time.
5) The best solution (in general) is to use a std::vector. Unlike an array a std::vector can be returned from a function. So this option leads to the simplest, most natural code.
vector<string> roster::commaSeparatedToArray(string rowToParse) {
...
vector<string> valueArray(expectedArraySize);
...
return valueArray;
}
Since your array/vector is constant size, you could also use a std::array
array<string, expectedArraySize> valueArray;
To complete the answer that John has already given, I made some example code to show you, how such function could look like.
Parsing, or tokenizing can be easily done with the std::sregex_token_iterator. That is one of the purposes for this iterator. You can see the simplicity of the usage below.
In the function we define a vector af string and use its range constructor to do the whole tokenizing.
Then we make a sanity check and return the data.
Please see:
#include <string>
#include <regex>
#include <iterator>
#include <vector>
#include <algorithm>
#include <iostream>
const std::regex separator(",");
constexpr size_t ExpectedColumnSize = 9;
std::vector<std::string> commaSeparatedToArray(std::string rowToParse)
{
// Parse row into substrings
std::vector<std::string> columns{
std::sregex_token_iterator(rowToParse.begin(),rowToParse.end(),separator ,-1),
std::sregex_token_iterator() };
// Check number of columns
if (columns.size() != ExpectedColumnSize) {
std::cerr << "Error. Unexpected number of columns in record\n";
}
return columns;
}
// test code
int main()
{
// Define test data
std::string testInputData{ "1,2,3,4,5,6,7,8,9" };
// Get the result from the parser
std::vector<std::string> parsedElements{ commaSeparatedToArray(testInputData) };
// show the result on the console
std::copy(parsedElements.begin(), parsedElements.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
return 0;
}

C++: Append to front, add to back array of int's

I have the following array:
int a1[] = {1,2,3,4,5,6};
I would like to know how can I append any number to the front, and to the back of this array. In JavaScript, there is unshift() and push(). Is there anything like that in C++?
In C++, arrays are a kind of type, and the array size is part of the type. Therefore, the size of an array object is part of this object's type and not modifiable at runtime.
To manage dynamic collections of objects in C++, you would usually use a container class. There are several useful containers included in the standard library; the most important one is std::vector, which manages a dynamic, contiguously stored sequence of elements — essentially a resizable array!
A JavaScript array is much closer to a C++ vector (or perhaps to a hash map) than to a C++ array.
Unlike Javascipt arrays, which are all-purposed arrays, C++ gives you few types of consecutive containers.
In your example, you demonstrated the use of built-in arrays also known as C-arrays. they are basically size-immutable arrays, and other than being a line of bytes which holds up variables value, they have no special features.
For flexible high-level arrays, use either std::vector, or the less known-but-really-awsome std::deque.
Also, get familiar with std::array which is a good subsitute for built-in arrays.
You can't do it directly, but if you like, you can write a simple code to manage it:
#include <stdlib.h>
#include<stdarg.h>
#include <iostream>
using namespace std;
typedef struct int_array
{
int *ptr;
int len;
int_array(int n_args, ...)
{
ptr = NULL;
len = 0;
va_list ap;
va_start(ap, n_args);
for (int i = 1; i <= n_args; i++) {
push(va_arg(ap, int));
}
va_end(ap);
}
int operator[](int idx) const
{
return ptr[idx];
}
void push(int value)
{
ptr = (int*)(len ? realloc(ptr, (len + 1)*sizeof(int)) : malloc(sizeof((len + 1))));
ptr[len++] = value;
}
void unshift(int value)
{
ptr = (int*)(len ? realloc(ptr, (len+1)*sizeof(int)) : malloc(sizeof(len+1)));
for (int i = len++; i > 0; i--)
{
ptr[i] = ptr[i-1];
}
ptr[0] = value;
}
}IntArray;
int main(int argc, char** argv)
{
IntArray arr(6/* initial len */, 1, 2, 3, 4, 5, 6);
arr.push(7);
arr.push(8);
arr.unshift(0);
arr.unshift(-1);
for (int i = 0; i < arr.len;i++)
{
cout << arr[i] << endl;
}
return 0;
}

How to stop looping through array when index is empty?

If I have an array of size MAX_SIZE and only have 20 index occupied how do you make it so that it stops printing 0s after itemList[20]? (I am reading in from a text file)
const int MAX_SIZE = 1000;
item itemList[MAX_SIZE];
for(int i= 0; i<MAX_SIZE;i++)
{
itemList[i].Print(); //prints members in item
if(i==19) // I used this just to see what I was printing properly
{ //I know it is bad practice so I would like an alternative.
break; //Also, it is only possible if you have access to the text file.
}
}
You can perform a basic check:
if(itemList[i].Function() == 0) break;
As an alternative to break, you can use a while loop:
int i = 0;
while (itemList[i] != 0 && i < MAX_SIZE)
{
itemList[i].Print();
i++;
}
Replace itemList[i] != 0 with whatever expression you're using to determine whether the element is occupied or not.
Alternatively, keep track of how many elements there are as you build up the array from the file, and only loop that many times.
Better still, remember that you're using C++, not C. Add elements from the file to a container such as std::vector instead of a raw array, then just loop through the whole thing. This also fixes a serious bug in your code; namely, that you will have undefined behaviour when there are more than 1000 entries in the file.
const int MAX_SIZE = 1000;
item itemList[MAX_SIZE];
for (int i = 0; i < sizeof(aitemList / sizeof(*itemList)); i++)
{
if (itemList[i] != 0)
itemList[i].Print();
}
or use a vector
std::vector<int> itemList;
for (int i = 0; i < itemList.size(); i++)
{
if (itemList[i] != 0)
{
// do stuff
}
}
A short lesson in:
correctly iterating through a null-terminated pointer array
cleaning up arrays of pointers in an exception safe way
solving your problem correctly
.
#include <iostream>
#include <algorithm>
#include <memory>
using namespace std;
struct Oper {
void exec() const { cout << "Hello\n"; }
~Oper() { cout << "deleted\n"; }
};
int main()
{
Oper* myArray[1000];
fill(begin(myArray), end(myArray), nullptr);
// make a sentinel to ensure that the array is cleaned up if there is an exception
std::shared_ptr<void> sentinel(&myArray, [&](void*) {
// clean up array
for (auto p = begin(myArray) ; p != end(myArray) ; ++p) {
delete *p;
}
});
myArray[0] = new Oper;
myArray[1] = new Oper;
myArray[2] = new Oper;
myArray[4] = new Oper; // note: missed 3
for(auto p = begin(myArray) ; p != end(myArray) && *p ; ++p) {
(*p)->exec();
}
return 0;
}
Output:
Compiling the source code....
$g++ -std=c++11 main.cpp -o demo -lm -pthread -lgmpxx -lgmp -lreadline 2>&1
Executing the program....
$demo
Hello
Hello
Hello
deleted
deleted
deleted
deleted
for(int i= 0; i<MAX_SIZE && i<20;i++)
it looks better because using of break is a bad pattern.

How can I return an array?

Is there any way to return an array from a function? More specifically, I've created this function:
char bin[8];
for(int i = 7; i >= 0; i--)
{
int ascii='a';
if(2^i-ascii >= 0)
{
bin[i]='1';
ascii=2^i-ascii;
}
else
{
bin[i]='0';
}
}
and I need a way to return bin[].
You can't do that but you can:
return a dynamicaly allocated array - best owned by a smart pointer so that the caller does not have to care about deallocating memory for it - you could also return something like an std::vector this way.
populate an array/vector passed to you as an argument by pointer (suggested) or a non const reference.
Your array is a local variable allocated on the stack. You should use new [] to allocate it on the heap. Then you can just say: return bin;. Beware that you will have to explicitly free it with delete [] when you are done with it.
You are really asking the wrong question. If you want to do string processing in C++, use the std::string and/or std::vector classes, not arrays of char. Your code then becomes:
vector <char> func() {
vector <char> bin(8);
for( int i = 7; i >= 0; i-- ) {
int ascii='a';
if ( 2 ^ i - ascii >= 0 ) {
bin[i] = '1';
ascii = 2^i - ascii;
}
else {
bin[i] ='0';
}
}
return bin;
}
I think your best bet is to use a vector. It can function in many ways like an array and has several upsides (length stored with type, automatic memory management).
void Calculate( std::vector<char>& bin) {
for(int i = 7; i >= 0; i--)
{
int ascii='a';
if(2^i-ascii >= 0)
{
bin.push_back('1');
ascii=2^i-ascii;
}
else
{
bin.push_back('0');
}
}
}
If you want to return a copy of the array (might make sense for small arrays) and the array has fixed size, you can enclose it in a struct;
struct ArrayWrapper {
char _bin[8];
};
ArrayWrapper func()
{
ArrayWrapper x;
// Do your stuff here using x._bin instead of plain bin
return x;
}
Or just use a std::vector as has been already suggested.
Similar implemented to #ari's answer, i want to say there is already a boost solution, boost::array solving your problem:
boost::array<char, 8> f() {
boost::array<char, 8> bin;
for(int i = 7; i >= 0; i--) {
int ascii = 'a';
if(2 ^ i-ascii >= 0) {
bin[i] = '1';
ascii = 2 ^ i-ascii;
} else {
bin[i] = '0';
}
}
}
...
boost::array<char, 8> a(f());
[I'm not sure what you want to do with that algorithm though, but note that i think you want to do 1 << i (bit-wise shift) instead of 2 ^ i which is not exponentiation in C++.]
Boost array is a normal array, just wrapped in a struct, so you lose no performance what-so-ever. It will also be available in the next C++ version as std::array, and is very easy to do yourself if you don't need the begin()/size()/data()-sugar it adds (to be a container). Just go with the most basic one:
template<typename T, size_t S>
struct array {
T t[S];
T& operator[](ptrdiff_t i) { return t[i]; }
T const& operator[](ptrdiff_t i) const { return t[i]; }
};
But as usual, use the tools already written by other people, in this case boost::array. It's also got the advantage of being an aggregate (that's why it has no user declared constructor), so it allows initializing with a brace enclosed list:
boost::array<int, 4> a = {{ 1, 2, 3, 4 }};
you need to pass array bin as an argument in your function.
array always pass by address, therefore you dont need to return any value.
it will automatically show you all changes in your main program
void FunctionAbc(char bin[], int size);
void FuncationAbc(bin, size)
{
for(int i = 7; i >= 0; i--)
{
int ascii='a';
if(2^i-ascii >= 0)
{
bin[i]='1';
ascii=2^i-ascii;
}
else
{
bin[i]='0';
}
}
}
You'll want to pass by reference, as follows:
void modifyBin(char (&bin)[8])
{
/* your function goes here and modifies bin */
}
int main()
{
char bin[8];
modifyBin(bin);
/* bin has been updated */
return 0;
}
I think that everyone else answered this one... use a container instead of an array. Here's the std::string version:
std::string foo() {
int ascii = 'a';
std::string result("00000000");
for (int i=7; i>=0; --i) {
if (2^i-ascii >= 0) {
result[i] = '1';
ascii = 2^i-ascii;
}
}
return result;
}
I'm not really sure if 2^i-ascii is want you want or not. This will be parsed as (2 ^ (i - ascii)) which is a little strange.