Array of pointers to pointers: managing strings for different languages - c++

I currently have a lot of character arrays that store simple character strings in English for display. I also have pointers to these character arrays.
char helloAr[20] = "Hello";
char timeAr[20] = "Time";
char dogAr[20] = "Dog";
char* helloPtr = helloAr;
char* timePtr = timeAr;
char* dogPtr = dogAr;
I am adding more character arrays in a different language, French to begin with.
char helloArFr[20] = "Bonjour";
char timeArFr[20] = "temps";
char dogArFr[20] = "chien";
If the user selects French I plan to change the address that all my pointers (currently pointing at the English character arrays) point to, so they now point to the French character arrays. I assume I can simply assign a new values to these pointers to do this,
helloPtr = helloArFr;
timePtr = timeArFr;
dogPtr = dogArFr;
however my actual code will have a lot of arrays so I wanted to use a loop to do this rather than lots of statements like the one above.
To do this I plan to create an array of character pointers to the addresses of my character arrays.
char* charArrAddresses [NUMBER_OF_TEXT_ARRAYS]=
{
&helloAr,
&timeAr,
&dogAr,
&helloArFr,
&timeArFr,
&dogArFr,
};
I also plan to store all the pointers in an array so that I can reference them by their location in the array in my single statement, but this is where I need some help as I am unsure on how to do this. Something like this maybe?
char ** langPtrs[NUMBER_OF_LANG_POINTERS]=
{
helloPtr,
timePtr,
dogPtr,
};
In the single statement inside the loop I will use the selected language and the number of char arrays to calculate the correct index for charArrAddresses, lets call this X for now. I will use the value of my loop (say i) to index my langPtrs array. So in my single want to say something like,
for(i = 0; i<NUMBER_OF_LANG_POINTERS; i++)
{
langPtrs[i]= charArrAddresses[X];
}
I am trying to assign the address of the character array stored in index X of charArrAddresses to the pointer in index i in the langPtrs array. I just need help on exactly how to declare the langPtrs array and on how to write my single statement above.

Rather than placing the strings for all languages in a single array, make a 2D array of strings and languages. If you don't plan on modifying any of these strings, you can make them string literals instead of arrays.
enum langs {
LANG_ENGLISH,
LANG_FRENCH,
NUMBER_OF_LANGS
};
enum strings{
STR_HELLO,
STR_TIME,
STR_DOG,
NUMBER_OF_STRINGS
};
const char *langPtrs[NUMBER_OF_LANGS][NUMBER_OF_STRINGS]=
{
{ "Hello", "Time", "Dog" }
{ "Bonjour", "temps", "chien" }
};
Since the values of the symbols in an enum start at 0 and increment by 1 for each subsequent symbol, you can use them an array indexes. The last member of each enum, which does not correspond to an actual element in the array, can be used as the size of the array.
So if you want to, for example, print the string for "time" in French, you would use:
printf("%s\n", langPtrs[LANG_FRENCH][STR_TIME]);
If you want to always print string from whatever the "current" language is, you can create a pointer to the subarray for the current language:
const char **currentLang = langPtrs[LANG_FRENCH];
Then you can use that:
printf("%s\n", currentLang[STR_TIME]);
EDIT:
If you want to keep helloPtr, timePtr, and dogPtr, and you want to set them based on the current language, you can put their addresses in another array:
const char **usedInClassesPtrs[NUMBER_OF_STRINGS] = {
&helloPtr,
&timePtr,
&dogPtr
}
Then loop through the array, dereferencing each element to give you the actual pointers you want to change, and assign them a string from the 2D language array based on the current language as follows:
for (i=0; i<NUMBER_OF_STRINGS; i++) {
*usedInClassesPtrs[i] = langPtrs[currentLang][i];
}

