Символы и строки
До сих пор мы работали только с числовыми данными, как целыми, так и действительными. Но очень часто (если речь идет не о сугубо научных рассчетах) приходится оперировать с текстовой информацией. В этом листочке содержится основная информация о принципах работы с символами и текстами.
Символьный тип char
Любой текст состоит из символов. Символ — это некоторый значок, изображение. Один и тот же символ можно записать по-разному, например, два человека по-разному напишут от руки букву “A”, и даже в компьютерном представлении одна и та же буква будет выглядеть по-разному, если ее отображать разными шрифтами, при этом это будет все равно один и тот же символ. Верно и другое: разные символы могут быть записаны одинаково, например, вот две разные буквы, одна — латинского алфавита, другая — русского: “A” и “А”. Несмотря на то, что они выглядят одинаково, удобней считать их разными символами.
Итак, способ хранения текстовой информации в компьютере не связан напрямую с изображением этого текста. Вместо символов хранятся их номера — числовые коды, а вот то, как выглядит символ с данным числовым кодом на экране напрямую зависит от того, какой используется шрифт для отображения символов. При этом, разумеется, следовало бы договориться о единообразном способе кодирования символов числовыми кодами, иначе текст, записанный на одном компьютере, невозможно будет прочитать на другом компьютере.
Первоначально договорились под кодирование одного символа отвести один байт, то есть 8 бит информации. Таким образом можно было закодировать 256 различных значений, то есть в записи текста можно использовать 256 различных символов. Этого достаточно, чтобы отобразить все символы латинского алфавита, цифры, знаки препинания и некоторые другие символы. Стандарт, указывающий, какие числовые коды соответствуют каким основным символам, называется ASCII. В таблицу ASCII включены символы с кодами от 0 до 127, то есть ASCII — это семибитный код. Вот так выглядит таблица ASCII:
Char Dec Oct Hex | Char Dec Oct Hex | Char Dec Oct Hex | Char Dec Oct Hex ------------------------------------------------------------------------------------- (nul) 0 0000 0x00 | (sp) 32 0040 0x20 | @ 64 0100 0x40 | ` 96 0140 0x60 (soh) 1 0001 0x01 | ! 33 0041 0x21 | A 65 0101 0x41 | a 97 0141 0x61 (stx) 2 0002 0x02 | " 34 0042 0x22 | B 66 0102 0x42 | b 98 0142 0x62 (etx) 3 0003 0x03 | # 35 0043 0x23 | C 67 0103 0x43 | c 99 0143 0x63 (eot) 4 0004 0x04 | $ 36 0044 0x24 | D 68 0104 0x44 | d 100 0144 0x64 (enq) 5 0005 0x05 | % 37 0045 0x25 | E 69 0105 0x45 | e 101 0145 0x65 (ack) 6 0006 0x06 | & 38 0046 0x26 | F 70 0106 0x46 | f 102 0146 0x66 (bel) 7 0007 0x07 | ' 39 0047 0x27 | G 71 0107 0x47 | g 103 0147 0x67 (bs) 8 0010 0x08 | ( 40 0050 0x28 | H 72 0110 0x48 | h 104 0150 0x68 (ht) 9 0011 0x09 | ) 41 0051 0x29 | I 73 0111 0x49 | i 105 0151 0x69 (nl) 10 0012 0x0a | * 42 0052 0x2a | J 74 0112 0x4a | j 106 0152 0x6a (vt) 11 0013 0x0b | + 43 0053 0x2b | K 75 0113 0x4b | k 107 0153 0x6b (np) 12 0014 0x0c | , 44 0054 0x2c | L 76 0114 0x4c | l 108 0154 0x6c (cr) 13 0015 0x0d | - 45 0055 0x2d | M 77 0115 0x4d | m 109 0155 0x6d (so) 14 0016 0x0e | . 46 0056 0x2e | N 78 0116 0x4e | n 110 0156 0x6e (si) 15 0017 0x0f | / 47 0057 0x2f | O 79 0117 0x4f | o 111 0157 0x6f (dle) 16 0020 0x10 | 0 48 0060 0x30 | P 80 0120 0x50 | p 112 0160 0x70 (dc1) 17 0021 0x11 | 1 49 0061 0x31 | Q 81 0121 0x51 | q 113 0161 0x71 (dc2) 18 0022 0x12 | 2 50 0062 0x32 | R 82 0122 0x52 | r 114 0162 0x72 (dc3) 19 0023 0x13 | 3 51 0063 0x33 | S 83 0123 0x53 | s 115 0163 0x73 (dc4) 20 0024 0x14 | 4 52 0064 0x34 | T 84 0124 0x54 | t 116 0164 0x74 (nak) 21 0025 0x15 | 5 53 0065 0x35 | U 85 0125 0x55 | u 117 0165 0x75 (syn) 22 0026 0x16 | 6 54 0066 0x36 | V 86 0126 0x56 | v 118 0166 0x76 (etb) 23 0027 0x17 | 7 55 0067 0x37 | W 87 0127 0x57 | w 119 0167 0x77 (can) 24 0030 0x18 | 8 56 0070 0x38 | X 88 0130 0x58 | x 120 0170 0x78 (em) 25 0031 0x19 | 9 57 0071 0x39 | Y 89 0131 0x59 | y 121 0171 0x79 (sub) 26 0032 0x1a | : 58 0072 0x3a | Z 90 0132 0x5a | z 122 0172 0x7a (esc) 27 0033 0x1b | ; 59 0073 0x3b | [ 91 0133 0x5b | < 123 0173 0x7b (fs) 28 0034 0x1c | < 60 0074 0x3c | \ 92 0134 0x5c | | 124 0174 0x7c (gs) 29 0035 0x1d | = 61 0075 0x3d | ] 93 0135 0x5d | >125 0175 0x7d (rs) 30 0036 0x1e | > 62 0076 0x3e | ^ 94 0136 0x5e | ~ 126 0176 0x7e (us) 31 0037 0x1f | ? 63 0077 0x3f | _ 95 0137 0x5f | (del) 127 0177 0x7f
При этом символы с кодами, меньшими 32 — это специальные управляющие символы, которые не отображаются на экране. Например, для того, чтобы обозначить конец строки в системе Linux используется один символ с кодом 10, а в системе Windows — два подряд идущих символа с кодами 13 и 10, символы с кодами 48-57 соответствуют начертанию арабских цифр (обратите внимание, символ с кодом 0 — это вовсе не символ, отображающийся на экране, как “0”), символы с кодами 65-90 — заглавные буквы буквы латинского алфавита, а если к их кодам прибавить 32, то получатся строчные буквы латинского алфавита. В промежутках между указанными диапазонами находятся знаки препинания, математические операции и прочие символы.
Но в ASCII-таблицы нет русских букв! А также нет букв сотен других национальных алфавитов. Первоначально для отображения букв национальных алфавитов использовали вторую половину возможного значения байта, то есть символы с кодами от 128 до 255. Это приводило к множеству проблем, например, поскольку 128 значений явно недостаточно для того, чтобы отобразить символы всех национальных алфавитов (даже недостаточно для того, чтобы отобразить символы одного алфавита, например, китайской письменности. Поэтому в настоящее время для кодирования символов используется стандарт Unicode, последняя версия 5.2 которого (октябрь, 2009) включает 107361 различный символ. Естественно, для кодирования Unicode-символов недостаточно одного байта на символ, поэтому используются многобайтовые кодировки (для представления одного символа необходимо несколько байт).
Мы будем работать только с символами ASCII, поэтому для представления одного символа будет использоваться только один байт.
В языке C++ для хранения однобайтового символа используется тип данных char . Переменную типа char можно рассматривать двояко: как целое число, занимающее 1 байт и способное принимать значения от -128 до 127 (тип signed char , есть также беззнаковая модификация unsigned char , принимающая значения от 0 до 255) и как один символ текста. Само по себе определение char может оказаться как знаковым, так и беззнаковым, в зависимости от операционной системы и компилятора. Поэтому использовать тип char не рекомендуется, лучше явно указывать будет ли он знаковым ( signed ) или беззнаковым ( unsigned ).
Как и целые числа, данные типа char можно складывать, вычитать, умножать и даже делить. Но если операции умножения и деления, как правило, бессмысленны, то сложение и вычитание вполне осмысленно. Например, если к символу ‘A’ прибавить 1, то получится символ ‘B’ , а если вычесть 1, то получится символ ‘@’ . То есть в следующем фрагменте кода на экран будет выведена буква B .
char c = 'A'; c = c + 1; coutВ этом примере видно, что переменным типа char можно присваивать значения, равные ASCII кодам символов, если эти символы заключать в кавычки. То есть запись 'A' будет соответствовать символу A , или ASCII коду 65.
Также в этом примере видно, что при выводе на экран переменной типа char мы увидим изображение этого символа. Как же узнать значение ASCII-кода символа? Его не нужно узнавать, сам символ - это и есть ASCII-код. А как его вывести на экран? Очень просто - нужно преобразовать значение величины типа char к значению типа int . Например, вот так:
coutИмя типа, записанное в скобочках перед значением, это и есть оператор преобразования значения к указанному типу.
Аналогично, при считывании переменной типа char через поток cout , из потока ввода считывается один символ, переменная получает значение, равное его ASCII-коду. Например, если написать программу, содержающую строчку
char c; cin >> c;запустить ее, ввести символ A (безо всяких кавычек!), то в переменную c будет записано значение 65 - ASCII-код символа A .
Переменным типа char можно и явно присваивать числовые значения. Например, можно сделать так:
#include using namespace std; int main() < unsigned char c = 'A'; cout << c << " " << (int) c << endl; c = 126; // char можно присвоить и числовое значение cout
Эта программа выведет две строки: “ A 65 ” и “ ~ 126 ”, то есть символы с ASCII-кодами 65 (A) и 126 (~) и сами ASCII-коды.
Организовать последовательное посимвольное считывание всего входного потока можно при помощи цикла while :
#include using namespace std; int main() < char c; while (cin >> c) // Цикл пока считывание успешно < // Делаем необходимые действия, // обрабатывая символ c >return 0; >В этом примере программа будет посимвольно считывать входной поток (по умолчанию — ввод с клавиатуры), пока не встретит признак конца файла. Для того, чтобы сообщить программе о завершении входного потока при вводе с клавиатуры необходимо нажать клавиши Ctrl-d в системе Linux и Ctrl-z в системе Windows.
Эта программа при считывании данных будет игнорировать символы–разделители: пробелы, символы новой строки и табуляции. Если нужно, чтобы в переменную c считывались все символы, в том числе и разделители, то необходимо для потока ввода cin установить манипулятор noskipws при помощи инструкции:
cin >> noskipws;>S; // считать строку S с клавиатуры --> >S1>>S2>>S3; --> >S) // Цикл до тех пор, пока считывание успешно --> >. -->
Строки в языке C++
Текстовая строка - это последовательность символов. Поскольку символы в строке пронумерованы, то естественным представлением для строки был бы массив символов. Так строки и представлялись в языке C - строкой считался массив символов, а для обозначения конца строки использовался символ с ASCII-кодом 0, что позволяло хранить строки переменной длины (то есть в массиве char[n] можно было хранить строки любой длины, не превосходящей n-1 . Такой способ хранения строк порождал ряд неудобств: любая строка была ограничена по длине размером массива, а чтобы вычислить длину строки необходимо было пройти по всей строке до появления нулевого символа, то есть определение длины строки требует количество операций, пропорциональное этой длине.
В языке C++ для представления строк существует более совершенный тип данных string , в основе которого лежит такой же массив символов, завершающийся нулевым символом, но содержащий еще ряд дополнительных возможностей. Для работы со строками языка C++ необходимо в начале программы подключить описание типа string , которое находится в одноименном файле:
#include
Переменная для хранения строковых данных объявляется так:
string S;Присвоить строковой переменной некоторое константное значение можно так:
S = "Hello, world!";С записью строк в тексте программы в кавычках мы уже встречались, когда выводили текст в поток cout . Обратите внимание - константы типа char записываются в одинарных кавычках, а строки - в двойных кавычках. В частности, 'A' - это символ, а "A" - это строка, состоящая из одного символа. Поэтому переменной типа char нельзя присвоить значение "A" , поскольку они имеют несовместимые типы данных.
По сути, переменная типа string является массивом символов и с каждым символом этой строки можно работать по-отдельности, обращаясь к ним по индексу, как к элементам массива. Например:
coutДля определения длины строки есть метод size() , применяемый к строке. Он возвращает целое число - количество символов в строке. Его можно использовать так:
string S; cin >> S; coutДля начала нам понадобится две операции над строками: сложение двух строк и изменение размера строки.
Основная операция над строками - сложение: например, при сложении строк "Hello, " и "world!" получится строка "Hello, world!" . Такая операция над строками называется .
Вот пример использования конкатенации строк:
string S, S1, S2; // Объявление трех строк cout > S1; // Считали строку S1 S2 = "Hello, " // Присвоили строке значение S = S2 + S1; // Использование конкатенации coutДругая операция - изменение размера строки. Для этого существует метод resize , который применяется к строке. У метода resize есть две формы записи: с одним и с двумя параметрами. Если он вызывается с одним параметром, то этот параметр задает новую длину строки. Например, так:
string S = "abcdefg" S.resize(3); coutВторой параметр метода resize задает символ, которым будут заполнены символы в строке, если размер строки увеличивается в результате изменения размера. Например:
string S = "abc" S.resize(6, 'd'); coutПри считывании строк из входного потока считываются все символы, кроме символов–разделителей (пробелов, табуляций и новых строк), которые являются границами между строками. Например, если при выполнении следующей программы
string S1, S2, S3; // объявили 3 строки cin>>S1>>S2>>S3;ввести текст ‘ Мама мыла раму ’ (с произвольным количеством пробелов между словами), то в массив S1 будет записана строка "Мама" , в S2 — "мыла" , в S3 — "раму" .
Таким образом, организовать считывание всего файла по словам, можно следующим образом:
string s; while (cin >> s) // Цикл пока считывание успешно < // Делаем необходимые действия >Если нужно считать строку со всеми пробелами, то необходимо использовать функцию getline следующим образом:
string S; getline(cin, S);В данном случае если запустить эту программу и ввести строку "Мама мыла раму" , то именно это значение и будет присвоено строке S . Считать же весь входной поток по строкам можно при помощи следующего кода:
string s; while (getline(cin, S)) // Цикл пока считывание успешно < // Делаем необходимые действия >Упражнения
3A: ASCII-код символа
Считайте со стандартного ввода символ и выведите его ASCII-код. Решите эту задачу с использованием только одной переменной типа char .
Программа получает на вход один символ с ASCII кодом от 33 до 126.
3B: Символ с данным ASCII-кодом
Считайте со стандартного ввода целое число и выведите ASCII-символ с таким кодом. Решите эту задачу с использованием только одной переменной типа int .
Программа получает на вход число от 33 до 126.
3C: Таблица ASCII
Выведите все символы ASCII с кодами от 33 до 126 и их коды в следующем виде:
! 33 " 34 # 35 . > 125 ~ 1263D: Символы в заданном интервале
Выведите подряд, без пробелов, все символы, лежащие в таблице ASCII между двумя заданными символами.
Программа получает на вход один символ с ASCII-кодом от 33 до 126, являющийся начальным символом интервала и число от 33 до 126, являющееся ASCII-кодом символа, завершающего интервал.
A 68ABCD0 5701234567893E: IsDigit
Для данного символа, считанного со стандартного ввода, проверьте, является ли он цифрой. Программа должна вывести слово YES , если символ является цифрой, или слово NO .
Решение оформите в виде функции bool IsDigit(char c) . В решении нельзя использовать циклы. В решении нельзя использовать константы с неочевидным значением типа 48 или 57.
3F: ToUpper
Напишите функцию char ToUpper(char c) , которая переводит символ в верхний регистр, то есть для строчной буквы латинского алфавита возвращает сооветствующую заглавную букву латинского алфавита, а для остальных символов возвращает тот же символ.
Считайте один символ со стандартного ввода и переведите его в верхний регистр. В решении нельзя использовать циклы. В решении нельзя использовать константы с неочевидным значением.
3G: Сменить регистр символа
Напишите функцию char CaseChange (char c) , меняющую регистр символа, то есть переводящую заглавные буквы в строчные, а строчные - в заглавные, остальные символы не меняющие.
Считайте один символ со стандартного ввода, выведите результат работы данной функции. В решении нельзя использовать циклы. В решении нельзя использовать константы с неочевидным значением.
3H: Нижний регистр
Дана строка, возможно, содержащая пробелы. Считайте эту строку и переведите все символы этой строки в нижний регистр. Решение оформите в виде функции void ToLower (string & S) , получающей в качестве параметра строку по ссылке и изменяющая символы этой строки.
Для перевода одного символа в нижний регистр напишите отдельную функцию.
Hello, world!hello, world!3I: Проверить строки на равенство
Даны две строки (возможно, с пробелами). Проверьте, равны ли они. Если строки равны, выведите слово YES , если строки не равны, выведите слово NO .
Решение оформите в виде функции bool IsEqual(const string &S1, const string & S2) .
После того, как вы решите эту задачу, вам разрешается использовать оператор == для сравнения строк.
Hi
HIBye
Bye3J: Извлечь цифры
Дана строка, возможно, содержащая пробелы. Извлеките из этой строки все символы, являющиеся цифрами и составьте из них новую строку. Решение оформите в виде функции string ExtractDigits (const string & S) , получающей на вход исходную строку S и возвращающую новую строку, содержащую только цифры данной строки.
Указание. Заведите строку Answer , пройдите по всем символам данной строки, при обнаружении цифры добавляйте ее в конец строки Answer , увеличивая ее размер на 1. По завершении цикла верните значение Answer .
3K: Значение выражения - 1
Дана строка, состоящая из n цифр, между которыми стоит n-1 знак операции, каждый из которых может быть либо +, либо -. Вычислите значение данного выражения.
Решение оформите в виде функции int Evaluate(const string & S) .
3L: StrToInt
Дана строка, содержащее запись в виде символов целого числа от 0 до 10 9 -1. Определите значение этого числа в виде переменной int. Решение задачи оформите в виде функции int StrToInt (const string & S) .
Функция main должна быть такой:
int main() < string S; cin >> S; cout
3M: IntToStr
Дана целое число от -10 9 +1 до 10 9 -1. Запишите это число в строку, то есть выполните преобразование, обратное предыдущей задаче (но только допускаются отрицательные числа).
Решение задачи оформите в виде функции string IntToStr (int n) .
Функция main должна быть такой:
int main() < int n; cin >> n; cout
4A: Самое длинное слово
Дана строка. Найдите в этой строке самое длинное слово и выведите его. Если в строке несколько слов одинаковой максимальной длины, выведите первое из них. Решение оформите в виде функции string LongestWord (const string & S) .
In a hole in the ground there lived a hobbit.ground4B: Слова с прописной буквы
Дана строка. Измените регистр символов в этой строке так, чтобы первая буква каждого слова была заглавной, а остальные буквы - строчными.
Решение оформите в виде функции void Capitalization (string & S) .
In a hole in the ground there lived a hobbit.In A Hole In The Ground There Lived A Hobbit.4C: Шифр Цезаря
В шифре Цезаря каждый символ заменяется на другой символ, третий по счету в алфавите после данного, с цикличность. То есть символ A заменяется на D, символ B - на E, символ C - на F, . символ Z на C. Аналогично строчные буквы заменяются на строчные буквы. Все остальные символы не меняются.
Дана строка, зашифруйте ее при помощи шифра Цезаря. Решение оформите в виде функции void CaesarCipher (string & S) .
Указание: сделайте функцию char CaesarCipher (char c) , шифрующую один данный символ.
In a hole in the ground there lived a hobbit.Lq d kroh lq wkh jurxqg wkhuh olyhg d kreelw.4D: Значение выражения - 2
Дано выражение одно из следующих видов: “A+B”, “A-B” или “A*B”, где A и B - целые числа от 0 до 10 9 . Определите значение этого выражения.
Решение оформите в виде функции Eval(const string & S) .
100-1014E: Значение выражения - 3
Дана строка, содержащая одно или более целых чисел от 0 до 10 9 , разделенных знаками “+” или “-”. Вычислите значение этого выражения.
Решение оформите в виде функции Eval(const string & S) .
21+7-104F: Поиск подстроки
Даны две строки, возможно, содержащие пробелы. Выведите слово YES , если первая строка является подстрокой второй строки или слово NO в противном случае.
Решение оформите в виде функции bool IsSubstring(const string & Pattern, const string & Source) .
hole in the ground
In a hole in the ground there lived a hobbit.hole on the ground
In a hole in the ground there lived a hobbit.5A: Look-and-say sequence
Продолжите последовательность чисел:
1 11 21 1211 111221 312211 13112221 1113213211 .Дано натуральное число \(N\). Выведите \(N\)-й член этой последовательности.
12115B: Палиндром - 2
Дана строка, возможно, содержащая пробелы. Определите, является ли эта строка палиндромом, при условии, что заглавные и строчные буквы не различаются, а все символы, не являющиеся буквами, должны быть пропущены. Выведите слово YES , если слово является палиндромом и словов NO , если не является.
Решение оформите в виде функции bool IsPalindrome (const string & S) . При решении этой задачи нельзя пользоваться вспомогательными массивами или строками.
Was it a rat I saw?abca5C: Удалите лишние пробелы
Строка состоит из одного или нескольких слов, разделенных одним или несколькими пробелами. Удалите из строки лишние пробелы: два и более подряд идущих пробелов замените на один и удалите все пробелы в начале и в конце строки.
Сложность алгоритма должна быть пропорциональная длине исходной строки.
После вывода результата на экран выводите обязательно символ конца строки!
В примере ниже для наглядности пробелы изображаются при помощи символа “·”.
·one··two···three··one·two·three5D: Значение выражения - 4
Строка состоит из целых чисел, принимающих значения от 0 до 10 9 , разделенных знаками операций “+”, “-” и “*”. Вычислите значение этого выражения выполняя действия по правилам арифметики.
Тесты к этой задаче закрытые.
Как вывести символы из строки?
Всем привет! Прошу помощи, дали такое задание: "Программа, которая читает строку длиной до 20 символов от пользователя (необходимо выяснить, не превышает ли строка заданную длину, если да, то нужно ввести заново), подсчитывает и перечисляет количество гласных, согласных, знаков препинания, чисел и других символов (через запятую). Пример: слово Auto, гласные: 3 - A, u, o и т. д." .
Код на поиск и подсчет гласных, согласных и т.д. уже есть. Не знаю как теперь вывести все посчитанные символы из строки, и как поставить условие что, если строка больше 20 символов, то надо ввести ее заново? Помогите пожалуйста.#include #include #define N 21 int main()< char str[N]; const char vovels[]="eyuioaEYUIOA"; const char consonants[]="qwrtpsdfghjklzxcvbnmQWRTPFGHJKLZXCVBNM"; char digits[]="0123456789"; const char punctuation[]=". ;!?\"()-"; const char symbols[]="@#$%^&*<>[]<>_+=\'¹%|\\/`~"; const char spaces[]=" "; int v, c, d, p, s, sp; v = c = d = p = s = sp = 0; printf("Enter a string no more than 20 symbols :\n\n"); gets(str); for (int i=0; str[i] != '\0'; i++) if (strchr(vovels,str[i])) v++; else if (strchr(consonants,str[i])) c++; else if (strchr(digits,str[i])) d++; else if (strchr(punctuation,str[i])) p++; else if (strchr(symbols,str[i])) s++; else if (strchr(spaces,str[i])) sp++; printf("\nVowels: %d\n", v); printf("\nConsonants: %d\n", c); printf("\nDigits: %d \n", d); printf("\nPunctuation: %d\n", p); printf("\nSymbols: %d\n", s); printf("\nSpaces: %d\n", sp); return 0; >
- Вопрос задан более трёх лет назад
- 458 просмотров
2 комментария
Простой 2 комментария
Saboteur @saboteur_kiev
Так а что вы пытались сделать, и что не получилось?
А то такое ощущение, что вы у кого-то стырили кусок кода, в котором даже не попытались разобраться, и ждете пока вам все остальное сделают.
Ну попробуйте же приложить хоть каплю усилий самостоятельно?

