Создание таблицы с помощью printf в c++

Я пытаюсь сделать такую ​​​​таблицу.... (Просто без точек, которые я использовал для разделения каждого элемента)

Еженедельная заработная плата:

Имя......................Должность.......Брутто......Налог......Нетто

Партнер Эбенезера Скруджа 250,00 ..62,25 .187,75

Боб Крэтчит ..........Клерк ......15.00 ....2.00 ..13.00

Вот как выглядит мой код для этой части....

for (int count=0; count < numberOfEmployees; count++)
{
    cout << "Employee: \n";
    cout << "\t Name: ";
    cin.getline (employees[count].name, EMPLOYEESIZE); 

    cout << "\t Title: ";
    cin.getline (employees[count].title, EMPLOYEESIZE);

    cout << "\t SSNum: ";
    cin >> employees[count].SSNum;

    cout << "\t Salary: ";
    cin >> employees[count].Salary;

    cout << "\t Withholding Exemptions: ";
    cin >> employees[count].Withholding_Exemptions; 
    cin.ignore();

    cout << "\n";
}


double gross;
double tax;
double net;
double adjusted_income;

cout << "\n";

cout << "Weekly Payroll: \nName \t \t Title \t Gross \t Tax \t Net \n";


for (int count=0; count < numberOfEmployees; count++)
{
    gross = employees[count].Salary;
    adjusted_income = subtraction_times (employees[count].Salary, employees[count].Withholding_Exemptions);
    tax = adjusted_income * .25;
    net = subtraction (gross, tax);

    printf ("\n%s", employees[count].name); 
}

У меня есть первая часть таблицы (часть имени), но теперь я не знаю, что делать с остальной частью таблицы. Может кто-нибудь помочь мне?

Спасибо


person Gvegas222    schedule 09.02.2012    source источник
comment
Вам нужно напечатать строку заголовка, прежде чем вы войдете в цикл. Также взгляните на setw и другие iomanipulators.   -  person dbrank0    schedule 09.02.2012
comment
Есть ли какая-то особая причина, по которой вы должны использовать printf?   -  person Mankarse    schedule 09.02.2012
comment
Скорее всего это часть задания :^)   -  person hochl    schedule 20.03.2012


Ответы (4)


Вы можете использовать printf с флагом выравнивания по левому краю (-).

printf("%-10s", "title"); // this will left-align "title" in space of 10 characters

Вот пример программы:

#include <string>
using namespace std;

int main()
{
    string name = "Bob Cratchit";
    string title = "Clerk";
    float gross = 15;
    float tax = 2;
    float net = 13;

    printf("%-25s%-20s%-10s%-10s%-10s\n", "Name", "Title", "Gross", "Tax", "Net"); 
    printf("%-25s%-20s%-10.2f%-10.2f%-10.2f\n", name.c_str(), title.c_str(), gross, tax, net); 
    return 0;
}

Выход:

Name                     Title               Gross     Tax       Net
Bob Cratchit             Clerk               15.00     2.00      13.00
person B Faley    schedule 09.02.2012
comment
Джеймс, что может быть ремонтопригодной альтернативой? - person scrafy; 10.06.2016

Самый очевидный вопрос: зачем использовать printf, когда другие инструменты более адаптированы? Другой вопрос, о котором часто забывают, заключается в том, что является (конечным) носителем вывода? Если текст будет напечатан на принтере или в текстовом поле в оконной системе, вам может не хватить работы. Шрифты в таких системах редко имеют фиксированную ширину, поэтому вам придется учитывать ширину отдельных символов. Для вывода на принтер я бы предложил вывести LaTeX, а затем выполнить его постобработку. Для вывода в окно библиотека, которую вы используете, вероятно, имеет какой-то табличный компонент, который будет выполнять форматирование за вас.

