I have a class that stores data and within the class I have an array called 'position' that stores strings of 2 characters. Unfortunately, the amount of 2 character strings it should hold will vary:
class shipStatus
{
public:
char* name;
int x{};
char position[x][2]; // does not work
void setInfo(char name[], int x);
void displayStatus();
};
The setInfo function assigns a numerical value to x, which varies among objects. I would like the value of x to also dictate the length of the character array 'position'.
For example:
if x = 3 then
char position[3][2]; // the length of the second array is always 2
How can I make my code do this? If I try adding a variable as the parameters my code does not compile.
Here is my setInfo function:
void shipStatus::setInfo(char name[], int x)
{
name = name;
x = x;
}
Since this is C++, you should use the C++ facilities that are available to you. In your case, it would be std::string, std::vector, and std::array.
Below is an example using basically what your original shipStatus structure consisted of, and changing it to using the above mentioned constructs:
#include <string>
#include <array>
#include <vector>
#include <iostream>
class shipStatus
{
std::string name; // <-- Replaced char*
std::vector<std::array<char, 2>> position; // <-- A vector of an array that has a size of 2
public:
void setInfo(std::string n, int x);
void displayStatus();
void setPosition(size_t whichItem, char c1, char c2);
size_t getNumPositions() const;
};
void shipStatus::setInfo(std::string n, int x)
{
name = n;
position.resize(x); // <-- All we need to do is resize() to dynamically resize the vector
}
void shipStatus::displayStatus()
{
for (auto& p : position)
std::cout << p[0] << " " << p[1] << "\n";
}
void shipStatus::setPosition(size_t whichItem, char c1, char c2)
{
position[whichItem] = {c1, c2}; // <-- we set one item in the vector, and in
// that item, we set the [0] and [1] characters
}
size_t shipStatus::getNumPositions() const { return position.size(); }
int main()
{
shipStatus sStatus;
sStatus.setInfo("Ship 1", 3);
sStatus.setPosition(0, '4', '2');
sStatus.setPosition(1, 'a', 'b');
sStatus.setPosition(2, 'y', 'z');
std::cout << "Number of positions: " << sStatus.getNumPositions() << "\n";
sStatus.displayStatus();
}
Output:
Number of positions: 3
4 2
a b
y z
Note that we no longer need x as a member, since a std::vector knows its size already by calling the size() member function.
char **position;
position = (char **)malloc(sizeof(char *)*x);
for (int i=0; i<x; ++i)
{
position[i] = (char *)malloc(sizeof(char)*2);
}
This is a classic "C" way of doing it, will work in C++ too.
For a cleaner approach, we should use vectors/lists for this purpose.
Related
See Last line of code:
Trying to get number of elements from a array depending on a condition. How do i get the number of elements in an array when using an array like shown below:
using namespace std;
const char *options[3] = {"Option1", "Option2", "Option3"};
const char *options2[2] = {"Option1", "Option2"};
int main() {
const char **p;
if (true) {
p = options;
} else {
p = options2;
}
printf("%ld\n", sizeof(options)); // returns 24
printf("%ld\n", sizeof(options2)); // Returnns 16
printf("%ld\n", sizeof(options) / sizeof(p)); // returns 3
printf("%ld\n", sizeof(options2) / sizeof(p)); // returns 2
// How to use only pointer p to get the number of elements
printf("%ld\n", sizeof(p) / sizeof(p[0])); // returns 1 and not 3
return 0;
}
Sorry, but it is simply not possible to get an array's size from just a raw pointer to an array element.
One option is to store the array size in a separate variable alongside the array pointer, eg:
#include <iostream>
const char *options[3] = {"Option1", "Option2", "Option3"};
const char *options2[2] = {"Option1", "Option2"};
int main() {
const char **p;
size_t p_size;
if (some condition is true) {
p = options;
p_size = sizeof(options) / sizeof(options[0]); // or better: std::size(options) in C++17 and later
} else {
p = options2;
p_size = sizeof(options2) / sizeof(options2[0]); // or better: std::size(options2)
}
std::cout << sizeof(options) << "\n"; // returns 24
std::cout << sizeof(options2) << "\n"; // returns 16
std::cout << p_size << "\n"; // returns 3 or 2, based on condition
return 0;
}
In C++20 and later, you can use std::span instead (in C++14 and C++17, you can use gsl::span from the GSL library), eg:
#include <iostream>
#include <span>
const char *options[3] = {"Option1", "Option2", "Option3"};
const char *options2[2] = {"Option1", "Option2"};
int main() {
std::span<const char*> p;
if (some condition is true) {
p = options;
} else {
p = options2;
}
std::cout << sizeof(options) << "\n"; // returns 24
std::cout << sizeof(options2) << "\n"; // returns 16
std::cout << p.size() << "\n"; // returns 3 or 2, based on condition
return 0;
}
If you're going to write C++, write C++. You're starting from one of C's more questionable decisions, and then trying to force C++ to do the same thing. To twist Nike's phrase, "Just don't do it!"
std::array<char const *, 3> options {"Option1", "Option2", "Option3"};
std::array<char const *, 2> options2 {"Option1", "Option2"};
This makes it easy to retrieve the size of the array in question--and the size is part of the type, so all the work happens at compile time, so it imposes no runtime overhead. For example, if you do something like this:
template <class Array>
void showSize(Array const &a) {
std::cout << a.size() << "\n";
}
int main() {
showsize(options);
showSize(options2);
}
...what you'll find is that the compiler just generates code to write out the literal 3 or 2:
mov esi, 3 // or `mov esi, 2`, in the second case
call std::operator<<(std::ostream &, unsigned long)
[I've done a bit of editing to demangle the name there, but that's what the code works out to.]
Here's the un-edited version, in case you care.
If you really insist, you can side-step using an std::array as well:
const char *options[3] = {"Option1", "Option2", "Option3"};
const char *options2[2] = {"Option1", "Option2"};
template <class T, size_t N>
void showSize(T (&array)[N]) {
std::cout << N << '\n';
}
int main() {
showSize(options);
showSize(options2);
}
This doesn't actually use a pointer though--it passes the array by reference, which retains its type information, so the instantiated function template "just knows" the size of the array over which it was instantiated.
20 years ago, I'd have said this was a good way to do things. 10 years ago, I'd have preferred std::array, but realized it was new enough some compilers didn't include it yet. Nowadays, unless you really need to use an ancient (Pre-C++ 11) compiler, I'd use std::array.
I am adding the header file and cpp file (it has main fucntion).
AuctionPrices.h
#ifndef AuctionPrices_h
#define AuctionPrices_h
/*
*
* class AuctionPrices - maintains Buy Order, Sell Order books
*/
#include <bits/stdc++.h>
#include <map>
//#pragma pack(1)
struct Order
{
char * itemId;
char * auctionId;
int Side;
};
class AuctionPrices
{
public:
virtual int AddNewOrder(char *itemId, char *auctionId, int Side, int Price) = 0;
virtual int DeleteOrder(char *itemId, char *auctionId) = 0;
virtual int Print() = 0;
};
class AuctionPrice_Imp : public AuctionPrices
{
public:
AuctionPrice_Imp();
~AuctionPrice_Imp();
std::map <int, Order, std::greater< int >> BuyMap;
std::map <int, Order, std::less< int >> SellMap;
int AddNewOrder(char *itemId, char *auctionId, int Side, int Price);
int DeleteOrder(char *itemId, char *auctionId);
int Print();
};
#endif
AuctionPrices_Imp.cpp
/**
* Auction Price Class implementation
* Constructor, AddNewOrder, DeleteOrder, Print
*
*/
#include <bits/stdc++.h>
#include <map>
#include "AuctionPrices.h"
using namespace std;
AuctionPrice_Imp::AuctionPrice_Imp()
{
}
AuctionPrice_Imp::~AuctionPrice_Imp()
{
}
int AuctionPrice_Imp::AddNewOrder(char *itemId, char *auctionId, int Side, int Price)
{
Order order;
memcpy(order.itemId, itemId, strlen(itemId)+1);
memcpy(order.auctionId, auctionId, strlen(auctionId)+1);
order.Side = Side;
if (Side == 1)
{
BuyMap.insert (std::pair<int,Order>(Price,order));
//buyLevels_.insert( std::pair< OfPrice, Level< OrderEntry > >( price, buyLevel ) );
}
else if (Side == 2)
{
SellMap.insert (std::pair<int,Order>(Price,order));
}
else
{
return 0;
}
return 1;
}
int AuctionPrice_Imp::DeleteOrder(char *itemId, char *auctionId)
{
return 0;
}
int AuctionPrice_Imp::Print()
{
std::map <int,Order,std::greater< int >>::iterator buy_it;
std::map <int,Order,std::less< int >>::iterator sell_it;
// Print Sell Map
for ( sell_it = SellMap.begin();sell_it != SellMap.end(); sell_it++)
{
std::cout << sell_it->first << '\t' << std::endl;
}
// Print Buy Map
for ( buy_it = BuyMap.begin();buy_it != BuyMap.end(); buy_it++)
{
std::cout << buy_it->first << '\t' << std::endl;
}
return 1;
}
int main()
{
AuctionPrice_Imp * auctionPrice_Imp = new AuctionPrice_Imp();
/*
AddNewOrder(“item1”, “auction1”, 1, 100)
AddNewOrder(“item1”, “auction2”, 1, 101)
AddNewOrder(“item2”, “order3”, 1, 99)
AddNewOrder(“item2”, “order4”, 2, 100)
*/
auctionPrice_Imp->AddNewOrder("item1", "auction1", 1, 100);
auctionPrice_Imp->AddNewOrder("item1", "auction2", 1, 101);
auctionPrice_Imp->AddNewOrder("item2", "order3", 1, 99);
auctionPrice_Imp->AddNewOrder("item2", "order4", 2, 100);
auctionPrice_Imp->Print();
}
When I am running the code its giving segmentation fault at the line:
memcpy(order.auctionId, auctionId, strlen(auctionId)+1);
Please anyone can help or correct the code.
The functions I am calling are supposed to add the orders to the Maps: BuyMap and SellMap. Once they have added to those map, I am using a print function to print the values.
Order order;
This creates a new Order object. Order does not have a constructor, so none of its class members, itemId, and auctionId, get initialized to point to anything. These pointers are uninitialized, random garbage. Immediately afterwards:
memcpy(order.itemId, itemId, strlen(itemId)+1);
memcpy(order.auctionId, auctionId, strlen(auctionId)+1);
Since neither itemId, nor auctionId, point to sufficient memory that are at least strlen(itemId)+1 or strlen(auctionId)+1 in size, respectively, this results in undefined behavior, and your crash.
In C++, before using a pointer, it is your responsibility to make sure that the pointer is valid, and points to the correct object, objects, or sufficiently-sized memory buffers. C++ will not do that for you, you have to do all that work yourself.
But if your intent is to write modern C++ code, it is much simpler just to use C++ classes, like std::strings instead of plain char * pointers. std::strings automatically handle all these low-level details, manage memory properly, without making it your responsibility to do so. You will find a complete description of std::string and many examples of using it in your C++ textbook.
You should use std::string to avoid having to deal with low level issues of pointers and memory allocation. These are the issues that you are getting wrong in your code. Here's your code rewritten to use std::string
struct Order
{
std::string itemId;
std::string auctionId;
int Side;
};
int AuctionPrice_Imp::AddNewOrder(std::string itemId, std::string auctionId, int Side, int Price)
{
Order order;
order.itemId = itemId;
order.auctionId = auctionId;
order.Side = Side;
See how easy that is? The code to use std::string is no different to the code that handles int.
I am struggling to find the correct format for initializing a (private) array within a class and getting/setting the values from outside the class.
My code is semi-functional, but feels awkward in incorrectly formatted.
It is returning only the first element of the array, I want it to return all the contents. Read code comments for additional details.
Note: This is (a very small part of) a project I am working on for school -- an array must be used, not a vector or list.
student.h
class Student {
public:
// Upon researching my issue, I read suggestions on passing pointers for arrays:
void SetDaysToCompleteCourse(int* daysToCompleteCourse[3]);
int* GetDaysToCompleteCourse(); // Ditto # above comment.
private:
int daysToCompleteCourse[3];
student.cpp
#include "student.h"
void Student::SetDaysToCompleteCourse(int* daysToCompleteCourse) {
// this->daysToCompleteCourse = daysToCompleteCourse; returns error (expression must be a modifiable lvalue)
// Feels wrong, probably is wrong:
this->daysToCompleteCourse[0] = daysToCompleteCourse[0];
this->daysToCompleteCourse[1] = daysToCompleteCourse[1];
this->daysToCompleteCourse[2] = daysToCompleteCourse[2];
}
int* Student::GetDaysToCompleteCourse() {
return daysToCompleteCourse;
}
ConsoleApplication1.cpp
#include "pch.h"
#include <iostream>
#include "student.h"
int main()
{
Student student;
int daysToCompleteCourse[3] = { 1, 2, 3 };
int* ptr = daysToCompleteCourse;
student.SetDaysToCompleteCourse(ptr);
std::cout << *student.GetDaysToCompleteCourse(); // returns first element of the array (1).
}
I gave this my best shot, but I think I need a nudge in the right direction.
Any tips here would be greatly appreciated.
I would say:
// student.h
class Student
{
public:
// If you can, don't use numbers:
// you have a 3 on the variable,
// a 3 on the function, etc.
// Use a #define on C or a static const on C++
static const int SIZE= 3;
// You can also use it outside the class as Student::SIZE
public:
void SetDaysToCompleteCourse(int* daysToCompleteCourse);
// The consts are for "correctness"
// const int* means "don't modify this data" (you have a setter for that)
// the second const means: this function doesn't modify the student
// whithout the const, student.GetDaysToCompleteCourse()[100]= 1 is
// "legal" C++ to the eyes of the compiler
const int* GetDaysToCompleteCourse() const; // Ditto # above comment.
Student()
{
// Always initialize variables
for (int i= 0; i < SIZE; i++) {
daysToCompleteCourse[i]= 0;
}
}
private:
int daysToCompleteCourse[SIZE];
// On GCC, you can do
//int daysToCompleteCourse[SIZE]{};
// Which will allow you not to specify it on the constructor
};
// student.cpp
void Student::SetDaysToCompleteCourse(int* newDaysToCompleteCourse)
{
// It's not wrong, just that
// this->daysToCompleteCourse[0] = daysToCompleteCourse[0];
// use another name like newDaysToCompleteCourse and then you can suppress this->
// And use a for loop
for (int i= 0; i < SIZE; i++) {
daysToCompleteCourse[i]= newDaysToCompleteCourse[i];
}
}
const int* Student::GetDaysToCompleteCourse() const
{
return daysToCompleteCourse;
}
// main.cpp
#include <iostream>
std::ostream& operator<<(std::ostream& stream, const Student& student)
{
const int* toShow= student.GetDaysToCompleteCourse();
for (int i= 0; i < Student::SIZE; i++) {
stream << toShow[i] << ' ';
}
return stream;
}
int main()
{
Student student;
int daysToCompleteCourse[3] = { 1, 2, 3 };
// You don't need this
//int* ptr = daysToCompleteCourse;
//student.SetDaysToCompleteCourse(ptr);
//You can just do:
student.SetDaysToCompleteCourse(daysToCompleteCourse);
// On C++ int* is "a pointer to an int"
// It doesn't specify how many of them
// Arrays are represented just by the pointer to the first element
// It's the FASTEST and CHEAPEST way... but you need the SIZE
const int* toShow= student.GetDaysToCompleteCourse();
for (int i= 0; i < Student::SIZE; i++) {
std::cout << toShow[i] << ' ';
// Also works:
//std::cout << student.GetDaysToCompleteCourse()[i] << ' ';
}
std::cout << std::endl;
// Or you can do: (because we defined operator<< for a ostream and a Student)
std::cout << student << std::endl;
}
You can check out it live here: https://ideone.com/DeJ2Nt
The following C++ code sorts an array in descending order using qsort:
#include<iostream>
#include<cstdio>
#include <stdlib.h>
using namespace std;
struct player {
double data;
int index;
};
struct player A[] = {{0.690277,0}, {0.517857,1}, {0.780762,2}, {0.0416667,3}, {0.0416667,4}};
int compare (const void * a, const void * b)
{
return ( ((struct player*)b)->data - ((struct player*)a)->data );
}
int main ()
{
int n;
qsort (A, 5, sizeof(struct player), compare);
for (n=0; n<5; n++)
printf ("data=%lf, index=%d\n", A[n].data, A[n].index);
return 0;
}
But I am getting output like this:
data=0.517857, index=1
data=0.780762, index=2
data=0.041667, index=3
data=0.041667, index=4
data=0.690277, index=0
Is there anything wrong in the code?
In compare, you are subtracting two sub-1 doubles and casting them to an int, the result will in most cases be 0. Instead of subtracting you should compare them and return -1/1.
Consider using this compare instead:
int compare (const void * a, const void * b)
{
auto x = reinterpret_cast<const player*>(a);
auto y = reinterpret_cast<const player*>(b);
if(x->data < y->data)
return -1;
if(x->data > y->data)
return 1;
return 0;
}
That said, this style of coding is ancient/deprecated/bad practice.
Consider writing similar to this instead:
#include<iostream>
#include <algorithm>
struct player {
double data;
int index;
bool operator < (const player& p) const
{
return data < p.data;
}
};
auto A = std::vector<player>{
{0.690277,0}, {0.517857,1},
{0.780762,2}, {0.0416667,3}, {0.0416667,4}
};
int main ()
{
std::sort(std::begin(A), std::end(A));
for(const auto& x: A)
std::cout << "data=" << x.data << ", "
<< "index=" << x.index << "\n";
}
Suggested changes:
don't import std names globally
don't mix cstdio and iostreams (only include one of them)
use std::vector or std::array instead of native array
define the sorting order in the interface of the class (bool operator <). (this should also imply that you define the other arithmetic operators - it is good practice and avoids subtle bugs later, but it is not required for this particular implementation to compile and work)
use std::sort instead of qsort
don't use raw pointers (using them like this is a source for bugs)
#include <iostream>
#include "HtmlTable.h"
using namespace std;
int main()
{
cout << "Content-type: text/html" << endl << endl;
HtmlTable t(2,3);
t.insert(2,1, "one");
t.insert(1,2, "two");
t.insert(2,3, "three");
t.print();
return 0;
}
#ifndef HTMLTABLE_H
#define HTMLTABLE_H
#include <string>
#include <iostream>
using namespace std;
class HtmlTable
{
public:
HtmlTable(int y, int x)
{
}
void print()
{
cout << "<table>";
for (row=0; row<y; row++)
{
cout << "<tr>";
for (col=0; col<x; col++)
{
cout << "<table border='1'>";
cout << m_Table[y][x];
}
cout << "</td>";
}
cout << "</table>";
}
void insert(int row, int col, string text)
{
y = row;
x = col;
z = text;
m_Table[y][x] = {{z,z,z,z},{z,z,z,z},{z,z,z,z},{z,z,z,z}};
}
protected:
private:
string m_Table[100][100];
int row;
int col;
string text;
int x;
int y;
string z;
int get_x = x;
int get_y = x;
};
#endif // HTMLTABLE_H
I have to create a 2d array of strings.
There is an insert function that inserts a string into a certain spot in the array.
Then the print function should print a table with the words inside the corresponding box.
output should be something like this:
|____| two |______|
| one|_____| three|
I am given int main and cant change anything.
My current issue is with the void insert. the error is:
no match for 'operator=' in
'((HtmlTable*)this)->HtmlTable::m_Table[((HtmlTable*)this)->HtmlTable::y]
my past attemps only printed the last spring and repeated in for every box in the table.
what am i doing the array incorrectly? is my print function also incorrect?
This line:
m_Table[y][x] = {{z,z,z,z},{z,z,z,z},{z,z,z,z},{z,z,z,z}};
is plain wrong. m_Table is a 2D array or strings, so m_Table[y][x] is just a std::string. You should write: m_Table[y][x] = z.
But there are many other problems in your code:
you pass the array dimensions in HtmlTable constructor but ignore them
you declare z, row, col, text as member variable when they does not store state: they should be local variable of member functions
these two lines
int get_x = x;
int get_y = x;
declare unused member variable and try to initialize them which is incorrect. Member variables should be initialized in constructor (except for integral static const ones)
print make row loop from 0 to y, and col from 0 to x (which is right if x and y are initialized), but consistently writes m_Table[y][x] instead of m_Table[row][col]
And your print method is wrong... because you never initialized x and y. Your constructor should be:
HtmlTable(int y, int x): x(x), y(y)
{
}
and you should not modify them in insert:
void insert(int row, int col, string text)
{
m_Table[row][col] = text;
}
Array are 0 indexed in C++. Your main should contain:
t.insert(1,0, "one");
t.insert(0,1, "two");
t.insert(1,2, "three");
BTW, generated HTML is incorrect: you do not close <tr> tag, not open <td> one, and nest <table> tags in a strange way but this would be another story...