2D arrays as arguments - c++

I have read a book about C, and I did try, so please be soft with me.
I am trying to understand how memory really works.
I would like to have some words array like this ( in C) :
char builts[20][10]={"light","temp"}; //should it looks like this ?
Then, I would like to pass that array to a function (in another class)
//some class
char *builtinFunctions;
void Intepreter::setBuiltIns( char *builtins)
{
// here - should I save a copy to builtinFunctions ?? how ?
}
The other class need to have access to that array of words all the time.
Why this is gives error : intepreter.setBuiltIns(&builts); ?
How would one declare builtinFunctions ? as a pointer or array ? should it be copied to?
How exactly the whole thing should look like ??

There are multiple ways to pass a 2D array to a function:
The parameter is a 2D array
int array[10][10];
void passFunc(int a[][10])
{
// ...
}
passFunc(array);
The parameter is an array containing pointers
int *array[10];
for(int i = 0; i < 10; i++)
array[i] = (int*)malloc(40); //array[i] = new int[10];
void passFunc(int *a[10]) //Array containing pointers
{
// ...
}
passFunc(array);
The parameter is a pointer to a pointer
int **array;
array = (int*)malloc(40);//array = new int *[10];
for(int i = 0; i <10; i++)
array[i] = (int*)malloc(40); //array[i] = new int[10];
void passFunc(int **a)
{
// ...
}
passFunc(array);

When passing a simple array to a function, you pass it as a pointer (array name is decayed as a pointer to the first element of the array), like this :
int foo[3] = { 3, 2, 1 };
bar(foo);
So your function takes a pointer to an int as parameter :
void bar(int *data) { }
Here you have an array which contains NULL terminated string of length 10 which are arrays too. So, builts is a pointer to his first element so a pointer to an array of 10 char :
char builts[20][10] = {"light", "temp"};
char (*foo)[10] = builts; // This is valid, foo is a pointer to an array of 10 char
So, your function must take an argument of type char (*)[10], because you pass a pointer to an array of 10 char :
void bar(char (*data)[10]) { }

You can pass the 2 day array by just using its name while calling a function, like:
test_2d(builts);
You can either pass the total number of words as a separate argument, or alternatively, you can make a special word to indicate end of your array. For instance, I have used a special word "\0" to indicate that this marks the end of array. Overall the code looks like.
#include<stdio.h>
#include<string.h>
int main(void)
{
char builts[20][10]={"light","temp", "\0"};
test_2d(builts); /* without passing total number of args; depends on special word at the end */
test_2d_num(builts, 2); /* also pass total num of elements as argument */
return 0;
}
/* This needs a special word at the end to indicate the end */
void test_2d(char builts[][10])
{
int i;
char tmp[10];
/* just print the words from word array */
for (i=0; *builts[i] != '\0'; i++ )
printf("%s\n", builts[i]);
/* also try copy words to a tmp word and print */
for (i=0; *builts[i] != '\0'; i++ ) {
strcpy(tmp, builts[i]);
printf("%s\n", tmp);
}
/* Do something */
}
/* Also get total number of elements as a parameter */
void test_2d_num(char builts[][10], int tot_elem)
{
int i;
/* Process each word from the array */
for (i = 0; i < tot_elem; i++) {
printf("%s\n", builts[i]);
/* Do something */
}
}
Note that this function can only process arrays like, builts[][10], and not builts[][11], or builts[][9].
If you want want a generic function, then you need to store the addresses of individual words in an char *arr[] and pass this array to the function. Like
int main()
{
/* store the addresses of individual words in an `char *arr[] */
char *arr[] = {"hello", "this", "that", NULL};
test_2d_gen(arr);
return 0;
}
void test_2d_gen(char *arr[])
{
int i;
/* process each word */
for (i = 0; arr[i] != NULL; i++) {
printf("%s\n", arr[i]);
/* Do something */
}
}

Related

Return array or multiple variables from a function

