Column Alignment using C++ - c++

I'm struggling getting my columns to align on an assignment I have for school. The directions are to ensure that each column heading aligns correctly with its respective column. I've tried everything I've found online so far, including the cout.width() and the setw(), neither of which has worked. I'm hoping it's not due to me implementing these methods incorrectly, though I can't think of any other reason why they wouldn't work. The assignment specifically has 2 student names to use as an example. Jones, Bob and Washington, George. Due to the major difference in the number of characters between one student and the next, the columns just won't align. I know that setting a column width should fix that, but in my case it isn't. Then code I'm supplying is using the setw() method, but I can supply how I tried using the cout.width() if needed. Any help is GREATLY appreciated.
#include <iostream>
#include <iomanip>
#include <string>
#include <cstdlib>
using std::cout;
using std::cin;
using namespace std;
const int ARRAYSIZE = 2;
struct studentData{
string lastName;
string firstName;
float studentGpa;
}studentArray[ARRAYSIZE];
void displayData(int a);
int main()
{
int counter = 0;
for (int a = 0; a < ARRAYSIZE; a++)
{
cout << "Enter last name: " << endl;
cin >> studentArray[a].lastName;
cout << "Enter first name: " << endl;
cin >> studentArray[a].firstName;
cout << "Enter GPA: "<< endl;
cin >> studentArray[a].studentGpa;
counter++;
}
cout << "\n\n";
displayData(counter);
return 0;
}
void displayData(int a)
{
int newSize = a;
cout << left << setw(20) <<"\nName(Last, First)";
cout << right << setw(20) << "GPA\n";
for (int z = 0; z < newSize; z++)
{
cout << studentArray[z].lastName << ", " << studentArray[z].firstName;
cout << right << setw(20) << fixed << setprecision(2) <<studentArray[z].studentGpa << endl;
}
}
And my console input/output:
Enter last name:
Jones
Enter first name:
Bob
Enter GPA:
3.0
Enter last name:
Washington
Enter first name:
George
Enter GPA:
4.0
Name(Last, First) GPA
Jones, Bob 3.00
Washington, George 4.00

You are along the right lines, but std::setw only applies to the next output operation. If you turn printing the name into one operation, instead of 3 (last, comma, first) then you can pad the width of that more easily:
void displayData(std::size_t a)
{
std::cout << std::left
<< std::setw(20)
<< "Name(Last, First)"
<< "GPA\n";
for (std::size_t z = 0; z < a; ++z)
{
std::cout << std::left
<< std::setw(20)
<< (studentArray[z].lastName + ", " + studentArray[z].firstName)
<< std::fixed << std::setprecision(2)
<< studentArray[z].studentGpa
<< '\n';
}
}
Output:
Name(Last, First) GPA
Jones, Bob 3.00
Washington, George 4.00
Here, both for printing the column headings, and for the student names, I use std::left to say that the content should be at the left of the padded total, and std::setw to pad this output operation to 20 characters total (by default it will pad with spaces).
In both cases, this is the 1st column in the output, so I don't need to do anything with the 2nd column. If you had a 3rd column, you would need to pad the 2nd as well.
I also replaced your ints with size_ts for array indexing. It's a little point, but you shouldn't really use a signed type for indexing into a container where accessing a negative index would be Undefined Behaviour.
Also, please reconsider your use of what are often considered bad practices: using namespace std; and endl (those are links to explanations).

Related

Why arrays do not print whole table?

#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int d,m;
int districts=3;
int months = 12;
double sales[districts][months];
for (d=0 ; d < districts; d++)
{
for(m=0; m< months; m++)
{
cout << "Enter sales for District " << d+1 << ":" << " and Month " << m+1 << ": ";
cin >> sales[districts][months];
}
}
cout << "\n\n\n";
cout << setw(40) << "Months\n";
cout << setw(26) << "1 2 3 4 5 6 7 8 9 10 11 12\n";
for (d=0; d < districts ; d++)
{
cout << "District " << d+1;
for(m=0; m< months; m++)
{
cout << ": " << sales[districts][months];
}
}
return 0;
}
This code after running takes only two input values from user and after that a window appear displaying message a problem caused the program to stop working correctly.
There are no compilation errors and I am unable to find the problem. Is there anyone who can help?
You use variables d and m as counter-variables for your loops, but inside the loops you use the maximum value for both of them (districts and months) instead of d and m.
Change this: cin >> sales[districts][months]; to this: cin >> sales[d][m];
Also, this: cout << ": " << sales[districts][months]; to this: cout << ": " << sales[d][m];.
The term sales[districts][months] refers to a particular element sales[3][12], which also happens to be out of bounds for the 2-d array.
The reading loop is repeatedly reading a value to sales[districts][months], i.e. to sales[3][12], which - since array indexing starts at zero in all dimensions, doesn't exist. That gives undefined behaviour.
The output loops are repeatedly outputting the same value, which also gives undefined behaviour.
A common symptom (but not the only possible one) of undefined behaviour is abnormal program termination - and you are seeing an example of that.
There is also the wrinkle that
int districts=3;
int months = 12;
double sales[districts][months];
involves a variable length array (VLA) which is a feature of C (from the 1999 C standard or later) but is not valid C++. If that construct works for you, your compiler supports a non-standard extension.

