How to create a constructor which takes in a char array? - c++

I have a class, which take in a char array of size specified by a constexpr.
Message.h:
constexpr size_t InputBufferSize = 32;
class Message
{
private:
char input[InputBufferSize];
int size;
public:
//constructor
Message(char input[], int size);
//deconstructor
~Message();
int getSize();
};
I'm confused by how to define the constructor, and then create a new instance of that class using the constructor due to the char array. Here is my try (out of a few things I tried):
Message.cpp:
#include "Message.h"
Message::Message(char input[], int size) {
this->input[InputBufferSize] = input[];
this->size = size;
}
Message::~Message() { }
int Message::getSize() {
return size;
}
main.cpp:
#include <iostream>
#include "Message.h"
int main()
{
char charinp;
char input[InputBufferSize] = { 'a','b','c','d','e','f' };
Message ms1(input[], 1);
std::cout << ms1.getSize() << std::endl;
std::cin >> charinp;
return 0;
}
I'd like to create a constructor with an array as on of its parameters, where the array already has a set size, and then create an object from that. The array to be passed into the object will always be of the same size, which is the size of the array the constructor is set to take in.

Message(char input[], int size);
The use of [] in a parameter declaration is just syntax sugar, the compiler will interpret char input[] as char* input instead.
this->input[InputBufferSize] = input[];
This is not legal code. You need to use (std::)memcpy() or std::copy()/std::copy_n() to copy an array to another array:
memcpy(this->input, input, size);
std::copy(input, input + size, this->input);
std::copy_n(input, size, this->input);
On a side note, you should make sure that size does not exceed InputBufferSize before copying the input array:
size = std::min(size, InputBufferSize);
Message ms1(input[], 6);
This is also not legal code. You need to drop the [] when passing the array to a parameter:
Message ms1(input, 6);
std::cin >> charinp;
On a side note, you can use std::cin.get() instead, and remove charinp from your code (since you don't use it anyway).

You are using Message ms1(input[], 6); in your main function,try changing it to Message ms1(input, 6);.
The reason for this is that you have already declared the array char input[] and you have to refer it as inputafter you have declared it not input[].

Related

How to initialize C-style char array and int array via member initialization list through constructor?

Code-1
#include <iostream>
#include <cstring>
class A
{
private:
int p[5];
char str[20];
public:
A(int *q, char *s)
{
for(int i=0; i<=4; i++)
{
p[i]=*q;
q++;
}
strcpy(str,s);
}
};
int main()
{
int r[5]={2, 3, 5, 7, 11};
char ch[]="bonaparte";
A a1(r, ch);
return 0;
}
Output ( Runs smoothly but just gives warning )
Clang-Tidy: Constructor does not initialize
these fields: p, str
Why this warning is coming. I know that I am assigning in constructor not initializing but When I create simple class which just have int type variable and If I assign that in this same way it didn't give such warning ?
Code-2
#include <iostream>
#include <cstring>
class A
{
private:
int p[5];
char str[20];
public:
A(int *q, char *s): // just not getting how we can do this initialization
{
}
};
int main()
{
int r[5]={2, 3, 5, 7, 11};
char ch[]="bonaparte";
A a1(r, ch);
return 0;
}
Is there any way to initialize int type or C-style char array via member initialization list through constructor.
I know that I can replace char array with string but I want to know a way for C-style char array.
Arrays in C++ are not the friendliest bit of the language.
Specialy not when you let them decay to pointers (size information is lost).
So I prefer to use std::array, std::vector and std::string since these standard library classes help you prevent all sort of memory bugs.
About your initialization question, yes you can only assign in the body of the constructor. This is another reason I like std::array/std::vector better you can use them in the initializer. I also consider ::strcpy to be a left over from 'C' not to be used anymore in current C++. Have fun learning more C++ :)
#include <iostream>
//#include <cstring> // <== don't use this. (If you want to use strings in C++ use <string>
#include <vector>
#include <string>
// try to learn not to use what is called
// "magic numbers" in your source code!
// define numbers you are going to use
//
const std::size_t int_array_size = 5;
const std::size_t string_array_size = 20;
// we don't know the length of the string yet, but we can let
// the compiler figure it out and we make a templated constructor
class A
{
public:
// pass arrays in by const, you're not supposed to
// change their content.
A(const int (&p)[int_array_size], const char (&str)[string_array_size])
{
// I always use std::size_t for indices in arrays (not supposed to be <0)
for (/*int*/ std::size_t i = 0; i < int_array_size; i++) m_p[i] = p[i];
// don't use ::strcpy it's not "safe". It depends on correct input
// like the string having a trailing 0
for (std::size_t i = 0; i < string_array_size; i++) m_str[i] = str[i];
}
private:
int m_p[int_array_size];
char m_str[string_array_size];
};
// this is one way I would code it.
// using C++ with variable length array (so I use std::vector, for fixed length use std::array)
class B
{
public:
B(const std::vector<int>& p, const std::string& str) :
m_p{ p },
m_str{ str }
{
}
private:
std::vector<int> m_p; // or std::array<int,int_array_size>
std::string m_str;
};
int main()
{
// I prefer to use aggregate initialization (https://en.cppreference.com/w/cpp/language/aggregate_initialization)
int r[int_array_size]{ 2, 3, 5, 7, 11 };
// The next line is defined behavior. C++ standard says all remaining
// values of ch after bonaparte will be 0
char ch[string_array_size]{ "bonaparte" };
A a1(r, ch);
B b1{ {1,2,3}, "hello world!" };
return 0;
}