Если вы выводите, например, на какое-то устройство с фиксированной шириной шрифта, например, телетайп, вы можете использовать либо манипуляторы iostream, либо пользовательские типы. (Нет никакого способа сделать это чисто с printfвам нужны потоки ввода-вывода.) Абстрактно говоря, определение таких типов, как Name, Title и MonitaryAmount, является самым чистым решением. В этом случае вы просто определяете соответствующий оператор << для типа. Однако использование определяемого пользователем типа для имени и заголовка вместо просто std::string может быть излишним, и подход манипулятора может быть предпочтительнее. (В очень большом приложении, где отдельные типы будут оправданы, вам, вероятно, потребуется вывод в разных контекстах, и вы захотите, чтобы манипуляторы также указывали их.)

В самом простом решении можно обойтись всего двумя манипуляторами: TextField и MoneyField: каждый манипулятор будет принимать ширину поля в качестве аргумента конструктора и устанавливать соответствующие поля формата в своем операторе <<, например:

class TextField
{
    int myWidth;
public:
    TextField( int width ) : myWidth( width ) {}
    friend std::ostream&
    operator<<( std::ostream& dest, TextField const& manip )
    {
        dest.setf( std::ios_base::left, std::ios_base::adjustfield );
        dest.fill( ' ' );
        dest.width( manip.myWidth );
        return dest;
    }
};

а также

class MoneyField
{
    int myWidth;
public:
    MoneyField( int width ) : myWidth( width ) {}
    friend std::ostream&
    operator<<( std::ostream& dest, MoneyField const& manip )
    {
        dest.setf( std::ios_base::right, std::ios_base::adjustfield );
        dest.setf( std::ios_base::fixed, std::ios_base::floatfield );
        dest.fill( ' ' );
        dest.precision( 2 );
        dest.width( manip.myWidth );
        return dest;
    }
};

(На практике, вероятно, лучше использовать класс для денег. Например, вам понадобятся специальные правила округления для умножения; фактически, если вы рассчитываете налог, вам, вероятно, потребуется использовать какой-то десятичный тип, а не double, чтобы соответствовать требованиям законодательства относительно того, как он рассчитывается.)

В любом случае, учитывая приведенные выше манипуляторы, вы можете написать что-то вроде:

TextField  name( 15 );
TextField  title( 8 );
MoneyField gross( 8 );
MoneyField tax( 6 );
MoneyField net( 8 );
for ( std::vector< Employee >::const_iterator employee = employees.begin();
        employee != employees.end();
        ++ employee ) {
    std::cout << name  << employee->name()
              << title << employee->title()
              << gross << employee->salary()
              << tax   << calculateTax( employee->salary() )
              << net   << calculateNet( employee->salary() )
              << std::endl;
}

(Это предполагает, что вы очистили остальное, чтобы сделать его идиоматичным и удобным для сопровождения C++.)

person James Kanze    schedule 09.02.2012

Вместо использования вкладок для позиционирования в определенных столбцах используйте стандартные потоковые манипуляторы ввода-вывода. . Чтобы быть более конкретным, проверьте std::setw и std::left.

Что-то вроде этого:

std::cout << std::left << std::setw(25) << "Name" << std::setw(12) << "Title"
          << std::setw(11) << "Gross" << std::setw(9) << "Tax" << "Net\n";
person Some programmer dude    schedule 09.02.2012

Вы не должны смешивать printf и cout - они используют разные механизмы буферизации и могут привести к разного рода проблемам. Поскольку вы используете С++, придерживайтесь cout. Посмотрите на setw и другие манипуляторы, чтобы отформатировать вывод по мере необходимости.

person Ed Heal    schedule 09.02.2012
comment
Когда вы говорите не смешивать, вы имеете в виду не чередовать операторы printf и cout в одном блоке кода? Или вы имеете в виду выбрать один для всего вашего проекта кода (т. е. для каждого исходного файла, участвующего в вашем проекте, где вы выводите std::out)? - person Minh Tran; 16.02.2017