Seg fault while outputting 2-d array of strings - c++

So i have been working on this code for a while, and I am not very skilled. I have created two classes one defines an item for a shopping list, and the other creates an array of the objects and outputs them as a list. The program works in my windows command prompt, but segfaults on GNU command line when I am outputting the array using cout statements.
void List::createList(Item ** itemPtr, int size)
{
string** list1 = new string*[size];
for(int i = 0; i < 5; i++)
{
list1[i] = new string[5];
}
for (int i = 0; i < size; i++)
{
list1[i][0] = itemPtr[i]->getName();
list1[i][1] = itemPtr[i]->getUnit();
list1[i][2] = itemPtr[i]->getSTRnumToBuy();
list1[i][3] = itemPtr[i]->getSTRcost();
list1[i][4] = itemPtr[i]->getSTRextCost();
}
cout << endl << left << fixed << setw(15) << setprecision(2) << "Name";
cout << fixed << left << setw(15) << setprecision(2) << "Unit Type";
cout << fixed << left << setw(15) << setprecision(2) << "# of units";
cout << fixed << left << setw(15) << setprecision(2) << "Cost/Unit";
cout << fixed << left << setw(15) << setprecision(2) << "Total" << endl;
for (int i = 0; i < size; i++)
{
cout << fixed << left << setw(15) <<setprecision(2)<<endl<< list1[i][0];
cout << fixed << left << setw(15) << setprecision(2) << list1[i][1];
cout << fixed << left << setw(15) << setprecision(2) << list1[i][2];
cout << fixed << left << setw(15) << setprecision(2) << list1[i][3];
cout << fixed << left << setw(15) << setprecision(2) << list1[i][4];
}
}

Your 1st loop should be :
for(int i = 0; i < size; i++)
{
list1[i] = new string[5];
}
That is, loop till size, not till 5.

string** list1 = new string*[size];
for(int i = 0; i < 5; i++)
Looks like a bug to me: if size < 5 then you will be reading out of bounds of the array you have created.
list1[i][0] = itemPtr[i]->getName();
list1[i][1] = itemPtr[i]->getUnit();
list1[i][2] = itemPtr[i]->getSTRnumToBuy();
list1[i][3] = itemPtr[i]->getSTRcost();
list1[i][4] = itemPtr[i]->getSTRextCost();
This could fail if the size of the itemPtr array is less than size.
Another point, though not related to the crash you're seeing, you are leaking memory here. list1 is a local variable that's not stored somewhere in your class. You are allocating memory for it on the heap, but do not free that memory (delete) it anywhere.

Your using C++ not C so use the power of the vector
void List::createList(Item ** itemPtr, int size) {
vector<vector<string>> list1;
list1.resize(size);
for (int i = 0; i < size; i++) {
list1[i].resize(5);
list1[i][0] = itemPtr[i]->getName();
list1[i][1] = itemPtr[i]->getUnit();
list1[i][2] = itemPtr[i]->getSTRnumToBuy();
list1[i][3] = itemPtr[i]->getSTRcost();
list1[i][4] = itemPtr[i]->getSTRextCost();
}
cout << endl << left << fixed << setw(15) << setprecision(2) << "Name";
cout << fixed << left << setw(15) << setprecision(2) << "Unit Type";
cout << fixed << left << setw(15) << setprecision(2) << "# of units";
cout << fixed << left << setw(15) << setprecision(2) << "Cost/Unit";
cout << fixed << left << setw(15) << setprecision(2) << "Total" << endl;
for (int i = 0; i < size; i++)
{
cout << fixed << left << setw(15) <<setprecision(2)<<endl<< list1[i][0];
cout << fixed << left << setw(15) << setprecision(2) << list1[i][1];
cout << fixed << left << setw(15) << setprecision(2) << list1[i][2];
cout << fixed << left << setw(15) << setprecision(2) << list1[i][3];
cout << fixed << left << setw(15) << setprecision(2) << list1[i][4];
}
}
Look Ma, no news nor deletes.

Related

Aligning output column using setw in C++