How to initialize dynamicly array from struct C++

I have an assignment to write a function that dynamicly initialize an array from struct that is in the header file. and for some resone I am keep getting the same error "uninitialized local variable 'columnData' used
this is the header file
#ifndef QUEUE_H
#define QUEUE_H
/* a queue contains positive integer values. */
typedef struct queue
{
int arraySize;
int* column;
} queue;
void initQueue(queue* q, unsigned int size);
void cleanQueue(queue* q);
void enqueue(queue* q, unsigned int newValue);
int dequeue(queue* q); // return element in top of queue, or -1 if empty
#endif /* QUEUE_H */
this is my code:
#include <iostream>
#include "queue.h"
int main()
{
queue* columnData;
unsigned int size = 0;
std::cout << "Please enter column size: ";
std::cin >> size;
initQueue(columnData, size);
printf("%d", &columnData->column[0]);
}
void initQueue(queue* q, unsigned int size) {
q->column = new int[size];
q->column[0] = 5;
}
void cleanQueue(queue* q) {
}
void enqueue(queue* q, unsigned int newValue) {
}
int dequeue(queue* q) {
return 1;
}
If someone can help me it will be great.
You declared an uninitialized pointer
queue* columnData;
that has an indeterminate value. So calling the function initQueue
initQueue(columnData, size);
invokes undefined behavior because within the function this pointer is dereferenced.
q->column = new int[size];
q->column[0] = 5;
Also the function does not set the data member arraySize.
You need in main to declare an object of the type queue
queue columnData;
and call the function like
initQueue( &columnData, size);
and within the function you have to set also the data member arraySize like
columnData->arraySize = size;
Pay attention to that this call
printf("%d", &columnData->column[0]);
is also wrong. You are trying to output a pointer using the incorrect conversion specifier %d.
After changing the declaration of the object columnData shown above the call of printf will look like
printf("%d", columnData.column[0]);
Though it will be more consistent to use the overloaded operator <<.

C++ pass const char* pointer array to object

