I am trying to avoid to repeat my code for 5 differentes arrays. I have 3 arrays (could be more in future):
const char *FirstlistOfOptionText[2] = {OPT_1,
OPT_2};
const char *SecondlistOfOptionText[2] = {OPT_1,
OPT_2};
const char *ThirdlistOfOptionText[2] = {OPT_1,
OPT_2};
THe elements in each one will not be the same. Now they are because I just copy&paste them. Number of elements won't neither.
I have a function in which I want to print every element of a list depending on a value I give as parameter. Also, I need to print one of those elements in other color (all in white except one in green).
I just want to have one code for printing and selecting the color as I have right now. But I want to select the correct array before doing that. I thought about:
const char *listOfOptions[];
if(menu_t.first_level_option == 0) {
listOfOptions = FirstlistOfOptionText;
}
if(menu_t.first_level_option == 1) {
listOfOptions = SecondlistOfOptionText;
}
if(menu_t.first_level_option == 2) {
listOfOptions = ThirdlistOfOptionText;
}
But I get some errors about storage size of 'listOfOptions' isn't known. Or that I can't use const char** for a char* or thing like that.
What is the correct way to do this?
Essentially you neeed to make listOfOptions a char **;
An array of pointers can be referenced through a pointer to pointers (that's what the char ** is).
The size will be unknown to anyone using listOfOptions thus you need a way to determine the size. Either terminate the list with a NULL pointer or you will have to use a 2nd variable (listOfOptionsSize) that tracks the size.
So the code below should compile (I opted for the NULL terminated lists).
const char *FirstlistOfOptionText[] = {"a", "b", NULL};
const char *SecondlistOfOptionText[] = {"c", "d", "e", "f", NULL};
const char *ThirdlistOfOptionText[] = {"e", "f", "g", NULL};
const char **listOfOptions= NULL; // pointer to pointer(s)
int first_level_option= 2; // some value for testing
if(first_level_option == 0) {
listOfOptions = FirstlistOfOptionText;
}
if(first_level_option == 1) {
listOfOptions = SecondlistOfOptionText;
}
if (first_level_option == 2) {
listOfOptions = ThirdlistOfOptionText;
}
printem(listOfOptions);
Now for your printing function, it will get the pointer to the list of pointers as a parameter and and will look like this:
void printem(const char **listOfOptions)
{
const char *word;
while (*listOfOptions!=NULL) { // while the pointer in the list not NULL
word= *listOfOptions; // get the char * to which listOfOptions is pointing
printf("entry: %s\n", word);
listOfOptions++;
}
}
Oh, and welcome to C-Pointer Hell :-)
const char *FirstlistOfOptionText[2] is an array of two pointers to char.
const char *listOfOptions[] is an array of unknown size with pointers to char.
const char **listOfOptions; is a pointer to a pointer to char and you can assign it the address of your list of options array:
listOfOptions = FirstlistOfOptionText;
const char *listOfOptions[];
But I get some errors about storage size of 'listOfOptions' isn't known.
The size of an array is part of its type. T[1] and T[2] are different types.
An array without a specified size is an incomplete type, and you cannot create an object of an incomplete type.
Or that I can't use const char** for a char* or thing like that.
Yes, because those are completely different types. The first is a pointer to a pointer to a constant char object. The second is a pointer to a non-constant char object.
Your code attempts to treat an array like a first-class citizen which you can assign like a "normal" object such as an int. It also attempts to treat arrays of different dimensions equally. None of that can work. C++ arrays are more limited than you think.
The solution is thus to use std::vector. And while you're at it, std::string instead of char*.
#include <string>
#include <vector>
#define OPT_1 "a"
#define OPT_2 "b"
int main()
{
std::vector<std::string> FirstlistOfOptionText = { OPT_1, OPT_2 };
std::vector<std::string> SecondlistOfOptionText = { OPT_1, OPT_2 };
std::vector<std::string> ThirdlistOfOptionText = { OPT_1, OPT_2 };
int first_level_option = 0;
std::vector<std::string> listOfOptions;
if (first_level_option == 0) {
listOfOptions = FirstlistOfOptionText;
}
if (first_level_option == 1) {
listOfOptions = SecondlistOfOptionText;
}
if (first_level_option == 2) {
listOfOptions = ThirdlistOfOptionText;
}
}
Of course, this can (and should) be improved even more. For example, getting rid of the preprocessor macros and putting the list selection into a function like std::vector<std::string> GetListOfOptions(int).
To print a list of options you may use a template function that takes a reference to a static array as a parameter:
template <int n>
void PrintOptions(const char* (&listOfOptions)[N])
{
for (int i = 0; i < N; i++)
{
//actual printing
}
}
void PrintMenu(/* ... */)
{
//...
switch (menu_t.first_level_option)
{
case 0:
PrintOptions(FirstlistOfOptionText);
break;
case 1:
PrintOptions(SecondlistOfOptionText);
break;
case 2:
PrintOptions(ThirdlistOfOptionText);
break;
}
//...
}
The size of an array will be deduced by the compiler.
Related
I am trying to solve a coding question that requires the results be returned using a given struct. The struct is defined as:
struct Answer
{
const char* const* lastNames;
unsigned numberOfPeople;
}
Where the lastNames is a pointer to last names that are each terminated by a non-alpha char. I can not seem to find any way to convert the vector of strings that I am using to compile all the last names into a variable that I can assign to lastNames. I have tried making a single string with all the last names and assigning it with c_str() like so:
Ans->lastName = allNames.c_str(); but this gives me an error. Due to the limitations of the question I am unable to change the struct variable to anything else. How can I assign a string to a const char* const*
The structure being used effectively uses a C-style approach to defining a variable sized array of pointers to char (with const sprinkled over it). You’ll need storage for both the array of char const* as well as the entities pointed to. Here is how you could build it from a std::vector<std::string>:
std::vector<std::string> strings = somehow_compute_the_strings();
std::vector<char const*> array;
for (std::string const& s: strings) {
array.push_back(s.c_str());
}
Answer answer = { array.data(), array.size() };
Of course, you can’t return answer without the pointer inside pointing to stale data: you’d need to keep the two std::vectors alive. Potentially these two objects could be made members of an object the function is called on. To actually return an object of type Answer without a place to hold on to the std::vectors you could allocate the relevant entities and accept that the result will yield a memory leak unless the caller can clean the result up.
You can't just cast stuff. struct Answer is expecting a char**, so you are going to have to build it and keep it valid as long as the struct Answer is in use. At least they were kind enough to let us know they don't intend to modify it or mess with cleaning up the memory, since it takes "const char * const *".
#include <iostream>
#include <vector>
#include <string>
#include <assert.h>
typedef std::vector<std::string> VectorOfStrings_type;
struct Answer
{
const char* const* lastNames;
unsigned numberOfPeople;
};
class AnswerWrapper
{
private:
// construct and maintain memory so the pointers in the Answer struct will be valid
char ** lastNames;
unsigned int numberOfPeople;
public:
AnswerWrapper(const VectorOfStrings_type &input){
numberOfPeople = input.size();
// create the array of pointers
lastNames = static_cast<char**>(
malloc(numberOfPeople * sizeof(char*))
);
// create each string
for (unsigned int i = 0; i < numberOfPeople; ++i){
const std::string &name = input[i];
// allocate space
lastNames[i] = static_cast<char*>(
malloc(name.size() + 1)
);
// copy string
strncpy(lastNames[i], name.data(), name.size());
// add null terminator
lastNames[i][name.size()] = '\0';
}
}
operator Answer (){
return Answer{ lastNames, numberOfPeople };
}
~AnswerWrapper(){
// critcally important, left as an exercise
assert(0);
}
};
void SomeFunctionWhichUsesAnswer(Answer a){
// presumably you have some legacy C code here
// but here's a quick and easy demo
for (unsigned int i = 0; i < a.numberOfPeople; ++i)
std::cout << a.lastNames[i] << std::endl;
}
int main() {
// Here is your vector of strings
VectorOfStrings_type myData { "custom formatted data goes here", "and more here", "and again" };
// You must construct a buffer for the "Answer" type, which must remain in scope
AnswerWrapper temp{ myData };
// AnswerWrapper is currently in scope, so inside this function, the pointers will be valid
SomeFunctionWhichUsesAnswer(temp);
}
Also, I noticed that the strings in Answer are not referred to as null terminated. That is a separate issue you can take care of.
A const member variable can only be assigned in the constructor.
if you can add to the struct, define a constructor, and use the : lastname(value) syntax; or use the struct Answer myVar{value,number}; initialization, right where you declare your instance.
Another - ugly, dangerous, and frowned upon - alternative is a cast: (char**) lastname = value;, or in C++ syntax reinterpret_cast<char**>(lastname) = value.
If someone is teaching you either of those approaches, change the teacher.
I was wondering if it was okay to pass around/return structs holding statically allocated arrays in C++. For example:
typedef struct t{
char name[32];
int id;
}t;
t foo(char name[]){
t my_t = {name, 0};
return my_t;
}
int main(){
t main_t = foo("a struct");
printf("%s", main_t.name); //is this safe to access?
return 0;
}
When it returns the struct by value, I guess it doesn't copy the array name, only the pointer to it.
Edit: Just to clear up some things. I do know that char *var is equal to char var[] in function arguments. I wrote this code up really quickly without even testing it. I know it is definitely not the best code in the world and I wouldn't advice anybody to use it in real life.
Ideally I would allocate the struct dynamically and pass around a pointer, however, I am teaching a person to program in C/C++. It is for a national exam which doesn't require a person to know dynamic allocation or pointers for that matter, that is why * are not really used at all.
The question is really about whether it is okay to return a struct holding a statically allocated array.
Shall we use this piece of code instead:
#include <iostream>
struct t{
char name[32];
int id;
};
t foo(int id){
t my_t;
my_t.id = id;
for(char i = 0; i < 31; i++){
my_t.name[i] = 'a';
}
my_t.name[31] = '\0';
return my_t;
}
int main(){
t main_t = foo(0);
std::cout << main_t.name; //is this safe to access?
return 0;
}
It can be done.
But it shouldn't be done: alternatives are std::string and std::array. You get your copy, allocation, deallocation etc... for free!
struct t {
std::string name;
int id;
std::array<int, 10> integers;
};
...
t main_t = {"a struct"};
main_t.integers[5] = 5;
t copy = main_t;
assert( copy.name == "a struct" );
assert( copy.id == 0 );
assert( copy.integers[5] == 5 );
There is no static array in your code.
When you return a t instance by value, it will copy the contents of the array.
The problem is with how you're initializing the t instance, not with how you're returning it.
Change this:
t my_t = {name,0};
To this:
t my_t = {0};
strncpy(my_t.name,name,sizeof(my_t.name)-1);
Or to this, if you want to avoid the use of library functions:
int i;
t my_t;
for (i=0; i<sizeof(my_t.name)-1 && name[i]!=0; i++)
my_t.name[i] = name[i];
my_t.name[i] = 0;
my_t.id = 0;
You've an error in your program; you're trying to copy a pointer to an array, instead you should copy the contents pointed to by the pointer into the array. It should be like this
#include <algorithm>
#include <cstring>
struct t
{
char name[32];
int id;
};
t foo(const char *name)
{
t my_t = {};
const size_t len = std::strlen(name);
const size_t max_len = sizeof(t::name) / sizeof(t::name[0]) - 1u;
std::copy(name, name + std::min(len, max_len), my_t.name);
return my_t;
}
int main()
{
t main_t = foo("a struct");
printf("%s", main_t.name);
}
As for your question
I was wondering if it was okay to pass around/return structs holding static arrays in C++
Yes, it's ok, the whole struct will get copied (or moved, depending on the type) to the variable at the calling end.
It's OK to pass around structs that contain arrays. However, this line doesn't do what you think it does:
t my_t = {name, 0};
Using designated initializer syntax, it would be equivalent to:
t my_t = { .name[0] = name; .name[1] = 0; };
The first member of t is an array with 32 elements, so the first 32 initializers are applied to those 32 chars. Unless you use some more braces, but you still need one initializer per element, there's no magic way to get a strcpy out of brace-enclosed initializers.
You should get a compiler error about initializing a char with a pointer.
I'm writing a program which finds exit from maze. I have a multidimentinal array representing the actual maze.
const int size = 12;
char maze[ size ][ size ] = {
"############",
"#...#......#",
"..#.#.####.#",
"###.#....#.#",
"#....###.#..",
"####.#.#.#.#",
"#..#.#.#.#.#",
"##.#.#.#.#.#",
"#........#.#",
"######.###.#",
"#......#...#",
"############",
};
VS C++ gives me a warning message, saying that size is too small for such array. I guess it's because there must be also '\0' symbol in each line. How do I initialize char array without '\0' symbols? I don't want to initialize size with value 13 because it's will be too confused to use this constant for functions (printing array, making move etc.) Is there any way to do it?
Also, how to pass this array to function void mazeTraverse using pointer?
int main()
{
mazetraverse(maze)
}
void mazeTraverse(char (*maze)[ size ])
Such code doesn't works...
You need to account for the NULL character at the end of the string:
char maze[size][size + 1] = { /* */ };
Alternatively, for more flexibility, you can do:
char *maze[size] = { /* */ };
I see you're using C++. Is there any reason you're not using std::string?
std::string maze[size] = { /* */ };
It's a lot more flexible; now you just change the prototype to:
void mazeTraverse(std::string maze[]);
If you're even more insane, you'll use std::vector<std::string>.
EDIT: I recommend learning a bit about std::string. It works just like a char* but you don't have to manually allocate it/etc. For example:
std::string mystring = "lol";
mystring = "lololol"; // perfectly legal!
std::cout << mystring[0] << "\n";
// Or: printf("%c\n", mystring[0]);
char* sz[8];
strcpy(sz, mystring[0].c_str());
// And so on...
So long as you're using C++, why not just make a simple class?:
class Maze {
public:
Maze(int width, const std::string& data)
:width_(width),
data_(data.begin(), data.end()) {
}
char operator()(int row, int column) const {
return data_[width_*row + column];
}
private:
int width_;
std::vector<char> data_;
};
You can initialize it easily by taking advantage of the fact that subsequent string literals, like "foo" "bar", are implicitly concatenated into "foobar":
Maze my_maze(12,
"############"
"#...#......#"
"..#.#.####.#"
"###.#....#.#"
"#....###.#.."
"####.#.#.#.#"
"#..#.#.#.#.#"
"##.#.#.#.#.#"
"#........#.#"
"######.###.#"
"#......#...#"
"############");
To initialize, I would:
char* maze[ size ] = {
"############",
"#...#......#",
"..#.#.####.#",
"###.#....#.#",
"#....###.#..",
"####.#.#.#.#",
"#..#.#.#.#.#",
"##.#.#.#.#.#",
"#........#.#",
"######.###.#",
"#......#...#",
"############",
};
To pass parameters you should be able to use char**. So that would be:
void mazeTraverse(char ** param)
"Doesn't works"? The code does work. And it works perfectly fine. (Assuming the compiler lets you to use those 13-character string literals to initialize arrays of size 12. This is actually an error in C++, but you said that you are getting a mere warning).
This
mazeTraverse(maze);
will compile and do exactly what you want it to do (the way I understand it). What exactly doesn't work in your case? "Doesn't work" is not exactly a meaningful description of the problem.
As for getting rid of the warning in the array initialization, if you insist on having the array of exact size, you'll have to initialize it in per-character fashion as in
char maze[ size ][ size ] = {
{ '#', '#', '#', ... },
{ ... },
// and so on
};
If you want to use string literals, then as you noted yourself, you have to declare the inner sub-arrays with bigger size
char maze[ size ][ size + 1 ] = {
"############",
// and so on
};
and change the function declaration accordingly
void mazeTraverse(char (*maze)[ size + 1 ])
I am passing an array to a function, and i am initializing it globally with some values.
I am using empty string in end of array to determine the array length.
Now, Is there some way to automatically initialize the array to have extra empty item in the end of it, so i have no chances to forget it from there? Just like the char[] works, it adds extra null to the end IIRC.
Here is my code what im using now:
struct twostrings {
string s1, s2;
};
twostrings options[] = {
{"text1", "more text1"},
{"text2", "more text2"},
{"text3", "more text3"},
{""}, // tells that the array ends here
}
int get_len(twostrings opt[]){
int p = 0;
while(1){
if(opt[p].s1 == ""){
return p;
}
p++;
// now here is a possibility to go in infinite loop if i forgot the empty string.
// currently i have a code here that checks if p > 10000 and gives error message to me if i manage to forget that empty string in accident.
}
return p;
}
void dosomething(twostrings options[]){
int len = get_len(options);
for(int p = 0; p < len; p++){
// do stuff
}
}
int main(){ // yes its not valid written main function. dont bother about it.
dosomething(options);
}
Passing around C arrays is not very idiomatic in C++. Try using a std::vector instead:
#include <vector>
#include <string>
struct twostrings {
std::string s1, s2;
};
typedef std::vector<twostrings> option_type;
twostrings options[] = {
{"text1", "more text1"},
{"text2", "more text2"},
{"text3", "more text3"}
};
int get_len(const option_type& options){
return options.size();
}
void dosomething(const option_type& options){
int len = get_len(options);
for(int p = 0; p < len; p++){
// do stuff
}
}
int main() { // This main function is perfectly fine!
option_type opt_vector(options, options + (sizeof options / sizeof options[0]));
dosomething(opt_vector);
}
Unforunately, you're not correct. The char array does not end automatically in a null, this is only a side effect of assigning it with a string literal (which has the automatic null at the end).
char x[] = "ABC"; // size 4, contains A, B, C, \0.
char x[] = {'A','B','C'}; // size 3, contains no terminating null.
So the short answer is no, there's no way to automatically end arrays with an automatic entry. There are a bunch of other options though, such as STL vectors which have other means of determining when you've reached the end. In C++0x there'll probably (IIRC) be a way to initialize the vector just like you'd like.
HTH.
EDIT:
Personally, I prefer to add the extra 0 at the end of the array myself, but I suppose there are ways to work around it using macros.
#define ARRAY(...) {__VA_ARGS__, {0}}
and use it like so
struct foo { char* x; char* y; }
struct foo x[] = ARRAY({"abc", "xyz"}, {"def","uvw"});
I have no idea if this works (and I have no preprocessor handy), and as I said, personally I don't like it. It also requires the first element in the struct to be something which can be assigned 0 to mark the end of the array.
Of course, this forces you to remember to wrap it in the macro call, which is pretty much as bad as forcing you to remember to terminate the array.
EDIT:
I just had a chance to test this and it works. Turns out variadic macros are, so far anyway, C only. However some (most?) C++ compilers support them anyway, a quick search turned up g++ and visual studio. Still I wouldn't favor this approach, I just added it for completeness.
Pass the length or the end instead of using a sentinel:
template<class T, int N>
int len(T (&)[N]) { // exists in a more general form as boost::size
return N;
}
typedef std::pair<std::string, std::string> twostrings;
// std::pairs have first and second members of the given types
void dosomething(twostrings options[], int size);
// call as: dosomething(array, len(array));
# or:
template<class T, int N>
T* end(T (&a)[N]) { // exists in a more general form as boost::end
return a + N;
}
void dosomething(twostrings* options_begin, twooptions* options_end);
// call as: dosomething(array, end(array));
// usage example:
void dosomething(twostrings* options_begin, twooptions* options_end) {
// you might name the parameters just 'begin' and 'end'
for (; options_begin != options_end; ++options_begin) {
// the 'begin' var advances through the entire sequence
// use for (twostrings* current = options_begin; current != options_end; ++current)
// if a separate copy is required
cout << options_begin->first << ": " << options_begin->second << '\n';
}
}
Note the [begin, end) iterator pattern (that's inclusive begin, exclusive end) is common in the stdlib (e.g. look at std::sort from <algorithm>).
This is a good halfway measure between arrays and containers such as std::vector, and allows you to keep the easy initialization syntax you have now (C++0x gives you that same syntax with containers such as std::vector, but 0x is not quite yet ready).
Don't use C style arrays in C++, they're just not worth the effort compared to vector.size(). You should use a boost::array<twostrings, length> for a static array.
Hell, you should probably just not use a static value.
There are better ways of finding array lengths. You can use:
1. sizeof(options) / sizeof(twostrings);
2. sizeof(options) / sizeof(options[0]);
3. std::vector<twostrings> options;
options.size();
4. ARRAYSIZE(options); (windows only)
Btw, if(opt[p].s1 == "") is checking 2 const char * pointers for equality, not 2 strings. Although compiller usualy optimizes equal string constants to point to one place, it is still an error.
You should use a NULL sentinell as it was adviced by Svisstack earlier.
edit: Proof
#include <stdio.h>
const char *one = "the string";
void main(){
const char *other = "the string";
printf("adress of 'one' = %x, it contains \"%s\"\n", one, one);
printf("adress of 'other' = %x, it contains \"%s\"\n", other, other);
if(one == other){
printf("one == other\n", one);
} else {
printf("one != other\n", one);
}
}
Output:
k:\temp>cl test.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86
/out:test.exe
test.obj
k:\temp>test.exe
adress of 'one' = 3d8140, it contains "the string"
adress of 'other' = 3d814c, it contains "the string"
one != other
How can we access variables of a structure? I have a struct:
typedef struct {
unsigned short a;
unsigned shout b;
} Display;
and in my other class I have a method:
int NewMethod(Display **display)
{
Display *disp=new Display();
*display = disp;
disp->a=11;
}
What does **display mean? To access variables of struct I have used ->, are there other methods too?
As Taylor said, the double asterisk is "pointer to pointer", you can have as many levels of pointers as you need.
As I'm sure you know, the arrow operator (a->b) is a shortcut for the asterisk that dereferences a pointer, and the dot that accesses a field, i.e.
a->b = (*a).b;
The parentheses are necessary since the dot binds tighter. There is no such operator for double asterisks, you have to first de-reference to get to the required level, before accessing the fields:
Display **dpl = ...;
(*dpl)->a = 42;
or
(**dpl).a = 42;
Think of it as *(*display). When you want to pass the address of an integer to a function so that you can set the integer, you use:
void setTo7 (int *x) {
*x = 7;
}
: : :
int a = 4;
setTo7 (&a);
// a is now 7.
It's no different from what you have except that you want to set the value of a pointer so you need to pass the pointer to that pointer. Simple, no?
Try this out:
#include <stdio.h>
#include <string.h>
static void setTo7 (int *x) { *x = 7; }
void appendToStr (char **str, char *app) {
// Allocate enough space for bigger string and NUL.
char *newstr = malloc (strlen(*str) + strlen (app) + 1);
// Only copy/append if malloc worked.
if (newstr != 0) {
strcpy (newstr, *str);
strcat (newstr, app);
}
// Free old string.
free (*str);
// Set string to new string with the magic of double pointers.
*str = newstr;
}
int main (void) {
int i = 2;
char *s = malloc(6); strcpy (s, "Hello");
setTo7 (&i); appendToStr (&s, ", world");
printf ("%d [%s]\n",i,s);
return 0;
}
The output is:
7 [Hello, world]
This will safely append one string value to another, allocating enough space. Double pointers are often used in intelligent memory allocation functions, less so in C++ since you have a native string type, but it's still useful for other pointers.
**display is just a double pointer (a pointer to a pointer of type Display).
The ** means that its a pointer-to-a-pointer. Basically it points to another pointer that then points to something else, in your case a Display structure.
If you called the function with only the object you can access the members with the . operator.
int NewMethod(Display display)
{
Display disp = display;
disp.a=11;
}
But this way you are not modifying directly the Display display object but a local copy. Your code suggests that the changes to the object are needed outside of the function so your only option is the one you described (well, maybe passing the argument by refference but the syntax then would more or less the same (->)).
Since disp is a Pointer you have to use ->
If you just have a "normal" variable (i.e. on the stack)
Display d;
you can write d.a
A struct is the same as a class. The only difference (I am aware of) is that all members are public by default.
You can do (*disp).a=11;
it is called dereferencing