I have been reading about setw for column widths, however setting a width for each colum does not seem to be aligning the last two columns. I have tried using the right align, however it also changes alignment for the left two columns as well, which I don't want. In the end I'd like everything to be left aligned. Is there an easier way of doing this other than setw?
Current code:
void print_head()
{
cout.setf(ios::left);
cout << setw(16) << "Operation"
<< setw(32) << "z"
<< setw(8) << "Cost"
<< setw(8) << "Total" << endl;
for (int i=0; i<64; ++i) cout << "-";
cout << endl;
}
print_head();
cout.setf(ios::left);
cout << setw(16) << "Initial String"
<< setw(32) << test1
<< setw(8) << "0"
<< setw(8) << "0" << endl;
for (int g = minops[0] + minops[1] - 1;g>-1;g--){
string a;
for(stringstream ss(operations[g]); getline(ss, a, ','); ) // that's all !
v.push_back(a);
//cout << v[current] << "\n";
if (v[current] == "c"){
z = sright(z, cursorg);
current++;
cout << setw(16) << "right"
<< setw(32) << z
<< setw(8) << "0"
<< setw(8) << tcost << endl;
}else if (v[current] == "d"){
z = sdelete(z, cursorg);
size = size - 1;
tcost = tcost + 2;
cout << setw(16) << "delete"
<< setw(32) << z
<< setw(8) << "2"
<< setw(8) << tcost << endl;
//cout << "cursor out of delete: " << cursorg << "\n";
current = current + 2;
}else if (v[current] == "r"){
z = sreplace(z, cursorg, test2, stoi(v[current+1]), stoi(v[current+2]));
int printtemp = stoi(v[current+2]);
string s(1,test2[printtemp]);
string tempstr = "replace by " + s;
tcost = tcost + 4;
cout << setw(16) << tempstr
<< setw(32) << z
<< setw(8) << "4"
<< setw(8) << tcost << endl;
current = current + 3;
}else if (v[current] == "i"){
z = sinsert(z, test2, cursorg, stoi(v[current+1]));
size = size - 1;
tcost = tcost + 3;
int printtemp = stoi(v[current+1]);
string s(1,test2[printtemp]);
string tempstr = "insert " + s;
cout << setw(16) << tempstr
<< setw(32) << z
<< setw(8) << "3"
<< setw(8) << tcost << endl;
current = current + 2;
}else{
}
//cout << operations[g] << "\n";
//cout << "z is: " << z << "\n";
}
cout << "\n";
cout << "minimum operations is: " << minops[0] << "\n";
This is my current output, however I want the cost and total cost to be a neat aligned column under the header. How do I use setw to fix my alignment?
Delete implementation:
string sdelete(string input, int &cursor){ //deletes the letter under the cursor, cost 2
if (cursor == (input.length() + 1)){
//do nothing
}else{
input[cursor] = NULL;
cursor = cursor+1;
}
//DEBUG cout << "delete input: " << input << "\n";
//DEBUG cout << "cursor in delete: " << cursor << "\n";
return input;
}

Multiplying elements in array not working in c++?

