Давайте немного вернемся назад и посмотрим на общую логику, прежде чем писать код.
У вас, очевидно, есть массив больших цифр, что-то вроде
#define DIGITS 10
#define ROWS 5
const char *const bigdigit[ROWS][DIGITS] = {
{ " 0 ", " 1 ", "22 ", "33 ", " 4", "555", " 66", "777", " 8 ", " 9 " },
{ "0 0", " 1 ", " 2", " 3", " 44", "5 ", "6 ", " 7", "8 8", "9 9" },
{ "0 0", " 1 ", " 2 ", " 3 ", "444", "55 ", "66 ", " 7 ", " 8 ", " 99" },
{ "0 0", " 1 ", "2 ", " 3", " 4", " 5", "6 6", " 7 ", "8 8", " 9" },
{ " 0 ", " 1 ", "222", "33 ", " 4", "55 ", " 6 ", " 7 ", " 8 ", "99 " }
};
, так что bigdigit[row][digit]
описывает строку row
(0..4) цифры digit
(0..9).Выше каждая цифра имеет ширину 3 символа, но это не имеет значения, если строки для любого конкретного символа имеют одинаковую ширину (т. Е. "
align!).
Допустим, вы хотитечтобы напечатать 251
, используя эти большие цифры.
Поскольку printf()
выводит сверху вниз, слева направо, нам нужно сначала напечатать верхний ряд 2
, затем верхний ряд 5
затем, затем верхняя строка 1
и, наконец, новая строка, пока мы не напечатаем остальные строки.
Итак, цикл, очевидно, должен быть
/* char *message; or
char message[MAXSIZE]; contains the digits to be printed
int columns = strlen(message); is the number of digits */
for (row = 0; row < ROWS; row++) {
for (column = 0; column < columns; column++) {
switch (message[column]) {
case '0': fputs(bigdigit[row][0], stdout); break;
case '1': fputs(bigdigit[row][1], stdout); break;
case '2': fputs(bigdigit[row][2], stdout); break;
case '3': fputs(bigdigit[row][3], stdout); break;
case '4': fputs(bigdigit[row][4], stdout); break;
case '5': fputs(bigdigit[row][5], stdout); break;
case '6': fputs(bigdigit[row][6], stdout); break;
case '7': fputs(bigdigit[row][7], stdout); break;
case '8': fputs(bigdigit[row][8], stdout); break;
case '9': fputs(bigdigit[row][9], stdout); break;
}
}
fputc('\n', stdout);
}
Если вынезнакомы с fputs()
, fputs(stuff, stdout)
эквивалентно printf("%s", stuff)
.Аналогично, fputc('\n', stdout)
эквивалентно printf("\n");
.
Другими словами, внешний цикл находится над строками, а внутренний цикл - над каждой большой цифрой, которая будет отображаться.Да, мы делаем цикл ROWS над сообщением, но это нормально;нам нужно это сделать.
Хотя я тоже рекомендую не показывать законченные решения, проблема OP заключалась в том, что на самом деле был просто порядок циклов, поэтому давайте сделаем исключение и посмотрим на полный пример программы:
#include <stdlib.h>
#include <stdio.h>
#define DIGITS 10
#define ROWS 7
const char *const bigdigit[ROWS][DIGITS] = {
{ " 00 ", " 1", " 22 ", "333 ", " 44 ", "5555", " 666", "7777", " 88 ", " 99 " },
{ "0 0", "11", "2 2", " 3", " 4 4 ", "5 ", "6 ", " 7", "8 8", "9 9" },
{ "0 0", " 1", " 2", " 3", "4 4 ", "5 ", "6 ", " 7 ", "8 8", "9 9" },
{ "0 0", " 1", " 2 ", " 33 ", "44444", "555 ", "666 ", " 7 ", " 88 ", " 999" },
{ "0 0", " 1", " 2 ", " 3", " 4 ", " 5", "6 6", " 7 ", "8 8", " 9" },
{ "0 0", " 1", "2 ", " 3", " 4 ", "5 5", "6 6", " 7 ", "8 8", " 9" },
{ " 00 ", " 1", "2222", "333 ", " 4 ", " 55 ", " 66 ", " 7 ", " 88 ", "999 " }
};
int main(void)
{
char message[100];
int row, col;
while (scanf(" %99[0-9]", message) == 1) {
for (row = 0; row < ROWS; row++) {
for (col = 0; message[col] != '\0'; col++) {
fputs(bigdigit[row][message[col] - '0'], stdout);
fputc(' ', stdout);
}
fputc('\n', stdout);
}
fputc('\n', stdout);
}
return EXIT_SUCCESS;
}
bigdigit
- это двумерный массив строковых литералов.Внешнее (левое) измерение - это строка (от 0 до ROWS
-1), а внутреннее (правое) измерение - это цифра (от 0 до 9).Это позволяет нам определять массив в удобной для восприятия человеком форме, как вы можете видеть.
Массив message
ограничен 100 символами, включая нулевой байт конца строки, '\0'
поэтому спецификатор преобразования ограничивает входное преобразование 99 символами.Преобразование - [0-9]
, что означает строку, содержащую цифры ASCII от 0 до 9.
Функция scanf()
возвращает количество успешных преобразований.scanf(" %99[0-9]", message)
возвращает 1, если преобразует строку, состоящую из десятичных цифр, 0 или EOF в противном случае.Пробел перед преобразованием означает, что любые пробелы (табуляции, пробелы, новые строки) пропускаются первыми.
Поэтому в этом примере программы такие числа преобразуются по одному, пока не будет предоставлен ввод, или покавход содержит что-то кроме пробела или числа.Например, любая буква завершит программу.
Важно понимать, что когда любая из семейства функций scanf()
встречает ввод, который не может быть преобразован в соответствии с запросом, этот ввод останется во входном буфере., Неконвертируемые данные не отбрасываются. Если вы хотите, вам нужно будет отбросить эти данные.(scanf("%*[\n]");
может использоваться для отбрасывания таких данных, если шаблоны преобразования начинаются с пробела. В основном это отбрасывает остальную часть входной строки, исключая символ новой строки в конце строки. *
означает, что преобразование пропускается;результат нигде не сохраняется, и нет параметра, соответствующего этому преобразованию.)
Цикл строки такой же, как объяснено в начале этого ответа.
Цикл столбца отличается в дваособенности: вместо цикла от 0
до значения, меньшего длины строки в message
, цикл от 0
до конца строки в message
.Помните, что в C строки заканчиваются нулевым символом, '\0'
.(strlen()
просто считает количество ненулевых символов, пока не увидит нулевой символ.)
Цикл столбца также печатает пробел между каждой цифрой.Это просто так, что вам не нужно иметь буквенное пространство в самом массиве bigdigit[][]
.
"хитрой" частью в выражении bigdigit[row][message[col] - '0']
является часть message[col] - '0'
.Видите ли, отдельные символы в строках на самом деле являются просто целыми числами, обычно называемыми кодами или кодовыми точками.Практически во всех наборах символов от 0
до 9
имеют непрерывный набор кодов, так что message[col] - '0'
оценивается как ноль, если четвертый символ в сообщении [] - это ноль, один - одна цифра и т. Д., до девяти.
Второй fputc('\n', stdout);
печатает пустую строку после каждой строки больших цифр. Вот и все для программы.
Если вы скомпилируете вышеуказанную программу и введете 1237 543
, программа выведет
1 22 333 7777
11 2 2 3 7
1 2 3 7
1 2 33 7
1 2 3 7
1 2 3 7
1 2222 333 7
5555 44 333
5 4 4 3
5 4 4 3
555 44444 33
5 4 3
5 5 4 3
55 4 333
Обратите внимание, что в C стандартным вводом является буферизация строки. (То есть, когда вы вводите ввод, программа фактически видит всю строку сразу, но только когда вы нажимаете Enter.) Поскольку печать больших цифр выполняется в цикле, который одновременно захватывает одну цифру из ввода, две строки напечатаны на отдельных строках.
Если вы хотите напечатать вводные данные так, как они были указаны в строке, вам нужно прочитать всю строку (например, с помощью fgets()
) и реализовать по крайней мере пробел (в bigdigit[][]
, я имею в виду ) и измените fputs(bigdigit[row][message[col] - '0'], stdout)
обратно на оператор switch, чтобы вы могли вывести пробел. Например:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define DIGITS 10
#define ROWS 7
const char *const bigdigit[ROWS][DIGITS] = {
{ " 00 ", " 1", " 22 ", "333 ", " 44 ", "5555", " 666", "7777", " 88 ", " 99 " },
{ "0 0", "11", "2 2", " 3", " 4 4 ", "5 ", "6 ", " 7", "8 8", "9 9" },
{ "0 0", " 1", " 2", " 3", "4 4 ", "5 ", "6 ", " 7 ", "8 8", "9 9" },
{ "0 0", " 1", " 2 ", " 33 ", "44444", "555 ", "666 ", " 7 ", " 88 ", " 999" },
{ "0 0", " 1", " 2 ", " 3", " 4 ", " 5", "6 6", " 7 ", "8 8", " 9" },
{ "0 0", " 1", "2 ", " 3", " 4 ", "5 5", "6 6", " 7 ", "8 8", " 9" },
{ " 00 ", " 1", "2222", "333 ", " 4 ", " 55 ", " 66 ", " 7 ", " 88 ", "999 " }
};
int main(void)
{
char message[100], *line;
int row, col;
while (1) {
line = fgets(message, sizeof message, stdin);
if (line == NULL)
break;
if (strcspn(line, "\r\n") < 1)
break;
for (row = 0; row < ROWS; row++) {
for (col = 0; line[col] != '\0'; col++) {
switch (line[col]) {
case '0': fputs(bigdigit[row][0], stdout); fputc(' ', stdout); break;
case '1': fputs(bigdigit[row][1], stdout); fputc(' ', stdout); break;
case '2': fputs(bigdigit[row][2], stdout); fputc(' ', stdout); break;
case '3': fputs(bigdigit[row][3], stdout); fputc(' ', stdout); break;
case '4': fputs(bigdigit[row][4], stdout); fputc(' ', stdout); break;
case '5': fputs(bigdigit[row][5], stdout); fputc(' ', stdout); break;
case '6': fputs(bigdigit[row][6], stdout); fputc(' ', stdout); break;
case '7': fputs(bigdigit[row][7], stdout); fputc(' ', stdout); break;
case '8': fputs(bigdigit[row][8], stdout); fputc(' ', stdout); break;
case '9': fputs(bigdigit[row][9], stdout); fputc(' ', stdout); break;
case ' ': fputs(" ", stdout); break;
}
}
fputc('\n', stdout);
}
fputc('\n', stdout);
}
return EXIT_SUCCESS;
}
Если вы увеличиваете DIGITS
, вы можете добавить bigdigit[row][10]
и т. Д. К делу switch
, чтобы напечатать, например, буквы и тому подобное.
Поскольку пробел - это всегда просто пробел, вместо использования для него записи bigdigit
, я просто сделал его шириной в пять пробелов, включая межбуквенный пробел.
Если вы скомпилируете и запустите эту программу, она будет работать до тех пор, пока вы не предоставите ей пустую строку. Для того же самого входа 1237 543
этот выводит
1 22 333 7777 5555 44 333
11 2 2 3 7 5 4 4 3
1 2 3 7 5 4 4 3
1 2 33 7 555 44444 33
1 2 3 7 5 4 3
1 2 3 7 5 5 4 3
1 2222 333 7 55 4 333
В этой программе есть только две действительно новые вещи, по сравнению с предыдущей: во-первых, вместо scanf()
вся строка ввода считывается в буфер message[]
(ограничен на один символ меньше длины, чем размер message[]
). Выражение sizeof message
соответствует количеству символов в массиве message
, включая зарезервированное для нулевого символа конца строки. Это работает только если message
является массивом, а не если это указатель.
(Если вы динамически выделяете память для char *message
, тогда вам нужно сохранить количество символов, выделенных вами, в отдельной переменной и указать это значение fgets()
. Стандартного способа определения количества символов не существует. впоследствии вы выделили указатель, в C вы должны сами отследить его, если он вам нужен.
Вторым изменением является вызов функции strcspn(line, "\r\n")
. Он возвращает количество символов в line
до конца строки или до любого из перечисленных символов (здесь, возврат каретки или перевод строки, два символа, которые используются для перевода строки в различных комбинациях в разных ОС), что произойдет первым.
(Иногда вы видите line[strcspn(line, "\r\n")] = '\0';
, используемый для обрезки содержимого line
при первом возврате каретки или переводе строки, удаляя новую строку в конце строки, которую оставляет fgets()
. Это безопасно до тех пор, пока line
не равно NULL и содержит строку, даже если она не содержит возврата каретки или перевода строки, потому что в этом случае strcspn()
просто возвращает длину строки.)
Строка if (strcspn(line, "\r\n") < 1)
может читаться как «Если в line
нет символов, или первый символ - это возврат каретки или перевод строки, то» . Я мог бы написать это как if (line[0] == '\0' || line[0] == '\r' || line[0] == '\n')
, но я подумал, что показывать такую изящную небольшую стандартную функцию было бы уместно здесь.
Поскольку в операторе switch
нет регистра default:
, все остальные символы, кроме цифр и пробела (и те, которые вы добавляете, увеличиваете DIGITS
и добавляете их строки в массив bigdigit[][]
и выводите как новый оператор case
), полностью игнорируются.