Storing user input data in a dynamic array of structures/ displaying said data. C++

So for my project I have to...
Create a structure using the format: struct PERSON{string name; int age; float gpa;};
Ask the user to enter the number of records they would like to enter.
Create a dynamic array p of PERSON type to be able to hold all records in part 2
Read data into array p in part 2
Display array p
However, whenever I run my program and begin to enter my data it won't let me enter more than one set of data and the output seems to make little sense.
Here is my code:
#include "stdafx.h"
#include <iostream>
#include <iomanip>
#include <string>
#include <cstdlib>
using namespace std;
struct PERSON
{
string name;
int age;
float gpa;
};
PERSON *p;
int main()
{
int count;
cout << "Please enter the number of records you wish to enter: ";
cin >> count;
p = new (nothrow) PERSON[count];
if (p == nullptr)
cout << "Error: memory could not be allocated";
for (int i = 0; i < count; i++)
{
cout << "Enter name, age, and gpa: ";
getline(cin, p[i].name);
cin >> p[i].age;
cin >> p[i].gpa;
cout << endl;
}cout << endl;
cout << "This is the content of array p: " << endl;
cout << right << setw(8) << "NAME" << setw(7) << "AGE" << setw(7) << "GPA" << endl;
cout << "--------------------------" << endl;
for (int i = 0; i < count; i++)
{
cout << p[i].name << " " << p[i].age << " " << p[i].gpa << endl;
}
return 0;
}
Now, this format seemed to work just fine when I was copying data from a file into a dynamic array of structures, but I can't seem to get it to work now that I'm dealing with user input.
Here is what a trial run of the program produces:
Please enter the number of records you wish to enter: 3
Enter name, age, and gpa: Robert 21 2.1 // This is the info I tested
Enter name, age, and gpa:
Enter name, age, and gpa:
This is the content of array p:
NAME AGE GPA
--------------------------
-842150451 -4.31602e+008 //?
-842150451 -4.31602e+008 //?
-842150451 -4.31602e+008 //?
Press any key to continue . . .
I've probably gone over the code two dozen times now and have been searching for an answer for quite a while. Any advice/analysis/comments would be greatly appreciated.
So #AndyG suggested that I change the getline(cin, p[i].name) to cin >> p[i].name and that seemed to clear things up. Thank you!
Sorry to trouble everyone over such a silly muck-up.
The Problem
Your getline(cin, p[i].name) is actually grabbing all your input on the same line, and your later cin statements are going to be mismatched.
std::getline should be reserved for getting an entire line into a character buffer or std::string, i.e., it's not always the appropriate tool for reading in a string.
The Solution
Instead, you simply need to replace getline(cin, p[i].name) with cin >> p[i].name.
Live Demo
Other minor changes
Remove the nullptr check:
if (p == nullptr)
cout << "Error: memory could not be allocated";
Because in C++ you will get an exception thrown if the new operator fails to allocate. Like bku_drytt mentioned, you can wrap this in a try catch block instead, although I'd personally just remove it altogether.
#include <new>
// ...
Person* p = null;
try
{
p = new Person[count];
} catch(std::bad_alloc& ex)
{
cerr << "Unable to allocate memory for Person! Error msg: " << ex.what() << "\n";
return 1;
}
Finally, don't forget to delete[] the memory you allocated for p:
// ...
delete[] p;
return 0;
} //end of int main()
Even though your OS will most definitely clean that memory up for you, you should still ensure you clean it up manually. Good practice at least. Alternatively, you can use a std::array or a std::vector instead, which will still give you random access just like the c-style array of PERSON you already have.
The std::getline() function is "misbehaving" in relation to your intentions because there is (I think) a new line character left in the stream input queue.
You can discard such characters by using the following command cin.sync().
Why does this happen? Because operator>> does not read whitespaces, but std::getline() does, so when the cin >> count; statement is executed and you press enter, the new line character (from pressing enter) is left in the stream input queue, which is automatically read by std::getline() upon execution.
There are other functions that can accomplish this and perhaps someone more informed can tell us which is the best choice.
Here is a fixed version:
#include "stdafx.h"
#include <iostream>
#include <iomanip>
#include <string>
#include <cstdlib>
using namespace std;
struct Person
{
string name;
int age;
float gpa;
};
int main()
{
cout << "Please enter the number of records you wish to enter: ";
int count;
cin >> count;
Person* p = new Person[ count ];
for ( int i = 0; i < count; i++ )
{
cin.sync(); // added this to discard unused characters from input queue
cout << "Enter name: ";
getline( cin, p[ i ].name );
cout << "Enter age: ";
cin >> p[ i ].age;
cout << "Enter gpa: ";
cin >> p[ i ].gpa;
cout << endl;
}cout << endl;
cout << "This is the content of array p: " << endl;
cout << right << setw( 8 ) << "NAME" << setw( 7 ) << "AGE" << setw( 7 ) << "GPA" << endl;
cout << "--------------------------" << endl;
for ( int i = 0; i < count; i++ )
{
cout << p[ i ].name << " " << p[ i ].age << " " << p[ i ].gpa << endl;
}
return 0;
}
Notes:
You do not need to check if Person* p is nullptr because the new operator will throw a std::bad_alloc exception if it fails to allocate enough memory. Consider wrapping that memory allocation in a try catch block if you really want to.

