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;
}
Related
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;
}
I have:
vector<string> myVector = {0};
myVector.push_back("first");
myVector.push_back("second");
char *list[] = ????
I want it to be initialized like if I was doing this
char *list[] = { "first", "second", NULL };
I know I can start allocating memory based on the size and of the vector and the size of the longest string in the vector (list[v.size()+1][longest_string_in_vector]) but I wanted to see I'm not thinking of something that might be easier/faster.
If the legacy code requires a char **, then to create a variable list, you can create a vector as you initially are doing in your question.
After that, create a std::vector<char *>, where the pointers are pointers within the vector for each item. Of course, you have to ensure that the vector doesn't go out of scope or is resized. It has to be fully "set up" before creating the std::vector<char *>.
In addition, since you are certain that the legacy function does not attempt to alter the strings sent to it, we should take away the "constness" of the strings.
#include <vector>
#include <string>
#include <iostream>
void legacy_function(char **myList)
{
for (int i = 0; myList[i]; ++i)
std::cout << myList[i] << "\n";
}
using namespace std;
int main()
{
vector<string> myVector;
myVector.push_back("first");
myVector.push_back("second");
//...
// create the pointer vector
vector<char *> myPtrVector;
// add pointer to string to vector
for (size_t i = 0; i < myVector.size(); ++i)
myPtrVector.push_back(const_cast<char*>(myVector[i].c_str()));
// stick the null at the end
myPtrVector.push_back(NULL);
// ...
// call legacy function
legacy_function(&myPtrVector[0]);
}
Basically, we created the strings in a vector, and created another vector that stores pointers to the strings.
Note that the function legacy_function takes a char **, and all we need to do is pass it the address of the first element in our pointer vector.
Live Example: http://ideone.com/77oNns
Edit: Rather than having the code strewn in different areas of your program, a better approach in terms of code organization is to encapsulate the creation of the array:
#include <vector>
#include <string>
class CharPtrPtr
{
std::vector<std::string> m_args;
std::vector<char *> m_argsptr;
public:
void add(const std::string& s) { m_args.push_back(s); }
char ** create_argsPtr()
{
m_argsptr.clear();
for (size_t i = 0; i < m_args.size(); ++i)
m_argsptr.push_back(const_cast<char*>(m_args[i].c_str()));
m_argsptr.push_back(NULL);
return &m_argsptr[0];
}
char **get_argsPtr() { return m_argsptr.empty()?NULL:&m_argsptr[0]; }
void clear_args() { m_args.clear(); m_argsptr.clear(); }
};
#include <iostream>
void legacy_function(char **myList)
{
for (int i = 0; myList[i]; ++i)
std::cout << myList[i] << "\n";
}
int main()
{
CharPtrPtr args;
args.add("first");
args.add("second");
legacy_function(args.create_argsPtr());
}
Live Example: http://coliru.stacked-crooked.com/a/834afa665f054a1f
I tried these two ways,
1.Initialize manually
char *list[] = { (char*)&myVector[0][0], (char*)&myVector[1][0] };
2.Initialize in a loop
char **list2 = new char*[ myVector.size() ];
for ( unsigned int i = 0; i < myVector.size(); ++i ) {
list2[ i ] = (char*)&myVector[ i ][0];
}
However these lists only have pointers to the each string in the vector and don't actually have a copy. If you change the strings, you'll see the changes from the lists. But if you empty the vector then the lists will have a dangling pointer.
3.If you want a copy of the strings then,
char **list = new char*[ myVector.size() ];
for ( unsigned int i = 0; i < myVector.size(); ++i ) {
list[ i ] = new char[myVector[i].size()+1];
strcpy( list[ i ], &myVector[i][0] );
}
I wouldn't write this code but, there you go..
What I need is to modify pTab array inside modifyAA(int a) function.
How can I achieve this?
Example Code:
int modifyAA(int a);
int main()
{
*pTab=new int[10]; int a=13;
for(int i=0;i<=9;i++)
pTab[i]=88;
modifyAA(a);
//I'd like to have pTab to be modified after function invoke
return 0;
}
modifyAA(int a){
for(int i=0;i<=9;i++)
pTab[i]=pTab[i]+1;
a=a+pTab[0];
return a;
};
Is it possible to modify array when function doesn't take it as parameter ?
You can use a global variable for the pointer to the first element of the dynamic array:
int * pTab;
int printAA(int a)
{
for (unsigned int i = 0 i != 10; ++i)
{
++pTab[i];
}
return a + pTab[0];
}
int main()
{
pTab = new int[10];
// populate
printAA(13);
}
You could use global variables. This could be practical especially if several functions like printAA() would need to call it.
However there is a risk of using *pTab before it's allocated. And also, you remember now the size, but if later you'd change the size to 10, you would have to find back all the places where you've hardcoded the 10 or the 9.
If the goal of not passing the parameter is mainly because you call the function a lot of times you could opt for a std::bind, creating a kind of dynamic function:
#include <iostream>
#include <functional>
int printDynArr(int* dynarr, size_t sz, int a) // proper function with all parameters
{
for (size_t i = 0; i < sz; i++)
dynarr[i]++; // It's a pointer, so you modify the data where it is stored
a += dynarr[0];
return a;
};
int main()
{
int *pTab = new int[10]; int a = 13; //declaring and alocating - dynamic array
auto printAA = std::bind<int>(printDynArr, pTab, 10, std::placeholders::_1); // dynamic function shortcut with predefind parameters
...
printAA(a); //using function without giving pTab as argument.
std::cin.get();
return 0;
}
If you were to do this "The C++ way", you could use a vector and iterators from stdlib, like so:
#include <vector>
typedef std::vector<int> PTab; // Defines a type for your pTab, it's a vector of integers
int printAA(PTab::iterator from, PTab::iterator until, int a); //declaring some func
int main()
{
PTab pTab(10, 88); // Initializes pTab vector to 10 elements all containing 88
int a = 0;
printAA(pTab.begin(), pTab.begin() + 10, a);
return 0;
}
int printAA(PTab::iterator from, PTab::iterator until, int a)
{
for (PTab::iterator i = from; i != until; ++i)
{
*i++; // Increments current element by 1
}
a += *from; // Adds the value of the from element to a
return a;
};
This way you don't pass the vector itself to the function, instead, you only pass a range of iterators, which gives the function a possibility to access the contents of the vector, but not to modify the vector object itself (ie. clear it, resize it, etc.).
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).
Changed completely due to suggestions from other member. Most problems solved, still having problems. Now won't output any names from the array in main. Not sure if I'm passing them back correctly from function.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
void bubblesort(string[], const int);
int sub = 0;
int main()
{
const int maxsize = 100;
string friendArray[maxsize];
ifstream friends;
friends.open("myFriends.dat");
while (sub < maxsize)
{
getline(friends, friendArray[sub]);
sub++;
}
bubblesort(friendArray, maxsize);
cout<<friendArray[0]<<" "<<friendArray[1]<<" "<<friendArray[2];
system("pause");
return 0;
}
void bubblesort(string *array, const int size)
{
bool swap;
string temp;
do
{
swap = false;
for (int count = 1; count < (size - 1); count++)
{
if(array[count-1] >array[count])
{
temp = array[count-1];
array[count-1] = array[count];
array[count] = temp;
swap = true;
}
}
}
while(swap);
}
Your problem isn't necessarily that temp inside bubblesort is not a char, the problem is that array is declared as a string and not a string[].
The reason you're getting the error is because array[count+1] is of type char, and temp is of type string. std::swap expects two elements of the same type.
However, that may be the least of your problems, your code doesn't compile for quite a few reasons. Not just that but you're passing in maxsize to bubblesort at each iteration. There's a flaw in both your logic and your syntax.
EDIT: Since you're still having trouble getting the sorting to work, here's a working modification of your code:
#include <iostream>
void bubblesort(std::string array[], size_t size)
{
bool bSwapped;
std::string temp;
do
{
bSwapped = false;
for (size_t count = 1; count < size; count++)
{
if(array[count-1] > array[count])
{
std::swap(array[count-1], array[count]);
bSwapped = true;
}
}
}
while(bSwapped);
}
int main(void)
{
std::string array[] = { "def", "ghk", "abc", "world", "hello" };
bubblesort(array, sizeof(array)/sizeof(*array));
for (size_t i = 0; i < sizeof(array)/sizeof(*array); ++i)
std::cout << array[i] + " ";
std::cout << std::endl;
return 0;
}
bubblesort could also be written as: void bubblesort(std::string *array, size_t size). There's no difference in this case since, when passed to a function, arrays decay into pointers.
Since arrays are passed by reference, a pointer to the first element, any modifications made to array inside of bubblesort will actually be modifying your array in main. So that's how arrays are "returned".
std::vector is a good alternative to the standard array, since it automatically resizes and obviously contains the length of the internal array so that you don't have to pass the size everywhere you pass an std::vector. You can also use it the same way as a regular array.
temp is a string, array[count] is a char (since an std::string is a vector of char elements.) I'm not sure what you're trying to do here, but the compiler is correct - you can't assign a char to a string.
You could change temp to be a char, since all you do with it is assign a char to it, and then assign it back to an element of array, which is also a char.
You need to declare temp as char. You can use std::swap to avoid such mistakes in the future:
std::swap(array[count], array[count+1]);
This would make your code compile, but it would not do what you're trying to do (bubblesort). The problem is that you are passing a single string (which is also an "array" of characters) instead of an array of strings, which is, in a very lose sense, "an array of arrays of characters". Your bubblesort needs to accept string *array as its first parameter.