I am trying to make a simple program in c++ that takes the price and number of items purchases, stores it in arrays, and then outputs the totals for each item in a tabular format. However, when I multiply the numbers in my code, I get totally strange answers! Can someone please enlighten me as to what's going on?
Code:
#include <iostream>
using namespace std;
int main(int argc, _TCHAR* argv[]) {
float price[4], tot[4];
int amt[4];
cout << "Please enter the price and amount of 4 items:\n";
for (int i = 0; i<4; i++) {
cout << "Price of item " << i + 1 << ": ";
cin >> price[i];
cout << "Amount of item " << i + 1 << ": ";
cin >> amt[i];
if (price[i] <= 0 || amt[i] <= 0) {
cout << "Invalid Input Entry!\n";
break;
}
tot[i] = price[i] * amt[i]; // I can't really see how I could have messed this up...
}
cout << "Total\t\tPrice\t\tAmount\n";
cout << "-----\t\t-----\t\t------\n";
for (int i = 0; i < 4; i++) {
cout << "$" << fixed << cout.precision(2) << tot[i] << "\t\t$" << price[i] << "\t\t" << amt[i] << endl;
}
system("pause");
return 0;
}
Output:
The problem is that you are outputting the return value of cout.precision(2) (which returns the previous precision, in this case 6 initially and then 2 afterwards) in front of each total price.
You need to either:
not pass the return value of cout.precision() to operator<<:
cout << "$" << fixed;
cout.precision(2);
cout << tot[i] << ...
or, call precision() one time before entering the loop:
cout.precision(2);
for (int i = 0; i < 4; i++) {
cout << "$" << fixed << tot[i] << "\t\t$" << price[i] << "\t\t" << amt[i] << endl;
}
use the std::setprecision() stream manipulator instead of calling cout.precision() directly:
#include <iomanip>
for (int i = 0; i < 4; i++) {
cout << "$" << fixed << setprecision(2) << tot[i] << "\t\t$" << price[i] << "\t\t" << amt[i] << endl;
}
or
#include <iomanip>
cout << setprecision(2);
for (int i = 0; i < 4; i++) {
cout << "$" << fixed << tot[i] << "\t\t$" << price[i] << "\t\t" << amt[i] << endl;
}
On a side note, you should not use \t characters to control the formatting of your table. Use stream manipulators like std::setw(), std::left, etc instead:
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cstdlib>
using namespace std;
const int maxItems = 4;
string moneyStr(float amount)
{
ostringstream oss;
// in C++11 and later, you can replace this with std::put_money() instead:
// http://en.cppreference.com/w/cpp/io/manip/put_money
//
// oss << showbase << put_money(amount);
oss << "$" << fixed << setprecision(2) << amount;
return oss.str();
}
int main(int argc, _TCHAR* argv[])
{
float price[maxItems], tot[maxItems];
int amt[maxItems];
int cnt = 0;
cout << "Please enter the price and amount of " << maxItems << " items:" << endl;
for (int i = 0; i < maxItems; ++i)
{
cout << "Price of item " << i + 1 << ": ";
cin >> price[i];
cout << "Amount of item " << i + 1 << ": ";
cin >> amt[i];
if (price[i] <= 0 || amt[i] <= 0) {
cout << "Invalid Input Entry!" << endl;
break;
}
tot[i] = price[i] * amt[i];
++cnt;
}
cout << left << setfill(' ');
cout << setw(16) << "Total" << setw(16) << "Price" << setw(16) << "Amount" << endl;
cout << setw(16) << "-----" << setw(16) << "-----" << setw(16) << "------" << endl;
for (int i = 0; i < cnt; i++) {
cout << setw(16) << moneyStr(tot[i]) << setw(16) << moneyStr(price[i]) << setw(16) << amt[i] << endl;
}
system("pause");
return 0;
}
Live Demo

Formatting with setw() c++

I am trying to create an organized looking graph with the amount of money for each food under each month. I was able to line up the first row, but after that, something started going off. This is what I ended up with:
This is the code I tried playing around with the setw() but I can't seem to change it for the number after it puts out the first array element.
void sales_report() {
for (int i = 0; i < 7; i++) {
cout << setw(17) << months[i] << " ";
}
cout << endl << foods[0] << " ";
for (int i = 0; i < 6; i++) {
sumapple += apples[i];
cout << setprecision(2) << fixed << setw(8) << money << apples[i] << " ";
}
cout << setprecision(2) << fixed << setw(8) << money << sumapple << endl;
cout << foods[1] << " ";
for (int i = 0; i < 6; i++) {
sumoranges += oranges[i];
cout << setprecision(2) << fixed << setw(7) << money << oranges[i] << " ";
}
cout << setprecision(2) << fixed << setw(7) << money << sumoranges << endl;
cout << foods[2] << " ";
for (int i = 0; i < 6; i++) {
sumpears += pears[i];
cout << setprecision(2) << fixed << setw(10) << money << pears[i] << " ";
}
cout << setprecision(2) << fixed << setw(10) << money << sumpears << endl;
cout << foods[3] << " ";
for (int i = 0; i < 6; i++) {
sumtomatoes += tomatoes[i];
cout << setprecision(2) << fixed << setw(7) << money << tomatoes[i] << " ";
}
cout << setprecision(2) << fixed << setw(7) << money << sumtomatoes << endl;
cout << foods[4] << " ";
for (int i = 0; i < 6; i++) {
sumcherries += cherries[i];
cout << setprecision(2) << fixed << setw(6) << money << cherries[i] << " ";
}
cout << setprecision(2) << fixed << setw(6) << money << sumcherries << endl << totalmonth;
for (int i = 0; i < 6; i++) {
total = apples[i] + oranges[i] + pears[i] + tomatoes[i] + cherries[i];
cout << setprecision(2) << fixed << setw(9) << money << total << " ";
}
}
You are using different std::setw() values in each of the for loops. Hence the misalignment. Use the same values.

Dynamic alignment issue