vector with characters displaying

I have a problem with displaying the data entered in register. The folowing program that I wrote displays just the last register.( ziua=day , inregistrari=registers, data=date (ex. 03.02.2013))
#include <iostream>
#include <conio.h>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
int main()
{
char ziua[30],data[30],inregistrari[90];
int n,i;
cout<<"INPUT DATA"<<endl;
system("Pause");
cout<<"\nEnter the day in which you want to perform the register: ";
cin>>ziua;
cout<<"\nDATE:";
cin>>data;
cout<<"\nEnter the number of registers you wanna perfom for the day "<<ziua<<":";
cin>>n;
for(i=1;i<=n;i++)
{
cout<<"\nRegister "<<i<<":";
gets(inregistrari);
}
cout<<"The data for the day of "<<ziua<<" are the following: ";
cout<<"\nDATE: "<<data;
for(i=1;i<=n;i++)
cout<<"\n"<<inregistrari;
getch();
}
you are programming in C++, you should use std::string instead of C-style strings.
inregistrari[90] is an array of characters big enough to hold 1 string of max length of 89 chars (+ terminating character), but your loop seems to be treating it as an array or strings (although in this case gets(inregistrari); keeps on rewriting the same string)
function gets is generally deprecated, in C you should use fgets instead (yet this is C++, thus the real solution here should be using std::getline)
instead of C-style arrays, use std::vector<std::string> here.
printing the inregistrari is in the body of for loop, but each iteration of this loop does exactly the same thing (the printing does not depend on i in any way)
using namespace std; within the global space is a bad practice
you don't have to declare all variables at the beginning of the function, this was necessary in old ANSI C (about 20 years ago)
Here's an example how it could look like instead:
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::string day, date;
int registerCount;
std::cout << "INPUT DATA"
<< std::endl << std::endl
<< "Enter the day in which you want to perform the register: "
<< std::endl;
std::cin >> day;
std::cout << "DATE:" << std::endl;
std::cin >> date;
std::cout << "Enter the number of registers you wanna perfom for the day "
<< day << ":" << std::endl;
std::cin >> registerCount;
std::vector<std::string> registers(registerCount);
for (int i = 0; i < registerCount; ++i)
{
std::cout << "Register " << i << ":" << std::endl;
std::getline(std::cin, registers[i]);
}
std::cout << "The data for the day of " << day << " are the following: "
<< std::endl;
std::cout << "DATE: " << date << std::endl;
for (int i = 0; i < registerCount; ++i)
std::cout << registers[i] << std::endl;
}
Note that you might wrap std::getline(std::cin, registers[i]) with if statement and check whether a valid stream object has been return and in case of empty lines, it will read the empty string thus you might also make sure that !registers[i].empty().

