Okay, this one has me stumped. I am trying to pass an array of character arrays into my class's constructor. The class has a private attribute which stores a pointer to the array of character arrays. The class may then process the array via the pointer.
Below is some code that demonstrates the desired functionality. But, it won't compile. How do I fix this code so it works?
using namespace std;
const int MAX_LINES = 10, MAX_STRING = 80;
class Alphabetizer{
public:
Alphabetizer(char * inArray[][MAX_STRING]) : input(inArray){};
private:
char * input[MAX_LINES][MAX_STRING];
};
int main(){
char charArray[MAX_LINES][MAX_STRING];
Alphabetizer theAlaphBet(charArray);
return 0;
}
If you're insisting on using C-compatible character pointers, I think you'll have the best luck using a char ** as the type for input. This is more of the usual way to do this (in C at least), and it has the added benefit of not forcing you to define a maximum string size.
As others have pointed out, you can take advantage of std::string instead, which may be a better choice overall.
I'm guessing it's that you're not passing a pointer to char[][], you're passing a char[][].
Also, you should be using std::string instead of char arrays.
std::string will be the most appropriate here! It handles strings and character arrays well enough!
There are few errors in the code. I suppose you are trying to refer to the charArray in the main function from inside the Alphabetizer object. If that is the case the declaration
char * input[MAX_LINES][MAX_STRING];
is wrong because the above declaration makes input an array of MAX_LINE of ( array of MAX_STRING of (char*)). In summary input is an array not a pointer to array of whatever. If you had intended it to be a pointer - which is what rest of your code hints to me - then you have to do the following,
const int MAX_LINES = 10, MAX_STRING = 80;
class Alphabetizer{
public:
Alphabetizer(char ((*ar)[MAX_LINES])[MAX_STRING]) : m_ar(ar){};
private:
char ((*m_ar)[10])[80];
};
int main(){
char charArray[MAX_LINES][MAX_STRING];
char ((*ar)[MAX_LINES])[MAX_STRING] = &charArray;
Alphabetizer theAlaphBet(&charArray);
return 0;
}
Moreover doing,
input(inArray)
is wrong, as it is equivalent to doing the following,
char a[1] = {'a'};
char b[1] = {'p'};
a = b;
assigning an array to another does not copy one over another. You have to do explicit memcpy. (This semantics is not meaningful in c or c++)
It's difficult to tell without seeing the compile errors, but I think the problem might be this line:
Alphabetizer theAlaphBet(charArray);
You are passing the array directly rather than it's address. It should read:
Alphabetizer theAlaphBet( &charArray );
However I think you may be overcomplicating things. You might be better off using a reference rather than a pointer:
const int MAX_LINES = 10, MAX_STRING = 80;
class Alphabetizer{
public:
Alphabetizer(char & inArray[][MAX_STRING]) : input(inArray){};
private:
char & input[MAX_LINES][MAX_STRING];
};
int main(){
char charArray[MAX_LINES][MAX_STRING];
Alphabetizer theAlaphBet(charArray);
return 0;
}
You might also want to look into using std::string instead as this may help to simplify your code.
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 have got a very strange problem.
Here is my code:
Header File
namespace test
{
class LoadConfigData
{
struct control_params
{
char active[];
char suspended[];
char erased[];
}*ctrl_params;
bool loadConfig();
};
};
Main.cpp
using namespace std;
using namespace test;
namespace test
{
extern LoadConfigData *loadConfigDataobj;
LoadConfigData *loadConfigDataobj = new LoadConfigData;
};
int main()
{
loadConfigDataobj->loadConfig();
cout <<loadConfigDataobj->ctrl_params->active_status_code_v<<endl;
cout <<loadConfigDataobj->ctrl_params->suspended_status_code_v<<endl;
cout <<loadConfigDataobj->ctrl_params->erase_status_code_v<<endl;
return 0;
}
bool LoadConfigData::loadConfig()
{
std::string a = "AC";
std::string b = "SP";
std::string c = "ER";
LoadConfigData::ctrl_params = new LoadConfigData::control_params;
sprintf(loadConfigDataobj->ctrl_params->active,"%s",a.c_str());
sprintf(loadConfigDataobj->ctrl_params->suspended,"%s",b.c_str());
sprintf(loadConfigDataobj->ctrl_params->erased,"%s",c.c_str());
return true;
}
Output:
ER
ER
ER
Which means that it's printing the last copied string for each struct member.
What is wrong in my code.
The problem is that you don't give the character arrays a size:
struct control_params
{
char active[];
char suspended[];
char erased[];
}*ctrl_params;
I'm rather surprised that this compiles; my understanding was that an unsized array was an incomplete type, and so couldn't be a non-static class member. However, my compiler at least (and presumably yours) treats these as arrays of size zero, all at the same location in memory. Therefore, each time you write to one it overwrites whatever you wrote to the others. (Of course, the behaviour is undefined since it writes outside the array bounds).
The simplest solution is to use std::string to represent the strings. That will manage its size automatically, and you can simply write active = a rather than messing around with sprintf (or, slightly more sensibly, strncpy) and hoping you don't get a buffer overrun.
The problem is your usage of sprintf. sprintf will not allocate any memory for you, active, suspended and erased are pointing to strange and undefined addresses. You are invoking undefined behaviour.
Without adding all the normally necessary detail, use std::string and it's operator overloads instead. For simple parsing, use streams. For now, totally avoid any C-string-function, and instead use C++ solely.
I was wondering if someone could help me understand how to securely pass a static unsigned char array from one class to another. My apologies if this is trivial but I wanted to be sure I do it right.
for example
// First Class
unsigned char data[1024];
TMainClass::TMainClass()
{
data[34] = 1;
data[45] = 65;
...
TOtherClass obj(data);
};
// Second class
static unsigned char obtainedData[1024];
TOtherClass::TOtherClass(unsigned char* _data)
{
obtainedData = _data;
};
You really should be using an stl or boost container. If, however, you have a good reason not to, then ...
You're passing it just fine, but the assignment is wrong.
obtainedData = _data;
You should really either copy the data
memcpy(obtainedData, _data, 1024);
std::copy(_data, _data+1024, obtainedData) // Thanks #Grizzly
or redefine the obtainedData variable
static unsigned char* obtainedData;
Notes:
Be sure you think about the size of the arrays you're passing and copying to. Are they guaranteed to be the same size?
What do you mean by "securely" or "safely"?
Your types are wrong ( you don't assign 1 array to another like that).
And this is c++ so really what you should probably be doing is using a std::string or std::vector or even if you need a fixed buffer std::array
I am a bit confused. There are two ways to return an array from a method. The first suggests the following:
typedef int arrT[10];
arrT *func(int i);
However, how do I capture the return which is an int (*)[]?
Another way is through a reference or pointer:
int (*func(int i)[10];
or
int (&func(int i)[10];
The return types are either int (*)[] or int (&)[].
The trouble I am having is how I can assign a variable to accept the point and I continue to get errors such as:
can't convert int* to int (*)[]
Any idea what I am doing wrong or what is lacking in my knowledge?
If you want to return an array by value, put it in a structure.
The Standard committee already did that, and thus you can use std::array<int,10>.
std::array<int,10> func(int i);
std::array<int,10> x = func(77);
This makes it very straightforward to return by reference also:
std::array<int,10>& func2(int i);
std::array<int,10>& y = func2(5);
First, the information you give is incorrect.
You write,
“There are two ways to return an array from a method”
and then you give as examples of the ways
typedef int arrT[10];
arrT *func(int i);
and
int (*func(int i))[10];
(I’ve added the missing right parenthesis), where you say that this latter way, in contrast to the first, is an example of
“through a reference or pointer”
Well, these two declarations mean exactly the same, to wit:
typedef int A[10];
A* fp1( int i ) { return 0; }
int (*fp2( int i ))[10] { return 0; }
int main()
{
int (*p1)[10] = fp1( 100 );
int (*p2)[10] = fp2( 200 );
}
In both cases a pointer to the array is returned, and this pointer is typed as "pointer to array". Dereferencing that pointer yields the array itself, which decays to a pointer to itself again, but now typed as "pointer to item". It’s a pointer to the first item of the array. At the machine code level these two pointers are, in practice, exactly the same. Coming from a Pascal background that confused me for a long time, but the upshot is, since it’s generally impractical to carry the array size along in the type (which precludes dealing with arrays of different runtime sizes), most array handling code deals with the pointer-to-first-item instead of the pointer-to-the-whole-array.
I.e., normally such a low level C language like function would be declared as just
int* func()
return a pointer to the first item of an array of size established at run time.
Now, if you want to return an array by value then you have two choices:
Returning a fixed size array by value: put it in a struct.
The standard already provides a templated class that does this, std::array.
Returning a variable size array by value: use a class that deals with copying.
The standard already provides a templated class that does this, std::vector.
For example,
#include <vector>
using namespace std;
vector<int> foo() { return vector<int>( 10 ); }
int main()
{
vector<int> const v = foo();
// ...
}
This is the most general. Using std::array is more of an optimization for special cases. As a beginner, keep in mind Donald Knuth’s advice: “Premature optimization is the root of all evil.” I.e., just use std::vector unless there is a really really good reason to use std::array.
using arrT10 = int[10]; // Or you can use typedef if you want
arrT10 * func(int i)
{
arrT10 a10;
return &a10;
// int a[10];
// return a; // ERROR: can't convert int* to int (*)[]
}
This will give you a warning because func returns an address of a local variable so we should NEVER code like this but I'm sure this code can help you.
I am trying to use XCode for my project and have this code in my .h:
class FileReader
{
private:
int numberOfNodes;
int startingNode;
int numberOfTerminalNodes;
int terminalNode[];
int numberOfTransitions;
int transitions[];
public:
FileReader();
~FileReader();
};
I get a "Field has incomplete type int[]" error on the terminalNode line... but not on the transitions line. What could be going on? I'm SURE that's the correct syntax?
Strictly speaking the size of an array is part of its type, and an array must have a (greater than zero) size.
There's an extension that allows an array of indeterminate size as the last element of a class. This is used to conveniently access a variable sized array as the last element of a struct.
struct S {
int size;
int data[];
};
S *make_s(int size) {
S *s = (S*)malloc(sizeof(S) + sizeof(int)*size);
s->size = size;
return s;
}
int main() {
S *s = make_s(4);
for (int i=0;i<s->size;++i)
s->data[i] = i;
free(s);
}
This code is unfortunately not valid C++, but it is valid C (C99 or C11). If you've inherited this from some C project, you may be surprised that this works there but not in C++. But the truth of the matter is that you can't have zero-length arrays (which is what the incomplete array int transitions[] is in this context) in C++.
Use a std::vector<int> instead. Or a std::unique_ptr<int[]>.
(Or, if you're really really really fussy about not having two separate memory allocations, you can write your own wrapper class which allocates one single piece of memory and in-place constructs both the preamble and the array. But that's excessive.)
The original C use would have been something like:
FileReader * p = malloc(sizeof(FileReader) + N * sizeof(int));
Then you could have used p->transitions[i], for i in [0, N).
Such a construction obviously doesn't make sense in the object model of C++ (think constructors and exceptions).
You can't put an unbound array length in a header -- there is no way for the compiler to know the class size, thus it can never be instantiated.
Its likely that the lack of error on the transitions line is a result of handling the first error. That is, if you comment out terminalNode, transitions should give the error.
It isn't. If you're inside a struct definition, the compiler needs to know the size of the struct, so it also needs to know the size of all its elements. Because int [] means an array of ints of any length, its size is unknown. Either use a fixed-size array (int field[128];) or a pointer that you'll use to malloc memory (int *field;).