When I try to list details of all items, each on a different line
with line numbering, there is alignment issue on it. I want instantly put the close bracket after the line numbering. Thanks.
cout << left
<< setw(20) << " Item Code"
<< setw(50) << "Description"
<< setw(20) << "Quantity on hand"
<< setw(20) << "Cost price"
<< setw(20) << "Selling price(RM)"
<< setw(20) << "Status"
<< setw(20) << "Discount(%)" << endl;
for (int i = 0; i <= 100; i++)//counter - 1; i++)
{
cout << left
<< setw(2) << i + 1 << ")"
<< setw(20) << item[i].getItemCode()
<< setw(50) << item[i].getDescription()
<< setw(20) << item[i].getQuantity()
<< setw(20) << item[i].getCostPrice()
<< setw(20) << item[i].getSellPrice()
<< setw(20) << item[i].getStatus()
<< setw(20) << item[i].getDiscount() << endl;
}
The only way of doing this, as far as I can see, is to walk through the list and find out "how long does this get" for each of the columns, and track what the largest is for each of the columns. Then use those values in the column width.
Strings are easy to find the length of, since they have a length as such. Numbers are harder - basically, you have to either take the approach of dividing it by ten down until it's zero (this means the integer part of floating point numbers - presumably for something like this, you have a fixed number of decimals or use "integeer to represent prices in cents" or some such). You may be able to use the std::tostring to produce as string that has a length too. Or you can use stringstream to output to a string - either individual items, or the whole lot and then count the number of characters between some separator character [that doesn't occur in the normal output, or things go wrong pretty easily!]
Example, using a simple struct:
struct Data
{
int x;
string y;
float z;
}
...
Data d[10];
int maxLen[3] = { 0 };
... // code fills in data with stuff.
for(int i = 0; i < 10; i++)
{
stringstream ss;
ss << left << d[i].x << " " << d[i].y << " " << fixed << setprecision(2) << d[i].z;
// Number of elements = 3.
for(int j = 0; j < 3; j++)
{
string s;
ss >> s;
if (s.length() > maxLen[j])
maxLen[j] = s.legnth;
}
}
...
for(int i = 0; i < 10; i++)
{
cout << left << setw(3) i << ": "
<< setw(maxLen[0]+1) << d[i].x
<< setw(maxLen[1]+1) << d[i].y
<< setw(maxLen[2]+1) << fixed << setprecision(2) << d[i].z << endl;
}

C++: Append string to output of first and last array index in loop

I tried to word the title as best as I could. Here I have a function that indexes through two parallel arrays and then outputs them with some formatting.
void outputTable(string salsa_jars[], int jars_sold[], int index[])
{
int totalSold = 0;
cout << setw(8) << "\nSalsa type sells: " << endl
<< "-------------------------------" << endl;
for(int i = 0; i <= (SALSA_TYPES-1); i++)
{
totalSold += jars_sold[index[i]];
cout << setw(15) << left << salsa_jars[index[i]]
<< setw(15) << right << jars_sold[index[i]] << endl;
}
cout << "-------------------------------" << endl
<< "Total sales: " << setw(17) << totalSold << endl;
}
What I'm trying to achieve is to add a string to the first and last outputs of the array. Below is my attempt.
void outputTable(string salsa_jars[], int jars_sold[], int index[])
{
int totalSold = 0;
cout << setw(8) << "\nSalsa type sells: " << endl
<< "-------------------------------" << endl;
for(int i=0;i<=(SALSA_TYPES-1);i++)
{
if(i == 0){
cout << setw(7) << left << salsa_jars[index[i]]
<< "(Highest)" << setw(14) << right
<< jars_sold[index[i]] << endl;
}
else if (i == (SALSA_TYPES-1)){
cout << setw(7) << left << salsa_jars[index[i]]
<< "(Lowest)" << setw(15) << right
<< jars_sold[index[i]] << endl;
}
else{
totalSold += jars_sold[index[i]];
cout << setw(15) << left << salsa_jars[index[i]]
<< setw(15) << right << jars_sold[index[i]] << endl;
}
}
cout << "-------------------------------" << endl
<< "Total sales: " << setw(17) << totalSold << endl;
}
But the code seems redundant, and I couldn't think of any other way to do it. If anyone has any pointers, I would appreciate it. Thanks.
Just prepare appropriate title for entry, and use common logic for displaying it:
for(int i=0;i<=(SALSA_TYPES-1);i++)
{
string title = toString(salsa_jars[index[i]]);
if(i == 0){
title += " (Highest)";
}
else if (i == (SALSA_TYPES-1)){
title += " (Lowest)";
}
totalSold += jars_sold[index[i]];
cout << setw(15) << left << title
<< setw(15) << right << jars_sold[index[i]] << endl;
}
}