How can I use 2D array in C++ using Visual Studio?

I'm new to this site and programming in C++ language this semester.
I have been really trying for 2 days and have asked classmates but they do not know either. A classmate said to use the 2D arrays but I don't know what that is and my professor has not gone over 2D arrays.
I am stuck and would really appreciate help.
The input file contains this:
Plain_Egg 1.45
Bacon_and_Egg 2.45
Muffin 0.99
French_Toast 1.99
Fruit_Basket 2.49
Cereal 0.69
Coffee 0.50
Tea 0.75
idk how to display all the "users" orders
Basically a receipt, like he orders this and how many, then ask "u want anything else?", then take the order number and how many again, THEN at the end give back a receipt that looks like this
bacon_and_eggs $2.45
Muffin $0.99
Coffee $0.50
Tax $0.20
Amount Due $4.14
Here is my code:
// Libraries
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>
#include <cmath>
using namespace std;
//structures
struct menuItemType {
string itemName;
double itemCost;
};
// Prototypes
void header();
void readData(menuItemType menu[]);
void Display(menuItemType menu[]);
int main() {
header();
menuItemType menu [8];
readData(menu);
Display(menu);
//system("pause");
return 0;
}
void header() {
char c= 61;
for (int i=0; i < 64; i++) {
cout << c;
}
cout << c << endl;
cout << endl;
cout << "Breakfast Menu" <<endl;
for (int i=0; i < 64; i++) {
cout << c;
}
cout << "" << c << endl;
cout << endl;
}
void readData(menuItemType item[]) {
int i=0;
ifstream in;
in.open("input.txt");
cout << fixed << setprecision(2);
while(!in.eof()) {
in >> item[i].itemName >> item[i].itemCost;
++i;
}
}
void Display(menuItemType item[]) {
int choice = 0, quantity = 0;
double total = 0.0, totalF = 0.0, tax = 0.0;
char exit = 'y';
int j = 1, z = 1, i = 1;
//the Menu
for (int i=0; i<8; i++){
cout << j << ". " << setw(18) << left << item[i].itemName << "$" << setw(10) << item[i].itemCost << endl;
j++;
}
cout << endl;
while(exit == 'y' || exit == 'Y') {
cout << "Please Enter your Selection or 0 to Exit : ";
cin >> choice;
if(cin.fail()) {
cout << "*******Invalid selection*******" << endl;
cin.clear();
cin.ignore(1000,'\n');
} else if (choice==0) {break; }
else {
cout<< "Enter Quantity: ";
cin>> quantity;
if (quantity==0) { break;}
else {
choice--;
total += (quantity * item[choice].itemCost);
tax = (total * .05);
totalF = total + tax;
cout << endl;
}
cout << endl;
cout << "======================================================" << endl;
cout << item[choice].itemName << "\t\t" << item[choice].itemCost << endl;
cout << "======================================================" << endl;
cout << "Do you want to continue (Y/N): ";
cin >> exit;
}
}
}
First off, you don't need a two dimensional array for this! You already have a one dimensional array of a suitable structure, as far as I can tell: Something which stores the name of the object and its price. What is somewhat missing is how many objects are currently in the array and how much space it has. If you want to go with the content of the entire array, make sure that you objects are correctly initialized, e.g., that the names are empty (this happens automatically, actually) and that the prices are zero (this does not).
I'm not sure if it is a copy&paste errors but the headers are incorrectly included. The include directives should look something like this:
#include <iostream>
The actual loop reading the values doesn't really work: You always need to check that the input was successful after you tried to read! Also, using eof() for checking that the loop ends is wrong (I don't know where people pick this up from; any book recommending the use of eof() for checking input loops is only useful for burning). The loop should look something like this:
while (i < ArraySize && in >> item[i].itemName >> item[i].itemCost)
++i;
}
This also fixes the potential boundary overrun in case there is more input than the array can consume. You might want to consider using a std::vector<Item> instead: this class keeps track of how many elements there are and you can append new elements as needed.
Note that you didn't quite say what you are stuck with: You'd need to come up with a clearer description of what your actual problem is. The above is just correcting existing errors and readjusting the direction to look into (i.e., forget about two dimensional arrays for now).

Sudoku game design problems C++