Dear StackOverFlowers,
I'm having trouble passing a const char* [] to an object. The scenario is as follows.
I have a class UlamScreen which contains a const char* [] with several strings. UlamScreen also contains an object homeScreenMenu.
class UlamScreen {
const char* homeScreenText[5] = {"EVA dun", "Sabine", "TPU dun", "test Wout",
UlamScreenMenu homeScreenMenu;
};
class UlamScreenMenu {
private:
const char* _menuText[];
public:
UlamScreenMenu(const char*[]);
void drawMenu();
};
I want to pass the const char* [] to UlamScreenMenu so I can use it in a member function called void drawMenu, like this:
void UlamScreenMenu::drawMenu() {
for (int i = 0; i < menuItems; i++) {
tft.println(_menuText[i]);
}
}
I passed it to UlamScreenMenu's constructor like this:
UlamScreen::UlamScreen() : homeScreenMenu(homeScreenText) {
}
UlamScreenMenu::UlamScreenMenu(const char* menuText[], int length) {
for(int i = 0; i < length; i++) {
_menuText[i] = menuText[i];
}
}
I thought this would work, but for some reason, it does not. tft.println(_menuText[i]); used with void drawMenu does not send anything to my tft screen. When I use tft.println(_menuText[i]); from within the UlamScreen class it works perfectly.
Just to be clear, I can use the tft object within the UlamScreenMenu class because other functions like tft.drawRect() are working correctly.
What is wrong with this way of passing the const char* []? Thanks in advance.
In C++, you can't declare a member variable of type const char* x[], since this would denote a flexible array member. Flexible array members are a C-feature allowing the last member of a struct to be an array of varying size (cf., for example, Arrays of unknown size / flexible array members). Having parameters of type const char* x[] in functions, however, is supported and has basically the same meaning as const char** x.
If you stick to a member of type const char**, then you'll have to handle memory management in that class. This means: take care of allocating, deallocating, copying, moving, copy-assigning, and move-assigning objets of that class (cf, for example, the rule of 0/3/5).
If - as suggested in the comments - you use standard library collections, e.g. std::vector, these classes will do all this stuff in a reliable manner for you. See the following example illustrating the difference between both:
Note that the C++-version probably would not even take a const char*[]-parameter but directly a const std::vector<const char*> &x-parameter. But I kept the const char*[]-parameter in the constructor to provide the same interface in both variants:
// Variant 1: "old" C-style:
class Menu {
public:
Menu(const char* x[], int length) {
m_x = new const char*[length];
m_length = length;
for (int i=0; i<length; i++) {
m_x[i] = x[i];
}
}
~Menu() {
delete[] m_x;
}
// TODO: implement copy- and move constructors + copy- and move assignments
// ...
void print() {
for (int i=0; i<m_length; i++) {
std::cout << m_x[i] << std::endl;
}
}
private:
const char** m_x = nullptr;
int m_length;
};
#include <vector>
// Variant 2: a C++- way:
class Menu2 {
public:
Menu2(const char* x[], int length) {
m_x.assign(x, x+length);
}
void print() {
for (auto s : m_x) {
std::cout << s << std::endl;
}
}
// Menu2 does not manage memory on its own, hence:
// No special copy/move - constructors/assignments to be implemented.
// No special destructor necessary
private:
std::vector<const char*> m_x;
};
int main() {
const char* x1[3] = {"one","two","three" };
const char* x2[2] = {"eins","zwei" };
// Variant 1
Menu m1(x1, 3);
m1.print();
// Variant 2
Menu2 m2(x2, 2);
m2.print();
}

How to pass the name of a member from a struct as an argument into a function using C++?

I have exhausted my patience trying to find this particular question .
I am trying to input the name of a particular member from a structure into a function.
My first thought was that this is impossible because a function's arguments needs to be a variable declared and defined in RAM. Yet the computer is able to interpret the location of a "member" for each instance given the members name.
The following is a arbitrary program where I created an array of structures and the program will some how input all of the data for each member in the structure for each instance in the array. It will then attempt to display all of the content for a particular member in the array. It is incomplete because I don't know how to make it work.
#include theUsual
// global variables
const int SIZE = 10;
// structures
struct structureExample
{
dataType member1;
dataType member2;
...
};
// functions
void inputData(structureExample s[], int size);
void displayMember( dataType member, structureExample s[], int size);
int main
{
structureExample sE[SIZE];
dataType memberName = member1 // member1 from the declared struct structureExample
inputData(sE,SIZE);
displayMember(memberName, sE, SIZE);
system("PAUSE");
return 0;
}
// inputs all the data for all members in an array of structure examples
void inputData(structureExample s[], int size)
{
...
}
// display's all of the content of a particular member from an array
void displayMember( dataType member, structureExample s[], int size)
{
for (int i = 0; i<size; i++)
{
cout << s[i].member << endl;
}
}
So given any member name from structureExample into displayMember, it will display the all of the content of that member for every unit in the array.
I have allot of questions about this but the biggest two are, can this even work? If so how could I make this work? Examples would be appreciated.
Thanks in advance!
It seems you want pointer on member:
struct structureExample
{
int member1;
float member2;
};
template<typename M>
void displayMember(M structureExample::*member, structureExample s[], int size)
{
for (int i = 0; i < size; i++)
{
std::cout << s[i].*member << std::endl;
}
}
int main()
{
structureExample sE[SIZE];
auto member = &structureExample::member1;
inputData(sE,SIZE);
displayMember(member, sE, SIZE);
}
Variable names, parameter names, member names, these are all lost during the compiling process, they are translated into memory address offsets. There are no actual names at runtime.
What you are asking for is not possible in C++. You will have to implement your own lookup logic, such as with a std::map, if you need to access values by names determined at runtime, eg:
#include theUsual
#include <map>
#include <string>
// global variables
const int SIZE = 10;
// structures
struct structureExample
{
std::map<std::string, dataType> values;
};
// functions
void inputData(structureExample s[], int size);
void displayMember(const std:string &valueName, structureExample s[], int size);
int main
{
structureExample sE[SIZE];
inputData(sE, SIZE);
displayMember("valueName", sE, SIZE);
system("PAUSE");
return 0;
}
// inputs all the data for all members in an array of structure examples
void inputData(structureExample s[], int size)
{
for (int i = 0; i < size; ++i)
{
...
s[i].values["valueName"] = ...;
...
}
}
// display's all of the content of a particular member from an array
void displayMember(const std::string &valueName, structureExample s[], int size)
{
for (int i = 0; i < size; ++i)
{
std::cout << s[i].values[valueName] << std::endl;
}
}

beginner question about arrays in structs in C++

I would like to create a struct and use it inside an other struct as an array. My problem is that I don't know how big array I would like to allocate, I will only know once I am in a function. I mean I would like to use [] instead of a pre-determined constant, like 10000.
I think if you look at my code it would be self-explanatory. Can you help me how to make this code work? Moreover it would help me a lot if you could tell me what is the name of the topic I am asking about (is it dynamic arrays?) and that where can I find articles/tutorials about this topic.
Here is the code with my broken way of thinking about arrays in structs.
#include <iostream>
using namespace std;
struct keyframe {
bool a;
int b;
int c;
};
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe keyframes[];
};
int main() {
keyframe_file my_file;
my_file.num_views = 1;
my_file.num_keyframes = 6;
my_file.keyframes = new keyframe[my_file.num_keyframes];
my_file.keyframes[0].a = true;
my_file.keyframes[0].b = 5;
my_file.keyframes[0].c = 9;
return 0;
}
Use a std::vector.
struct keyframe_file {
const int num_views;
const int num_keyframes;
std::vector<keyframe> keyframes;
};
int main() {
keyframe_file frame;
frame.keyframes.resize(...);
}
If it suits your purpose, an STL container (std::vector) is easily one of the best options - the less memory management you have to worry about, the better.
In any case, look at the struct definition Nawaz posted above - that's exactly how it should be. Dynamic arrays in C++ are simply pointers. You have, however, allocated the memory properly in your code, but you haven't freed it (so it's leaking). Since you allocated with new [] you will need to
delete [] my_file.keyframes;
in order to free the memory properly.
Resizing is another issue: with a smart implementation, array resizing can be an amortized O(1) operation which is nice. When you resize, it will always take you O(n) since you need to copy all the elements into a new array of different size, but if you do it half as much, it becomes O(1). That is, double the array each time you need to resize. Here is a very quick example
void resize()
{
if(numOfElementsInArray == sizeOfArray)
{
ArrayType * arr = new ArrayType[sizeOfArray*2]; // Allocate a double size array
for(int i=0;i<sizeOfArray;++i)
currentArray[i] = arr[i];
delete [] currentArray; // Free memory in old array
currentArray = arr; // Set the array to our new one
sizeOfArray *= 2; // Double the size
}
}
NOTE: The example above does not take into account space complexity; that said, if you have 5000 elements, and remove all but 5, this method with not shrink it (which is probably what you will want to do for all practical purposes)
Your code appears to be almost correct, except for two things:
keyframes needs to be a keyframe* rather than a keyframe[]
You forgot to delete the memory you allocated
That is incomplete type. In C++, array must be provided with size, and the size must be known at compile time itself.
You're using new, with which you should be using pointer.
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe *keyframes;
};
But std::vector<keyframe> is still a better choice, as #DeadMG already suggested.
By the way, the first two members are const in the struct, that means, they cannot be assigned value, as you're doing in your code. They must be initialized with values you want them to hold. That implies, now with vector, you've to include a constructor, to initialize the struct, as the struct is no more a POD.
struct keyframe_file {
const int num_views; //const member
const int num_keyframes; //const member
std::vector<keyframe> keyframes;
keyframe_file(int nviews, int nkeyframes)
: num_views(nviews), num_keyframes(nkeyframes), keyframes(nkeyframes){}
};
keyframe_file my_file(1,6); //done!
The suggested "Vector" is they safest way to do it.
But if it is only about making your code work (without resizing and stuff) the following should be working:
#include <iostream>
using namespace std;
struct keyframe {
bool a;
int b;
int c;
};
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe* keyframes;
};
int main()
{
keyframe_file my_file = {1, 6}; // initialization needed bcause of 'const int'
my_file.keyframes = new keyframe[my_file.num_keyframes];
for (int i = 0; i < my_file.num_keyframes; i++)
{
my_file.keyframes[i].a = true;
my_file.keyframes[i].b = 5 + i;
my_file.keyframes[i].c = 9 - i;
}
return 0;
}
somewhere in your code, when you are done using the array you have to call delete [] my_file.keyframes; as already mentioned.
There's a basic rule when using dynamic arrays in c++, especially when using it inside structs or classes, and it's to delete what you no longer need.
If you want to make your struct dynamic, it's easy, just replace the [] with * and the array will become dynamic, but it's not over yet, there is a lot of work.
You have to construct the array and destory it, and destoroying it is possible and useful noly with destructors, like this:
struct keyframe_file
{
const int num_views;
const int num_keyframes;
keyframe* keyframes;
~keyframe_file() // this is the destructor
{
delete[] keyframes;
}
};
Yet even that code isn't going to work at all, since you are assigning values to constants in variable my_file after creating it, it's illegal in c++, you should then use classes instead.
Using classes with dynamic arrays is very easy and interesting and makes your code very good, you don't have to know too much to do that, just learn what is a constructor, an initializer, destructor, private and public and go on with the following code:
#include <iostream>
using namespace std;
struct keyframe
{
bool a;
int b,c;
};
class keyframe_file
{
public:
keyframe_file(int NV, int NKF):num_keyframes(NKF),num_views(NV)
{
keyframes = new keyframe[num_keyframes];
}
~keyframe_file()
{
delete[] keyframes;
}
private:
const int num_views;
const int num_keyframes;
keyframe* keyframes;
};
int main()
{
keyframe_file my_file(1,6);
return 0;
}
This code works very well, it allows you to assign value to the constants num_views and num_keyframes for one time when creating the object (variable) my_file.
Remember, you are a C++ programmer, be proud of that, and use classes instead of structs and dynamic arrays instead of static ones.
Hope that's useful.
Use pointers and apply to your structure!
int *p;
p = new int;
#include <iostream>
using namespace std;
struct keyframe {
bool a;
int b;
int c;
};
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe *keyframes;
};
int main() {
keyframe_file my_file;
my_file.num_views = 1;
my_file.num_keyframes = 6;
for (int i = 0; i < my_file.num_keyframes; i++){
my_file.keyframes = new keyframe; //<---
}
my_file.keyframes[0].a = true;
my_file.keyframes[0].b = 5;
my_file.keyframes[0].c = 9;
return 0;
}