Saboteur, Ага, есть такое впечатление. Массивы названы правильно, хотя студенты обычно не задуряются такими вещами 🙂
Решения вопроса 0
Ответы на вопрос 2

Внимание! Изменился адрес почты!
man strlen (и даже неудобно такое писать - strlen() - это одна из первых строковых функций 🙂 )
man calloc
Для перечисления нужно завести отдельные массивы и копировать туда символ если условие сработало. А потом этот массив просто вывести.
Кроме того, статические массивы - зло, память надо брать динамически. Код я не привожу намеренно, потому что Вы учитесь и Ваше обучение и состоит в изучении того, какие есть строковые функции а не в копипастинге. Как основа эта программа годится. Но в ней нужно:
- заменить статическую память на динамическую
- после чтения строки проверить ее длину, если она > 20 - спросить заново, что нас естественно приводит к тому, что запрос будет делаться в бесконечном цикле
- в разборочном if не только крутить нужные счетчики, но и копировать символ в соответствущий массив.
- после окончания разбора вывести все отобранные массивы.
Ответ написан более трёх лет назад
Комментировать
Нравится Комментировать
Wundarshular @Wundarshular
Прежде всего настоятельно рекомендую сначала ознакомиться с основами языка, а также используемыми вами функциями ввода вывода. Язык С очень прост: если вы хотите выстрелить себе в ногу, вы стреляете.
Беглый просмотр вашего кода показывает, что вы не заботитесь о входных данных. Например, вот эта конструкция хоть и позволяет вам считать строку, но не даёт никаких гарантий, что она не превысит размер в 21 символ.
#define N 21 . char str[N]; printf("Enter a string no more than 20 symbols :\n\n"); gets(str);
А вот здесь вы наивно надеетесь, что у строки точно есть конец.
for (int i=0; str[i] != '\0'; i++)
Язык С очень прост: если вы хотите считать строку, вы её считаете. Но какой вы её получите - это ваша проблема.
Что до вашей задачи, то, полагаю, самым простым способом в вашем случае будет цикл в цикле: главным циклом вы проходитесь по полученной строке, побочными циклами ищите совпадения в ваших справочниках (массивы vovels и тд) и при нахождении оного либо выводите сразу, либо копируете символ куда-либо для вывода позже.
Вы значительно упростите код в этой части, если посмотрите таблицу ASCII.
Задача ограничения длины решается, например, чтением справочника языка - all-ht.ru/inf/prog/c/func/fgets.html - или просто бесцеремонным обрубанием введённой строки. Для принуждения повторного ввода, думаю, вам подойдёт while либо do while - что больше нравится.
Вывод символa по ascii коду
%c - выводит одиночный символ.
%s - выводит строку, а строка в С должна завершаться нулем.
Отслеживать
3,856 1 1 золотой знак 16 16 серебряных знаков 28 28 бронзовых знаков
ответ дан 9 окт 2016 в 12:30
847 4 4 серебряных знака 7 7 бронзовых знаков
Стоит добавить, что строка не только должна завершаться нулем, но и передаваться должен адрес строки, а не само значение как в случае с символом
9 окт 2016 в 12:34
@Mike: Поскольку в C по большому счёту нету строк (они эмулируются указателями), то передать саму строку, боюсь, невозможно.
9 окт 2016 в 12:43
В данном предложении
printf("%s", (char)a);
значение выражения (char)a рассматривается как адрес строки, завершаемой 0, так как символ форматирования %s используется для вывода строк с завершающим 0.
Для вывода отдельного символа вы можете использовать символ форматирования %c . В этом случае нет никакой необходимости использовать приведение типов (char)a , так как на самом деле аргумент будет снова преобразован к типу int . То есть вы можете просто записать
printf( "%c", a );
Отслеживать
ответ дан 9 окт 2016 в 12:51
Vlad from Moscow Vlad from Moscow
44.8k 3 3 золотых знака 38 38 серебряных знаков 89 89 бронзовых знаков
Самом смешное, что при прямом порядке байт (на архитектуре типа x86) можно просто указать &a - и этот dirty hack 🙂 сработает. Поскольку int - это все же обычно 4 байта (ну самая малость на 16-битных DOS'ах - 2), а ASCII-код помещается в одном байте, то второй (и последующие) будут нулевыми, так что &a по сути получается указателем на строку из одного символа. Так что
#include #include int main()
как ни смешно, сработает - при указанных выше условиях.
Отслеживать
ответ дан 9 окт 2016 в 14:41
219k 15 15 золотых знаков 120 120 серебряных знаков 230 230 бронзовых знаков
- c
- ascii
-
Важное на Мете
Похожие
Подписаться на ленту
Лента вопроса
Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.
Дизайн сайта / логотип © 2024 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2024.1.26.3951
Синтаксис спецификации форматирования: printf и wprintf функции
Различные функции printf и wprintf принимают строку формата и необязательные аргументы и создают форматированную последовательность символов для выходных данных. Строка формата не содержит ни одной или содержит несколько директив, которые являются либо литеральными символами для выходных данных, либо закодированными спецификациями преобразования, описывающими способ форматирования аргумента в выходных данных. Эта статья описывает синтаксис для кодирования спецификаций преобразования в строке формата. Список этих функций см. в разделе Потоковый ввод-вывод.
Спецификация преобразования состоит из необязательных и обязательных полей, имеющих следующий вид:
Каждое поле спецификации преобразования — это символ или число, указывающее конкретный параметр формата или описатель преобразования. Обязательное поле type определяет тип преобразования, которое применяется к аргументу. Необязательные флаги, ширина и точность полей определяют другие аспекты формата, такие как начальные пробелы или нули, обоснование и отображаемая точность. Поле size указывает размер использованного и преобразованного аргумента.
Базовая спецификация преобразования содержит только символ процента и символ type. Например, %s определяет преобразование строк. Чтобы вывести символ знака процента, используйте %% . Если за символом процента следует символ, который не имеет смысла в поле формата, вызывается обработчик недопустимого параметра. Дополнительные сведения см. в разделе "Проверка параметров".
Для обеспечения безопасности и стабильности убедитесь, что строки спецификации преобразования формата не определены конечным пользователем. Например, рассмотрим программу, которая предлагает пользователю ввести имя и сохраняет введенные данные в строковой переменной с именем user_name . Чтобы распечатать user_name , никогда не сделайте следующее:
printf( user_name ); /* Danger! If user_name contains "%s", program will crash */
Вместо этого используйте следующий код:
printf( "%s", user_name );
В Visual Studio 2015 printf были объявлены inline и scanf перемещены в заголовки и семейства функций. Если вы переносите старый код, вы можете увидеть LNK2019 в связи с этими функциями. Дополнительные сведения см. в журнале изменений Visual C++ 2003 – 2015.
Спецификатор преобразования типов
Символ спецификации преобразования type определяет, как должен интерпретироваться соответствующий аргумент: как символ, строка, указатель, целое число или число с плавающей запятой. Символ type — единственное обязательное поле спецификации преобразования; он указывается после всех необязательных полей.
Аргументы, которые следуют за строкой формата, интерпретируются согласно соответствующему символу type и необязательному префиксу size. Преобразования для типов char символов и wchar_t указываются с помощью или C однобайтовой и многобайтовой и широкой символьной строки задаются с c помощью s или S в зависимости от используемой функции форматирования. Аргументы символов и строк, указанные с помощью и c s интерпретируются как char char* и семейными printf функциями, а также wchar_t wchar_t* как и семейными функциями wprintf . Аргументы символов и строк, указанные с помощью и C S интерпретируются как wchar_t wchar_t* и семейными printf функциями, а также char char* как и семейными функциями wprintf . Это поведение зависит от Корпорации Майкрософт. По историческим причинам wprintf функции используют c и s ссылаются на wchar_t символы, а также C S указывают узкие символы.
Целые типы, такие как short , int , long long long и их unsigned варианты, указываются с помощью d , , i , o , u x и X . Типы с плавающей запятой, такие как float double , e f A E и long double , указываются с помощью , a , F g и . G По умолчанию, если они не изменяются префиксом размера , целочисленные аргументы принужаются к int типу и аргументы с плавающей запятой принуживаются к double . В 64-разрядных системах int используется 32-разрядное значение. Поэтому 64-разрядные целые числа будут усечены при форматировании выходных данных, если не используется префикс ll размера или I64 не используется. Типы указателей, указанные с помощью p размера указателя по умолчанию для платформы.
Только для систем Майкрософт:
Символ Z типа и поведение c символов , C s а S также символов типов при их использовании с printf функциями wprintf — расширения Майкрософт. Стандарт ISO C использует и s согласованно используется c для узких символов и строк, а C S также для расширенных символов и строк во всех функциях форматирования.
Символы поля типа
| Символ типа | Аргумент | Формат вывода |
|---|---|---|
| c | Символ | При использовании с функциями printf определяет однобайтовый символ; при использовании с функциями wprintf определяет расширенный символ. |
| C | Символ | При использовании с функциями printf определяет расширенный символ; при использовании с функциями wprintf определяет однобайтовый символ. |
| d | Целое | Десятичное целое число со знаком. |
| i | Целое | Десятичное целое число со знаком. |
| o | Целое | Восьмеричное целое число без знака. |
| u | Целое | Десятичное целое число без знака. |
| x | Целое | Целое число без знака; использует значение " abcdef ". |
| X | Целое | Целое число без знака; использует значение " ABCDEF ". |
| e | С плавающей запятой | Подписанное значение с формой [ - ]dddd e [ + - |]dd[d], где d — одна десятичная цифра, dddd — одна или несколько десятичных цифр в зависимости от указанной точности или шести по умолчанию, а dd[d] — две или три десятичные цифры в зависимости от формата вывода и размера экспонента. |
| E | С плавающей запятой | Идентичен формату e , за исключением того, что E вместо e представления экспонента. |
| f | С плавающей запятой | Подписанное значение, которое имеет форму [ - ]dddd . dd, где d имеет одну или несколько десятичных цифр. Количество цифр перед десятичной запятой зависит от величины числа, а количество знаков после десятичной запятой зависит от указанной точности либо используется шесть по умолчанию. |
| F | С плавающей запятой | Идентичен формату, за исключением бесконечности и выходных f данных NaN. |
| g | С плавающей запятой | Подписанные значения отображаются в f формате или e формате, в зависимости от того, что является более компактным для заданного значения и точности. Формат e используется только в том случае, если экспонент значения меньше -4 или больше или равен аргументу точности . Нули в конце отбрасываются, а десятичная запятая отображается только в том случае, если за ней следует хотя бы одна цифра. |
| G | С плавающей запятой | Идентичен формату g , за исключением того, что e E вместо этого представляет экспонент (где это необходимо). |
| a | С плавающей запятой | Подписанное шестнадцатеричное значение двойной точности с плавающей запятой, которое имеет форму [] 0x hh + | - p []dd, где h.hh являются шестнадцатеричными цифрами (с использованием строчных букв) мантисса, и dd — один или несколько цифр для экспонента. - Точность определяет количество цифр после запятой. |
| A | С плавающей запятой | Подписанное шестнадцатеричное значение двойной точности с плавающей запятой, которое имеет форму [ - ] 0X hhh P [ - + |]dd, где h.hhhh являются шестнадцатеричными цифрами (используя буквы букв) мантисса, и dd — один или несколько цифр для экспонента. Точность определяет количество цифр после запятой. |
| n | Указатель на целое число | Число символов, которые успешно записаны на данный момент в поток или буфер. Это значение хранится в целом числе, адрес которого указан в качестве аргумента. Размер целочисленного значения, на которое ссылается указатель, управляется префиксом спецификации размера аргумента. Описатель n отключен по умолчанию. Дополнительные сведения см. в примечании по безопасности. |
| p | Тип указателя | Отображение аргумента в виде адреса в шестнадцатеричных цифрах. |
| s | Строка | При использовании с функциями printf определяет строку однобайтовых или многобайтовых символов; при использовании с функциями wprintf определяет строку расширенных символов. Символы отображаются до первого нулевого символа или до тех пор, пока не будет достигнуто значение precision. |
| S | Строка | При использовании с функциями printf определяет строку расширенных символов; при использовании с функциями wprintf определяет строку однобайтовых или многобайтовых символов. Символы отображаются до первого нулевого символа или до тех пор, пока не будет достигнуто значение precision. |
| Z | Структура ANSI_STRING или UNICODE_STRING | VS 2013 и более ранних версий Когда адрес ANSI_STRING или UNICODE_STRING структура передается в качестве аргумента, отображает строку, содержащуюся в буфере, на которую указывает Buffer поле структуры. Используйте префикс модификатора размера для указания аргумента w UNICODE_STRING , например %wZ . Поле Length структуры должно содержать значение длины строки в байтах. Поле MaximumLength структуры должно содержать значение длины буфера в байтах. |
Универсальная среда выполнения C (UCRT)
Существует известная проблема в UCRT, которая в настоящее время поддерживается для обеспечения совместимости. S Как и описатель, Z описатель без префикса модификса размера ссылается на UNICODE_STRING использование узкой функции печати (например printf ) и ANSI_STRING при использовании широкой функции печати (например wprintf ).
Вместо этого Z используйте для hZ указания ANSI_STRING значения . wZ (или lZ ) можно по-прежнему использовать для указания UNICODE_STRING значения .
В Visual Studio 2015 и более поздних версиях, если аргумент, соответствующий описатель преобразования с плавающей запятой ( a , , f E e F A g ) G является бесконечным, неопределенным или NaN, форматированные выходные данные соответствуют стандарту C99. В этой таблице перечислены форматированные выходные данные.
| Значение | Выходные данные |
|---|---|
| Infinity | inf |
| Несигнальное значение NaN | nan |
| Сигнальное значение NaN | nan(snan) |
| Неопределенное значение NaN | nan(ind) |
Любой из этих строк может быть префиксирован знаком. Если символ описателя преобразования type с плавающей запятой является прописной буквой, выходные данные форматируются также прописными буквами. Например, если спецификатором формата является %F вместо %f , бесконечность форматируется как INF вместо inf . Функции scanf также могут анализировать эти строки, поэтому эти значения могут совершать круговой путь через функции printf и scanf .
До выхода Visual Studio 2015 в среде CRT использовался другой нестандартный формат для выходных данных значений бесконечности, неопределенных значений и значений NaN.
| Значение | Выходные данные |
|---|---|
| + Бесконечность | 1.#INF случайные цифры |
| -Бесконечности | -1.#INF случайные цифры |
| Неопределенное (то же, что и не число без вызова исключения) | цифра .#IND случайные цифры |
| Не число | цифра .#NAN случайные цифры |
Любой из этих строк может быть префиксирован знаком и может быть отформатирован по-разному в зависимости от ширины поля и точности, иногда с необычными эффектами. Например, печать 1.#J , printf("%.2f\n", INFINITY) так как #INF будет "округлено" до двух цифр точности.
Если аргумент, который соответствует %s или %S , или поле Buffer аргумента, который соответствует %Z , является указателем NULL, отображается значение "(NULL)".
Во всех экспоненциальных форматах минимальное отображаемое количество цифр показателя степени по умолчанию равно двум (три используются только при необходимости). С помощью _set_output_format функции можно задать число цифр, отображаемых в три для обратной совместимости с кодом, написанным для Visual Studio 2013 и раньше.
%n Так как формат по сути небезопасн, он отключен по умолчанию. При %n обнаружении в строке формата вызывается обработчик недопустимых параметров, как описано в разделе проверки параметров. Сведения о включении %n поддержки см. в статье _set_printf_count_output .
Директивы флагов
Первое необязательное поле в спецификации преобразования содержит директивы флага. Это поле содержит ноль или несколько символов флагов, которые указывают выходное обоснование и контрольные выходные данные знаков, пустые значения, начальные нули, десятичные точки и шестнадцатеричные префиксы. В спецификации преобразования может быть указано несколько директив флагов, и символы флагов могут размещаться в любом порядке.
Символы флагов
| Флаг | Значение | По умолчанию |
|---|---|---|
| - | Выравнивание результата по левому краю в пределах заданной ширины поля. | Выравнивание по правому краю. |
| + | Используйте знак (+ или -), чтобы префиксировать выходное значение, если оно имеет подписанный тип. | Знак отображается только для отрицательных значений со знаком –. |
| 0 | Если ширина префиксирована 0 , начальные нули добавляются до достижения минимальной ширины. Если указаны одновременно 0 и - , знак 0 игнорируется. Если 0 задан для целочисленного формата ( i , , u x , X , , o ) d и спецификации точности также присутствуют ( например, %04.d — 0 игнорируются). Если 0 задано для a формата с A плавающей запятой, начальные нули добавляются в мантиссу после 0x префикса или 0X префикса. | Без заполнения. |
| пустой (" ") | Используйте пустое значение, чтобы префиксировать выходное значение, если оно подписано и положительно. Пустой префикс игнорируется, если одновременно с ним присутствует флаг +. | Пустой префикс не отображается. |
| # | Если он используется с параметром o , x или X форматом # , флаг использует 0 0x (или 0X соответственно) префикс любого выходного значения, отличного от нуля. | Префикс не отображается. |
| При использовании с флагом e , E , f a F A или форматированием # флаг заставляет выходное значение содержать десятичную точку. | Десятичный разделитель появляется, только если после него есть цифры. | |
| Если используется в сочетании с форматом g или G , флаг # принудительно добавляет десятичный разделитель к выходному значению и запрещает отбрасывать конечные нули. |
Спецификация ширины
В спецификации преобразования необязательное поле спецификации ширины отображается после любых символов флага. Аргумент width — это неотрицательное целое число, которое управляет минимальным числом символов, которые являются выходными. Если количество символов в выходном значении меньше заданной ширины, к значениям слева или справа (в зависимости от того, определен ли флаг выравнивания по левому краю ( - )) добавляются пробелы, в количестве, необходимом для достижения минимальной ширины. Если width префикс равен 0, начальные нули добавляются в целочисленные или с плавающей запятой преобразования до достижения минимальной ширины, за исключением случаев, когда преобразование равно бесконечности или NaN .
Спецификация ширины никогда не вызывает усечения значения. Если число символов в выходном значении больше указанной ширины или если width оно не указано, все символы значения являются выходными, при условии точной спецификации.
Если в качестве спецификации ширины указана звездочка ( * ), значение ширины задается аргументом int из списка аргументов. Аргумент width должен предшествовать значению, отформатируемого в списке аргументов, как показано в этом примере:
printf("%0*d", 5, 3); /* 00003 is output */
Отсутствующее или небольшое width значение в спецификации преобразования не приводит к усечению выходного значения. Если результат преобразования превышает width значение, поле расширяется, чтобы содержать результат преобразования.
Спецификация точности
В спецификации преобразования третье необязательное поле является спецификацией точности. Он состоит из периода ( . ), за которым следует неотрицательное целое число, которое в зависимости от типа преобразования указывает количество строковых символов, число десятичных разрядов или число значимых цифр, которые должны быть выходными.
В отличие от спецификации ширины, спецификация точности может вызывать либо усечение выходного значения, либо округление значения с плавающей запятой. Если precision задано значение 0, а преобразованное значение равно 0, результат не выводит символов, как показано в этом примере:
printf( "%.0d", 0 ); /* No characters output */
Если спецификация точности представляет собой звездочку ( * ), аргумент int из списка аргументов предоставляет значение. В списке аргументов аргумент precision должен предшествовать форматируемому значению, как показано в следующем примере:
printf( "%.*f", 3, 3.14159265 ); /* 3.142 output */
Символ type определяет интерпретацию precision или точность по умолчанию при precision опущении, как показано в следующей таблице.
Влияние значений точности на тип
| Тип | Значение | По умолчанию |
|---|---|---|
| a , A | Точность определяет количество цифр после запятой. | Точность по умолчанию — 13. Если точность равна 0, десятичная запятая не выводится, если не используется флаг # . |
| c , C | Точность не применяется. | Символ выводится. |
| d , i , o , u , x , X | Точность определяет минимальное выводимое количество цифр. Если количество цифр в аргументе меньше значения precision, выходное значение дополняется слева нулями. Значение не усечено, если число цифр превышает точность. | Точность по умолчанию — 1. |
| e , E | Выводимое количество знаков дробной части задается спецификацией точности. Последняя выводимая цифра округляется. | Точность по умолчанию — 6. Если точность равна 0 или период ( . ) отображается без числа после него, десятичная точка не выводится. |
| f , F | Значение точности задает количество цифр после десятичной запятой. Если десятичная запятая присутствует, перед ней присутствует по крайней мере одна цифра. Значение округляется до соответствующего количества цифр. | Точность по умолчанию — 6. Если точность равна 0 или если период ( . ) отображается без числа после него, десятичная точка не выводится. |
| g , G | Точность определяет максимальное выводимое количество значащих цифр. | Выводятся шесть значащих цифр, а конечные нули усекаются. |
| s , S | Точность определяет максимальное количество выводимых символов. Символы, выходящие за рамки precision, не выводятся. | Символы печатаются до тех пор, пока не будет найден пустой символ. |
Спецификация размера аргумента
В спецификации преобразования поле size — это модификатор длины аргумента для описателя преобразования type. Префиксы поля размера в поле типа , j h hh , l , (строчные буквы), L , I w t z ll (верхний регистр i), I32 и I64 —укажите "размер" соответствующего аргумента — длинный или короткий, 32-разрядный или 64-разрядный, однобайтовый или широкий символ в зависимости от того, что они изменяют. Эти префиксы размера используются с символами type в семействах функций printf и wprintf для определения интерпретации размеров аргументов, как показано в следующей таблице. Поле size является необязательным для некоторых типов аргументов. Если префикс размера не указан, модуль форматирования использует целые аргументы, например подписанные или не подписанные char , short , int , long и типы перечисления как 32-разрядные типы int , а аргументы float , double и long double с плавающей запятой используются как 64-разрядные типы double . Такое поведение соответствует правилам повышения уровня аргументов по умолчанию для списков аргументов переменных. Дополнительные сведения о продвижении аргументов см. в разделе Многоточие и аргументы по умолчанию в выражениях Postfix. В 32-разрядных и 64-разрядных системах спецификация преобразования 64-разрядного целочисленного аргумента должна содержать префикс ll размера или I64 . В противном случае поведение модуля форматирования не определено.
Некоторые типы имеют разный размер в 32-разрядном и 64-разрядном коде. Например, size_t на 32 бита длиннее в коде, скомпилированном для x86, и на 64 бита длиннее в коде, скомпилированном для x64. Чтобы создать код форматирования для типов с переменным количеством байт, не зависящий от платформы, можно использовать модификатор размера аргумента с переменным количеством байт. Вместо этого используйте модификатор размера 64-разрядного аргумента и явно повысить тип аргумента переменной ширины до 64 бит. Модификатор размера аргумента ( I в верхнем регистре i) обрабатывает целые аргументы переменной ширины, но рекомендуется использовать модификаторы типа j t z и модификаторы для переносимости.
Префиксы размера для описателей типов формата printf и wprintf
| Чтобы указать | Используемый префикс | Со спецификатором типа |
|---|---|---|
| char unsigned char |
hh | d , i , o , u , x или X |
| short int short unsigned int |
h | d , i , o , u , x или X |
| __int32 unsigned __int32 |
I32 | d , i , o , u , x или X |
| __int64 unsigned __int64 |
I64 | d , i , o , u , x или X |
| intmax_t uintmax_t |
j или I64 | d , i , o , u , x или X |
| long double | l (строчная буква L) или L | a , A , e , E , f , F , g или G |
| long int long unsigned int |
l (строчная L) | d , i , o , u , x или X |
| long long int unsigned long long int |
ll (строчные буквы LL) | d , i , o , u , x или X |
| ptrdiff_t | t или I (верхний регистр i) | d , i , o , u , x или X |
| size_t | z или I (верхний регистр i) | d , i , o , u , x или X |
| Однобайтовый символ | h | c или C |
| Расширенный символ | l (строчная буква L) или w | c или C |
| Строка однобайтовых символов | h | s , S или Z |
| Строка расширенных символов | l (строчная буква L) или w | s , S или Z |
Типы ptrdiff_t и size_t являются __int32 или unsigned __int32 на 32-разрядных платформах и __int64 или unsigned __int64 на 64-разрядных платформах. I Префиксы (верхний регистр i), j t и z размеры принимают правильную ширину аргумента для платформы.
В Visual C++ хотя long double является отдельным типом, он имеет то же внутреннее представление, что и тип double .
Описатель hc или описатель типов является синонимом c функций printf и функций wprintf C hC . Описатель lc типов или wC описатель типов является синонимом функций printf C и функций c wprintf . lC wc Описатель hs или описатель типов является синонимом s функций printf и функций wprintf S hS . Описатель ls типов или wS описатель типов является синонимом S функций printf и функций s wprintf . lS ws
Только для систем Майкрософт:
I Префиксы модификатора размера аргументов (прописные буквы i), I32 I64 а также w префиксы размера аргументов являются расширениями Майкрософт и не совместимы с ISO C. Префикс h при использовании с данными типа char и l префиксом (строчным регистром L) при использовании с данными типа double являются расширениями Майкрософт.