I have (yet another) question about chars. Thanks to those who helped me with this before. I'm trying to do mainly 4 things at this point in the program. That is:
Build a 2D array 9x9 and fill it with underscores.
Ask for a row/column and then the number that the user wishes to go into that row/column as many times as the user wants.
Replace the specified blanks with the specified numbers.
Output the entire 9x9 char array on an ASCII art Sudoku board.
(Solving will come later.)
My problem is that when I enter the row/column and the number that I want to go into that row/column the dash that was originally in that spot disappears, but the number I entered does not appear in its place.
Here is the code so far:
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
int main () {
//Builds 9x9 char array.
char dash[9][9];
for (int array=0; array<9; array++) {
for (int array2=0; array2<9; array2++) {
dash[array][array2]='_';
}
}
cout << "Input the row #, then the column #, then the number that you wish to fill that spot." << endl;
cout << "Remember that a Sudoku board is 9x9." << endl;
cout << "When you wish to finish input and solve, type all 0's and press enter." << endl;
int rowb;
char row[99];
int columnb;
char column[99];
int numb;
char num[99];
//Inputs the row/column and number to go into specified row/column.
int control=0;
while (rowb!=0){
control++;
cout << "Row: ";
cin >> rowb;
cout << "Column: ";
cin >> columnb;
cout << "Number: ";
cin >> numb;
row[control]=rowb-1;
column[control]=columnb-1;
num[control]=numb;
}
int length;
length=strlen(row);
//Replaces the _'s in the specified rows/columns and replaces them with the integer the user specified. This is where I think I'm having the problem.
for (control=0; control<length; control++) {
dash[row[control]][column[control]]=num[control];
}
//Builds the Sudoko board and outputs the full 9x9 array.
cout << "╔═══════════╦═══════════╦═══════════╗" << endl;
for (int count=0; count<3; count++) {
for (int count2=0; count2<3; count2++) {
cout << "║_" << dash[count][count2*3] << "_|_" << dash[count][count2*3+1] << "_|_" << dash[count][count2*3+2] << "_";
}
cout << "║" << endl;
}
cout << "╠═══════════╬═══════════╬═══════════╣" << endl;
for (int count=3; count<6; count++) {
for (int count2=0; count2<3; count2++) {
cout << "║_" << dash[count][count2*3] << "_|_" << dash[count][count2*3+1] << "_|_" << dash[count][count2*3+2] << "_";
}
cout << "║" << endl;
}
cout << "╠═══════════╬═══════════╬═══════════╣" << endl;
for (int count=6; count<9; count++) {
for (int count2=0; count2<3; count2++) {
cout << "║_" << dash[count][count2*3] << "_|_" << dash[count][count2*3+1] << "_|_" << dash[count][count2*3+2] << "_";
}
cout << "║" << endl;
}
cout << "╚═══════════╩═══════════╩═══════════╝" << endl;
return 0;
}
There is a problem assignment of the number entered in the loop.
//Replaces the _'s in the specified rows/columns and replaces them with the integer the user specified. This is where I think I'm having the problem.
for (control=0; control<length; control++) {
dash[row[control]][column[control]]=num[control]; //<<<--- Assignment issue.
}
You are assigning an integer value in a character array & thus when you display you will get the corresponding char for the ascii value & not the integer. Try changing the assignment as follows:
//Replaces the _'s in the specified rows/columns and replaces them with the integer the user specified. This is where I think I'm having the problem.
for (control=0; control<length; control++) {
dash[row[control]][column[control]]=num[control] + '0'; // Convert to ascii value of the integer, but will fail if not b/w 0 & 9.
}
Checking if the number entered in is between 1 & 9 is also advised if you choose to use the above observation.
Please add checks for the row & column entered as enter values which are not b/w 1 & 9 will lead to undefined behaviour due to accessing out of bound array elements if the values entered are not b/w 1 & 9.
Also as mentioned by Benjamin Lindley please update strlen code.
Hope this helps!
length=strlen(row);
This is undefined behavior, because row[0] was never initialized, and you never null terminate the string.
char row[99];
...
int control=0;
while (rowb!=0){
control++;
...
row[control]=rowb-1;
...
Notice that the first time through the loop, control is 1. So, you're setting the value of row[1], but not row[0]. Move the increment to the end of the loop. There may be some other problems, but this is the primary one responsible for the behavior you're seeing.
Also, for strlen to work, you need to null terminate the string.
And finally, you're making the same mistake you've made in this question and this question. Why aren't you seeming to get that? Chars display differently than ints. The following code will not display the number 1:
char c = 1;
std::cout << c;
Look at the answers to those other two questions.