The #debush answer should work quite well.
From your example i assume that only 1 language is active at a time in your code. For that, i suggest to use a resource approach to manage your multi-language support. You can basically load the corresponding resource file of a language and store it in std::vector<std::string>, std::map<const enum/id/etc., std::string> or any similar data structure. This can be done either on the fly or at initialization stage depending on your need. In your code you save a pointer to this data structure std::vector<std::string>* ptr to refer to currently loaded language by invoking (*ptr)[index].

Related

C++ How to populate a static array of strings with new strings in different locations?

Say I got this
char* MapIds[5000] = { "Northeast Asia","Hanyang","Pusan","Pyongyang","Shanghai","Beijing","Hong Kong", /*...5000 values etc../* };
I tried
strcpy(MapIds[0], "gfggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg");
But it crashes
How Do I keep changing them around without messing up the strings in other elements.
I dont want to use std::string or vector those cause crazy slow compile times.
Because you try to copy into a literal string ("Northeast Asia").
In C++ a literal string is really a constant array of characters, any attempt to modify such an array will lead to undefined behavior (which can sometimes express themselves as crashes).
If you want to make MapIds[0] point to a new string, then you simply use assignment:
MapIds[0] = "gfggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg";
Because literal strings are constant arrays of characters, C++ doesn't really allow you to have a char* to point to them, you must use const char*:
const char* MapIds[] = { ... };
However, a much better solution is to not use C-style strings and char pointers (const or not) at all, but only use std::string:
std::string MapIds[] = { ... };
Then you can modify the strings in the array itself, using plain assignment as shown above.

Array of char pointers

I am looking at some code I did not write and wanted help to understand an element of it. The code stores character arrays, creates pointers to these arrays (assigning the pointers the arrays addresses). It looks like it then creates an array to store these characters pointers addresses and I just wanted some clarification on what I am looking at exactly. I also am confused about the use of the double (**) when creating the array.
I have included a stripped down and simplified example of what I am looking at below.
char eLangAr[20] = "English";
char fLangAr[20] = "French";
char gLangAr[20] = "German";
char* eLangPtr = eLangAr;
char* fLangPtr = fLangAr;
char* gLangPtr = gLangAr;
char **langStrings [3]=
{
&eLangPtr,
&fLangPtr,
&gLangPtr
};
When using the array they pass it as an argument to a function.
menu (*langStrings[0]);
So the idea is that the character array value "English" is passed to the function but I'm having trouble seeing how. They pass the menu function a copy of the value stored in the langStrings function at location 0, which would be the address of eLandPtr? If someone could explain the process in English so I could get my head around it that would be great. It might be just because it has been a long day but its just not straight in my head at all.
You are correct that langStrings contains pointers to pointers of array of characters. So each langString[i] points to a pointer. That pointer points to an array. That array contains the name of a language.
As others point out, it looks a bit clumsy. I'll elaborate:
char eLangAr[20] = "English"; is an array of 20 chars and the name "English" is copied to it. I don't expect that variable eLangAr will ever contain something else than this language name, so there is no need to use an array; a constant would be sufficient.
char **langStrings [3]= ... Here, it would be sufficient to have just one indirection (one *) as there seems no need to ever have the pointer point to anything else (randomly shuffle languages?).
in conclusion, just having the following should be sufficient:
const char *langStrings [3]=
{
"English",
"French",
"German"
};
(Note the const as the strings are now read-only constants/literals.)
What the given code could be useful for is when these language names must be spelled differently in different languages. So
"English",
"French",
"German" become "Engels", "Frans", "Duits". However, then there still is one level of indirection too many and the following would be sufficient:
char *langStrings [3]=
{
aLangArr,
fLangAr,
gLangAr
};
Ok, here goes.
The **ptrToptr notation means a pointer to a pointer. The easiest way to think on that is as a 2D matrix - dereferencing one pointer resolves the whole matrix to just one line in the matrix. Dereferencing the second pointer after that will give one value in the matrix.
This declaration:
char eLangAr[20] = "English";
Declares an array of length 20, type char and it contains the characters 'E', 'n', 'g', 'l', 'i', 's', 'h' '\0'
so it is (probably) null terminated but not full (there are some empty characters at the end). You can set a pointer to the start of it using:
char* englishPtr = &eLangAr[0]
And if you dereference englishPtr, it'll give the value 'E'.
This pointer:
char* eLangPtr = eLangAr;
points to the array itself (not necessarily the first value).
If you look at
*langStrings[0]
You'll see it means the contents (the dereferencing *) of the pointer in langStrings[0]. langStrings[0] is the address of eLangPtr, so dereferencing it gives eLangPtr. And eLangPtr is the pointer to the array eLangAr (which contains "English").
I guess the function wants to be able to write to eLangAr, so make it point to a different word without overwriting "English" itself. It could just over-write the characters itself in memory, but I guess it wants to keep those words safe.
** represents pointer to pointer. It's used when you have to store pointer for another pointer.
Value of eLangPtr will be pointer to eLangAr which will has the value "English"
Here:
char eLangAr[20] = "English";
an array is created. It has capacity of 20 chars and contains 8 characters - word "English" and terminating NULL character. Since it's an array, it can be used in a context where pointer is expected - thanks to array-to-pointer decay, which will construct a pointer to the first element of an array. This is done here:
char* eLangPtr = eLangAr;
Which is the same as:
char* eLangPtr = &eLangAr[0]; // explicitly get the address of the first element
Now, while char* represents pointer to a character (which means it points to a single char), the char** represents a pointer to the char* pointer.
The difference:
char text[] = "Text";
char* chPointer = &ch[0];
char** chPointerPointer = &chPointer; // get the address of the pointer
std::cout << chPointer; // prints the address of 'text' array
std::cout << *chPointer; // prints the first character in 'text' array ('T')
std::cout << chPointerPointer; // prints the address of 'chPointer'
std::cout << *chPointerPointer; // prints the value of 'chPointer' which is the address of 'text' array
std::cout << *(*chPointerPointer); // prints the first character in 'text' array ('T')
As you can see, it is simply an additional level of indirection.
Pointers to pointers are used for the same reason "first-level" pointers are used - they allow you to take the address of a pointer and pass it to a function which may write something to it, modifying the content of the original pointer.
In this case it is not needed, this would be sufficient:
const char *langStrings [3]=
{
eLangPtr,
fLangPtr,
gLangPtr
};
And then:
menu (langStrings[0]);

Insert char * with new into a vector C++

I have code sample like below..
std::vector<char*> vNameList;//it will be defined globally..
int main(int argc, char* argv[])
{
CollectName();
for(int i = 0; i<(int)vNameList.size(); i++)
{
printf("\n %s" , vNameList[i]);//Here gabage values are getting printed on console
}
return 0;
}
void CollectName()
{
char *Name = new char[sizeof(NAME)+1];//NAME datatype is defined having size of 32 char
//processing for Name is performed , which includes assigning Name variable with value..
//now insert it into vector
vNameList.push_back(Name);
delete[] Name; //at this Name value inserted into vector become garbage
}
I believe if we initialize char * with new it must be deleted to avoid memory leaks. But this is leading to modifying values from a vector.
Please guide me so that I can correct my code which will give me correct values.
I have some restriction to use Char * only , so suggest way to achieve this using char*.
You can correct your code by deleting the pointers only after you're done using them (assuming you actually have code which uses the pointers. Your example code doesn't print anything at all, garbage or otherwise).
But it's usually better design to store character strings in a std::string and when you store std::strings in a std::vector, you no longer need to manage the memory manually.
It is because the name of array is treated as pointer in c++(or c, it is inherted).
Therefore when you do
vNameList.push_back(Name);
It inserts the char * into vector,i.e the pointer to the first char(ans hence the string) to the vector, but you delete the pointer afterwards , therefore you get junk values. However if you don't delete the pointer , it works just fine as the pointer still exists , but this way you will not free up memory. Therefore : DONOT USE THIS
here it is : LIVE EXAMPLE
To avoid this hassle : you should use
std::vector<std::string> vNameList;
instead.

Parsing a string to a pointer array of chars: char[0] contains the full string and [1] onward contains nothing

I'm trying to parse a simple string to an array of *char and for some reason when I use string.c_str() it puts the entire string into *char[0] and the rest of the array is left blank (I originally thought that chars could only hold one ASCII character but I guess that they act differently as pointers), could anyone have a scan through my function and tell me if there are any obvious mistakes?
static void SetGame()
{
// Variable Initiation
int myRandom = rand() % (numOfWords - 1);
lengthOfString = wordArray[myRandom].length();
// Reinitiate Pointer Arrays
stringArray = new string[lengthOfString];
isDiscoveredArray = new bool[lengthOfString];
// Parse string to the array of characters
*stringArray = wordArray[myRandom].c_str();
// Set each boolean array value to false
for (int i = 0; i < sizeof(isDiscoveredArray); i++)
{
isDiscoveredArray[i] = false;
}
}
Here are my decelerations of the pointers
// Global Variable and pointer Declerations
string *wordArray;
int numOfWords;
string *stringArray;
int lengthOfString;
bool *isDiscoveredArray;
Any ideas? Thanks.
You are mixing types here. First you build an array of strings and store it in a pointer, then you assign to the first element a const char* coming from c_str. The code you currently have would be if your were creating a string for every character in your selected word.
Make your "stringArray" a const char* to fit with the code you already have, but remove the memory allocation.
You've got an array of std::string and when you deference it (i.e. *stringArray) its the same as stringArray[0], so that is why it always going into the first element of your array.
Since you are setting your array have the same number of elements as the string your are copying has characters, you may just want to use a string rather than a string array to copy it into.
If it supposed to be char* (character array) then you will need to explicitly copy the source, which is the result of wordArray[myRandom].c_str(), into your character array rather than using simple assignment.

Passing 2-D array with dynamic size between functions in C/++

This is "popular" question so I already checked the similar threads but still didnt resolve my issue.
How can I declare 2-D array to hold "strings" - I need array of array of chars AFAIK - and use it as argument to 5 functions one after another where I can pass it by reference and update the content dynamically so following function can compare it. (I might get 10 "strings" or even empty array, so I want to do it correctly with dynamic array coz array content is different from system to system).
"string" => C style string aka array of chars. MAXLEN < 32;
C solution would be more disirable but if vectors can work, why not.
One possible solution in C is as follows:
char **p_strings = calloc(num_strings, sizeof(*p_strings));
for (i = 0; i < num_strings; i++)
{
// Allocate storage for the i-th string (always leave room for '\0')
p_strings[i] = calloc(len_string[i]+1, sizeof(*p_strings[i]));
}
...
// Call a function
my_function(p_strings, num_strings);
You will need to remember to free all this data when you're done with it.
If you need to alter the length of a string, or change the number of strings, you will have to do some fairly painful reallocation. So if you're working in C++, you should probably just be using a std::vector<std::string>.
std::vector<std::string> strings;
strings.push_back("Foo");
strings.push_back("Bar");
...
my_function(strings);
You can even get const pointers to C-style strings for each element, using c_str().
Assuming C++; for this I see no problem with using a vector to string (the string serves as the second dimension):
void foo(vector<string> v) {
cout << v[0]; // Assuming the elements exist!
}
int main(int argc, char *argv[])
{
vector<string> vString; // Make the vector
vString.push_back("something"); // Add a string
foo(vString); // Print out 'something'
}
In your edit you also described that the only thing that will change would be the actual string, so instead of push_backing your strings when they are needed, you can init the vector with the length:
vector<string> vString(10); // Assuming a size of 10
and then use them normally:
vString[4] = "something";
and (in response to the comment), to resize at runtime:
vString.resize(15); // Make it bigger, generates new blank strings