int arrays[2] = {0,1};
void setup () {
Serial.begin(9600);
pinMode(2,INPUT);
}
void loop () {
int buttonstate = digitalRead(2); //reads I/O pin 2
if (buttonstate==HIGH) { //if I/O pin 2 is HIGH do following
arrays[] = function(arrays); //calls function "function"
Serial.println(arrays[0]); //prints out arrays[0]
Serial.println(arrays[1]); //prints out arrays[1]
}
}
int function (int arrays [2]) {
int holder = arrays[1]; //switches place the values on the array
arrays[1] = arrays[0];
arrays[0] = holder;
return arrays[]; //return the modified array
}
What am I doing wrong here? Can someone explain why my code is wrong?
Why doesn't it just return the array and modify its content? I have read on other articles about pointers, but I couldn't understand how they worked.
Well, your worst misconception is thinking that C allows you to pass a complete array as parameter or return value.
First of all, you cannot do an assignment like
arrays[] = function(...);
This is incorrect, as there's no way to refer to the array as a whole. You can return a reference to an array, something like:
arrays = function(...);
always that your function returns a valid POINTER TO INTEGER, and always that you declare your arrays variable as int *arrays;, instead. But this has another problem... a pointer doesn't allocate memory for the pointed to values.
The best solution is to use the array reference to pass it to the function, and then make the function to operate on the array proper. Like in
function(arrays); /* you should have function exchanged the arrays values properly */
for (i = 0; i < 2; i++) /* print arrays contents and check values have been exchanged */
printf("arrays[%d] == %d\n", i, arrays[i]);
in this case, the arrays() function should have been implemented as
void function(int arrays[])
{
int temporary = arrays[0];
arrays[0] = arrays[1];
arrays[1] = temporary;
/* no return as function is declared void */
}
Of course, you can return the reference to the original array, and this can be helpful in some expressions, but think always that you are dealing with the same array anycase.
int *function(int *arrays) /* this parameter declaration is equivalent to the last one */
{
int temporary = arrays[0];
arrays[0] = arrays[1];
arrays[1] = temporary;
return arrays; /* reference to the first array element */
}
The array is passed to the function by reference.
If you modify the array in the function, the changes will persist after the function call.
int arrays[2] = {0, 1};
void setup() {
Serial.begin(9600);
pinMode(2, INPUT);
}
void loop() {
int buttonstate = digitalRead(2); //reads I/O pin 2
if (buttonstate == HIGH) { //if I/O pin 2 is HIGH do following
function(arrays); //calls function "function"
Serial.println(arrays[0]); //prints out arrays[0]
Serial.println(arrays[1]); //prints out arrays[1]
}
}
void function(int arrays[]) {
int holder = arrays[1]; //switches place the values on the array
arrays[1] = arrays[0];
arrays[0] = holder;
}
If you don't want to modify the existing array, you will need to pass another array.
int arrays[2] = {0, 1};
int arrays2[3];
void setup() {
Serial.begin(9600);
pinMode(2, INPUT);
}
void loop() {
int buttonstate = digitalRead(2); //reads I/O pin 2
if (buttonstate == HIGH) { //if I/O pin 2 is HIGH do following
function(arrays, arrays2); //calls function "function"
Serial.println(arrays2[0]); //prints out arrays2[0]
Serial.println(arrays2[1]); //prints out arrays2[1]
Serial.println(arrays2[2]); //prints out arrays2[2]
}
}
void function(int arrays[], int arrays_return[]) {
arrays_return[0] = arrays[1];
arrays_return[1] = arrays[0];
arrays_return[2] = arrays[0] + arrays[1];
}
You will need to make sure that the array have appropriate size, because there won't be any explicit error thrown if you write/read outside the array's range, but you may find some odd behavior that will be hard to debug.

What is the easiest way to initialize a 2d array from a vector of strings?

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..

How to modify array inside function which doesn't take this array as parameter

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.).

cannot convert from 'std::string' to 'char'

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.

Returning array of dynamically allocated wchar_t* from a function

