В каждом браузере есть своя таблица стилей по умолчанию user agent
, которую он использует, чтобы сделать неустановленные веб-сайты более четкими. Например, большинство браузеров по умолчанию делают ссылки синими и посещенными ссылками фиолетовыми, дают таблицы определенное количество границ и отступов, применяют переменную font-size
s к H1
, H2
, H3
и т. Д. И определенную сумму
Вы когда-нибудь задавались вопросом, почему кнопки Submit выглядят по-разному в каждом браузере?
Очевидно, это создает определенное количество головных болей для авторов CSS, которые не могут понять, как чтобы их веб-сайты выглядели одинаково в каждом браузере.
Используя Сброс CSS, авторы CSS могут заставить всех браузеров сбросить все свои стили до нуля, избегая при этом различий между браузерами.
. Из последовательной базы, которую вы настроили с помощью сброса, вы можете продолжить переписывать документ, сохраняя при этом уверенность в том, что различия в браузерах в их стандартном рендеринге HTML не могут коснитесь вас!
Надеюсь, это помогло, вы можете взглянуть на эту статью, Какой сброс CSS я должен использовать? .
Хорошо, на основании вашего комментария я вижу, где вы застряли и почему. (также вам нужно исправить переменные цикла в draw_square
и draw_rect
, если вы этого еще не сделали).
Ваша основная проблема - не понимание того, как обрабатывать различное количество входов на строку. Когда вы столкнулись с этой проблемой, вы правильно выбрали getline
для чтения каждой строки в buffer
, но что тогда? Вот где stringstream
имеет все значение.
Почему? Две причины: (1) это позволяет вам анализировать содержимое buffer
дословно с базовым iostream >>
, и (2) оно, при необходимости, позволяет зацикливаться до конца чтения потока, как много (или так мало) токенов, которые присутствуют, останавливаясь, когда вы достигаете конца строки (что невозможно при использовании >>
в самом файловом потоке, так как >>
занимает пустое пространство и с радостью пропускает сразу по каждому '\n'
])
Учитывая это, ваш код действительно нуждался в небольшом рефакторинге (причудливое слово для исправления перемешанной логики).
Для начала Не задавайте жестко имена файлов или , используйте магические числа в своем коде. Используйте аргументы main()
, чтобы передать имена файлов в вашу программу и объявить константы, где это необходимо. Также избегайте использования char
, который не будет занимать начальные пробелы. cin >> a_char;
так же рад читать ' '
(пробел), как и читать что-то еще.
Также поместите ваши переменные соответствующим образом. Вам не нужно объявлять все свои переменные, чтобы они были видны на протяжении main()
. Объявите / определите их в соответствующих областях.
Например:
...
#include <sstream>
...
int main (int argc, char **argv) { /* don't hardcode filenames */
ifstream infile; /* infile and buffer are the only variables */
string buffer; /* that need to be scoped at main() */
При передаче имени файла в качестве аргумента, просто подтвердите, что ваш пользователь предоставил имя файла, или предоставьте ему информацию об использовании перед отправкой под залог.
if (argc < 2) { /* validate at least 1 argument is provided */
cerr << "error: insufficient input.\n"
"usage: " << argv[0] << " filename.\n";
return 1;
}
У вас есть аргумент, теперь подтвердите, что открываете свой файл для чтения:
infile.open (argv[1]); /* open filename provided as 1st argument */
if(!infile.good()) { /* validate file is open for reading */
cerr << "failed to open infile\n";
return 1;
}
Теперь важные изменения в том, как вы управляете циклом чтения. getline
предоставляет все, что вам нужно. Просто выполните цикл, пока getline
обеспечивает хороший ввод в buffer
, например
while (getline(infile, buffer)) { /* loop reading each line */
int row, col; /* remaining variables scoped inside */
string value, code; /* your read loop, use strings */
stringstream ss(buffer); /* create stringstream from buffer */
Теперь вы читаете каждую строку и создали stringstream
из buffer
для анализа ваших символов из - за исключением примечания , как value, code
объявлены как string
и not char
- это обеспечивает простой способ пропустить начальные пробельные символы только при чтении непробельных символов. Затем вы можете просто получить доступ к нужному персонажу, например, [Тысяча сто тридцать одна].
Подтвердите, что вы хорошо прочитали code
if (!(ss >> code)) { /* validate code read into string */
cerr << "error: ss >> code.\n";
break;
}
Тогда нужно просто повторить ту же проверку правильности чтения необходимых данных, вызывая правильную функцию в каждом switch() case:
, например,
switch (code[0]) /* switch on 1st char of code */
{
case 'R':
if ((ss >> value >> row >> col)) /* validate read */
draw_rect (value[0], row, col); /* draw rect */
else /* or handle error */
cerr << "error: 'R' invalid format '" << buffer << "'\n'";
break;
case 'T':
if ((ss >> value >> row)) /* ditto for rest of shapes */
draw_triangle(value[0], row);
else
cerr << "error: 'T' invalid format '" << buffer << "'\n'";
break;
case 'D':
if ((ss >> value >> row))
draw_diamond(value[0], row);
else
cerr << "error: 'D' invalid format '" << buffer << "'\n'";
break;
case 'S':
if ((ss >> value >> row))
draw_square(value[0], row);
else
cerr << "error: 'S' invalid format '" << buffer << "'\n'";
break;
case 'E':
cout << "Exiting\n";
goto exitE; /* goto to break nested loops / scopes */
break;
default:
cout << "Invalid input, try again" << endl;
}
}
exitE:; /* the lowly goto provides a simple exit */
Вот и все, кроме закрытия infile
(что произойдет автоматически, но не помешает вручную показать ваше рассмотрение закрытия).
Заметьте , однако, используйте goto
, а не флаг, который вы использовали для exit
. В то время как goto
не получает много пресса, у него есть одна бесценная цель, которая остается - способность вырваться из вложенных циклов и областей видимости. Не используйте его, чтобы выпрыгнуть из функций (техническое ограничение longjmp
), но это может значительно упростить вашу логику для разрыва вложенных циклов и перехода на несколько строк вниз. (также полезно в той же настройке переходить через код, обычно выполняемый в конце ваших циклов при условии ошибки)
Итак, поймите его использование. Вы можете использовать флаг, но вы можете найти goto
чище в ряде настроек.
С этим, вы можете поместить его в целом (игнорируя outfile
на данный момент) с чем-то похожим на:
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdlib>
using namespace std;
void draw_rect (char out_char, int rows, int columns); // Draws a rectangle shape
void draw_square (char out_char, int rows); //Draws a square shape
void draw_triangle (char out_char, int rows);// Draws a triangle shape
void draw_diamond (char out_char, int rows); // Draws a diamond shape
int main (int argc, char **argv) { /* don't hardcode filenames */
ifstream infile; /* infile and buffer are the only variables */
string buffer; /* that need to be scoped at main() */
if (argc < 2) { /* validate at least 1 argument is provided */
cerr << "error: insufficient input.\n"
"usage: " << argv[0] << " filename.\n";
return 1;
}
infile.open (argv[1]); /* open filename provided as 1st argument */
if(!infile.good()) { /* validate file is open for reading */
cerr << "failed to open infile\n";
return 1;
}
while (getline(infile, buffer)) { /* loop reading each line */
int row, col; /* remaining variables scoped inside */
string value, code; /* your read loop, use strings */
stringstream ss(buffer); /* create stringstream from buffer */
if (!(ss >> code)) { /* validate code read into string */
cerr << "error: ss >> code.\n";
break;
}
switch (code[0]) /* switch on 1st char of code */
{
case 'R':
if ((ss >> value >> row >> col)) /* validate read */
draw_rect (value[0], row, col); /* draw rect */
else /* or handle error */
cerr << "error: 'R' invalid format '" << buffer << "'\n'";
break;
case 'T':
if ((ss >> value >> row)) /* ditto for rest of shapes */
draw_triangle(value[0], row);
else
cerr << "error: 'T' invalid format '" << buffer << "'\n'";
break;
case 'D':
if ((ss >> value >> row))
draw_diamond(value[0], row);
else
cerr << "error: 'D' invalid format '" << buffer << "'\n'";
break;
case 'S':
if ((ss >> value >> row))
draw_square(value[0], row);
else
cerr << "error: 'S' invalid format '" << buffer << "'\n'";
break;
case 'E':
cout << "Exiting\n";
goto exitE; /* goto to break nested loops / scopes */
break;
default:
cout << "Invalid input, try again" << endl;
}
}
exitE:; /* the lowly goto provides a simple exit */
infile.close();
return 0;
}
void draw_diamond (char out_char, int rows)
{
int space = 1;
space = rows - 1;
for (int i = 1; i <= rows; i++)
{
for (int k = 1; k <= space; k++)
{
cout << " ";
}
space--;
for( int k = 1; k <= 2*i-1; k++)
{
cout << out_char;
}
cout << endl;
}
space = 1;
for (int i = 1; i <= rows; i++)
{
for(int k = 1; k <= space; k++)
{
cout << " ";
}
space++;
for(int k = 1; k <= 2*(rows-i)-1; k++)
{
cout << out_char;
}
cout << endl;
}
}
void draw_triangle (char out_char, int rows)
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j <= i; j++)
{
cout << out_char;
}
cout << endl;
}
}
void draw_square (char out_char, int rows)
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < rows; j++)
{
cout << out_char;
}
cout << endl;
}
}
void draw_rect (char out_char, int rows, int columns)
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < columns; j++)
{
cout << out_char;
}
cout << endl;
}
}
( примечание: переменная цикла i, j
фиксируется на draw_square
и draw_rect
, которые казались ошибками копирования / вставки - кроме того, в ваши функции фигуры не было внесено никаких изменений)
Пример использования / вывода
[117 ]Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.