I have a function whose signature is as follows:
GetCustomers( wchar_t** Name,int *count);
In main method: Call to customer looks like this:
GetCustomers( Name,&count);
The body of the function is as follows: (since count of customers is unknown , I am trying to allocate meomry dynamically)
GetCustomers( wchar_t** Name,int *count)
{
//Logic to get customer count : Stored in int myCustomersCount
Names = new wchar_t*[myCustomersCount];
for (int i=0; i < myCustomersCount; i++ )
{
Names[i] = new wchar_t;
}
//Logic to get customer names in wchar_t* strName = "Name1";
Names[0] = strName;
*count = myCustomersCount;
}
I would think that this implementation would allow array Name to be passed back correctly to the Main() function with memory allocation on heap but it seems not to work. What is wrong here? myCustomersCount seems to be correct in caller.
PS: The code compile and executes but array received in Main is garbage.
You seem to be thinking in terms of C, not really C++. I'd use something like:
std::vector<std::string> GetCustomers();
or (probably preferred):
template <class outIt>
void GetCustomers(outIt output_iterator);
The latter you'd use something like:
std::vector<std::wstring> customers;
GetCustomers(std::back_inserter(customers));
The third obvious possibility would be to just equip your customers class with a begin() and end() member functions that return iterators to the customers data.
Edit2: Here's some tested demo code:
#include <stdio.h>
#include <string.h>
#include <wchar.h>
void GetCustomers(wchar_t ***names, int *count) {
static wchar_t *myCustomers[] = {
L"You",
L"Him",
L"Her"
};
int myCustomersCount = 3;
wchar_t **temp = new wchar_t *[myCustomersCount];
*count = myCustomersCount;
for (int i=0; i<myCustomersCount; i++) {
temp[i] = new wchar_t[wcslen(myCustomers[i])+1];
wcscpy(temp[i], myCustomers[i]);
}
*names = temp;
}
int main() {
wchar_t **customers;
int count;
GetCustomers(&customers, &count);
for (int i=0; i<count; i++)
printf("%S\n", customers[i]);
return 0;
}
I'm really not sure what you're trying to do here; from what I understand about your code; you're trying to store some strings into an array of an array of character pointers.
GetCustomers(wchar_t **Name, int *count) {
Name = new wchar_t*[myCustomersCount];
for(int i = 0; i < myCustomersCount; i++) {
/* Get your customer name and store into strName */
Name[i] = strName;
}
*count = myCustomersCount;
}
In main, presumably you've got something like this
wchar_t *Name = NULL;
and then you say
GetCustomers( Name,&count);
This passes Name by value, but you want to pass it by reference:
GetCustomers( &Name,&count);
And presumably it's just a typo, but your parameter name is Name (singular) but you refer to it as Names (plural) in the function:
GetCustomers( wchar_t** Name,int *count)
{
//Logic to get customer count : Stored in int myCustomersCount
Names = new wchar_t*[myCustomersCount];
In any case, you want to assign to where Name is pointing, not to itself:
*Names = new wchar_t*[myCustomersCount];
Then for each element in Names you allocate one character, but then overwrite the first one with strName. The allocation is unnecessary (and in fact is a memory leak), and you should assign from strName to each element within the loop, as Suroot's answer does.
2 definite issue and 1 potential issue with your code. The main issue causing your problem first: Name itself is passed by value. That means when you you assign to it in the very first line of your function when you new the memory, you're assigning to the copy, not the original! You have three options: 1) keep the double pointer, make the caller responsible for allocating the memory, and add a third parameter for number of names that the array can hold (recommended) or 2) make Name a triple pointer (wchar_t*** Name) and then you can assign to it by dereferencing it: *Name = new wchar_t*[myCustomersCount]; or 3) just return the wchar_t** since you don't use the passed value for anything.
Then another definite issue: when you allocate memory for each name, you need to use the new[] operator there as well because otherwise you're only allocating room for a single wchar_t.
Finally, the potential issue. You don't show how exactly this code is getting each customer name. But if strName points to memory that is getting reused for each customer name as you put them all in your array, you're going to have to wstrcpy each name into the array. If it doesn't, then you don't need to allocate memory for each Names[i] as you can just store the result right into Names[i].
A final note: just from looking at this code it seems like you're going to have lots of problems with memory management as it seems very unclear who is responsible for allocating and deallocating memory which is likely going to lead to memory leaks. Try your best to keep the responsibility for allocating and deallocating the memory in the same location and you'll reduce lots of potential headaches -- have callers allocate the memory before they call the function and have the caller deallocate the memory when they're done with it.
/* changed */
wchar_t** GetCustomers( int *count)
{
//Logic to get customer count : Stored in int myCustomersCount
wchar_t **Names = new wchar_t*[myCustomersCount];
for (int i=0; i < myCustomersCount; i++ )
{
/* changed */
Names[i] = new wchar_t[MAX_NAME_SIZE];
}
//Logic to get customer names in wchar_t* strName = "Name1";
Names[0] = strName; /* possible wstrcpy needed here? */
*count = myCustomersCount;
/* changed */
return Names;
}
Edit
If you really absolutely can't change the function signature, the only solution I can think of is to flatten your array and use C memory functions (you could also just use a long series of news and deletes, but why not use realloc when this is what it's made for and you're managing memory without using other C++ features like the STL anyways?):
GetCustomers( wchar_t **Names, int *count)
{
//Logic to get customer count : Stored in int myCustomersCount
size_t names_size = 0;
for (int i=0; i < myCustomersCount; i++ )
{
strName = ???; // whatever you use to get the next name
size_t old_names_size = names_size;
names_size += (wstrlen(strName) + 1) * sizeof(wchar_t); //+1 for NULL
*Names = realloc(*Names, names_size);
if (!*Names) {
// Memory allocation failed, log it, abort, do whatever
}
wstrcpy(Names[old_names_size], strName);
}
*count = myCustomersCount;
}
Note that this assumes that Name has already been initialized and points to memory where you can store a wchar_t*, just like the original version assumed count has been initialized and points to memory where you can store an int.
I thought I'd make a fresh start in a new answer.
Here's a simple program that does what I think you're trying to do, with the constraint that the signature of GetCustomers must not be altered.
void GetCustomers(wchar_t** Names,int *count)
{
// Allocate the array of names
wchar_t **ar = new wchar_t*[3];
// Allocate space for each name in the array
ar[0] = new wchar_t[10];
ar[1] = new wchar_t[10];
ar[2] = new wchar_t[10];
// Fill in the names
wcscpy(ar[0],L"joe");
wcscpy(ar[1],L"jim");
wcscpy(ar[2],L"bob");
// Return the array through the bad GetCustomers signature
*Names = (wchar_t*)ar;
*count = 3;
}
int wmain(int argc, wchar_t* argv[])
{
// names is an array of strings
wchar_t **names = NULL;
int count;
// Squeeze names into the dodgy GetCustomers signature
GetCustomers((wchar_t**)&names,&count);
// Delete each name
for(size_t x = 0; x < count; ++x)
delete[] names[x];
// Delete the array
delete[] names;
return 0;
}
Note that I've matched the cast inside the function with another one in main. This way we keep everything as it should be, except for that pesky GetCustomers signature.
Does this help?