@DrummerIF, это замечательно, что Вы стараетесь.
По поводу текущего кода.
Писать text[c + 1] = 0
не только излишне, но и опасно. Излишне, поскольку (читаем man fgets) fgets всегда пишет ноль после считанных в буфер данных. Если мы вводим (с клавиатуры) больше символов, чем может поместиться в буфер, то (для Вашего случая fgets(text, 12, stdin)
) в text[]
будет помещено 11 байт, а в text[11]
fgets() сама запишет 0.
Опасно, т.к. в рассмотренном случае strlen(text)
вернет 11, и Вы запишите 0 в text[11 + 1], т.е. за последний байт, выделенный под массив.
Т.о., просто выбрасываем этот фрагмент за ненадобностью.
Теперь посмотрим на search()
.
Да, идея просматривать не все, а только введенные символы в text[] -- абсолютно правильная
(использование той же переменной c
в цикле по vocal[] -- очевидная ошибка, наверное описка).
Посмотрев на код чуть пристальней и подумав, а как может быть реализована функция strlen и при этом зная, что "строки" в Си это массивы байт, завершающиеся нулем, можно прийти к выводу, что вызов strlen в этом контексте излишен. Мы же все равно будем перебирать символы text[], поэтому ничто не может нам помешать самим по ходу дела обнаружить конец строки.
Например, цикл по символам text[] может выглядеть так:
for (j = 0; text[j]; j++)
Очевидно, что вложенный цикл по гласным можно (да и наверное, единообразный код это в самом деле хорошо) организовать так же, добавив нулевой байт в его конец
(кстати, тогда можно было бы описать гласные совсем просто:
static char vocal[] = "AEOYUI";
)
Но, для разнообразия технических приемов, мы пойдем другим путем и используем переменную c
(тут все начнут ругаться, что это плохое имя, имена переменных должны ... (это Вам расскажут все кому не лень)) для вычисления размера vocal[6] вот так:
с = sizeof(vocal) / sizeof(vocal[0]);
(Казалось бы -- дурь. Сами строчкой выше написали, что размер vocal 6! Но, в некоторых ситуациях лучше вычислять.)
Это стандартный прием для получения количества элементов массива. Обратите внимание истинный размер массива в этой точке должен быть известен компилятору (у нас внутри search() это справедливо для vocal[], но не для text[] и result[], которые реально создаются (т.е. под них отводится память) в вызывающей функции).
Идем дальше и замечаем, что после того, как мы обнаружили, что text[i] гласная, перебирать оставшиеся гласные уже не нужно. В результате основной код функции становится таким:
с = sizeof(vocal) / sizeof(vocal[0]);
for (i = 0; text[i]; i++)
for (j = 0; j < c; j++)
if (toupper(text[i]) == vocal[j]) {
result[v++] = text[i]; // обычная сишная "красивость", совместим индексацию с изменением индекса в одном выражении
break; // в самом деле, раз нашли, так пойдем сразу дальше по text[]
}
result[v] = 0; // обязательно завершим список обнаруженных гласных 0
Должны ли тут мы вернуться в main, туда где отводили память под result[] и увеличить ее на 1?
(ответ -- нет, памяти как раз достаточно, поскольку такой же 0 обязательно заносится в text[] функцией fgets)
Теперь по поводу вопросов.
- Зачем возвращать длину result? Для красоты, законченности, расширения функционала, возможного упрощения использования search(). На самом деле Вы бесплатно получаете ответ на вопросы, а гласные есть? а сколько там гласных?
Тогда прототип станет таким:
int search (char text[], char result[]);
Ну, соответственно должна измениться и реализация:
int
search (char text[], char result[])
{
...
return v;
}
Насчет возможного замечания насчет выбора типа функции int
-- а не size_t
я бы сказал -- давайте оставим пространство для маневра -- например, возможности возвращать ошибки (или сделать какое-то другое расширение функционала).
- Не понял про инициализирование 'text[12]' и 'result[12]'
Не понял, что за код в цитате и что этот цикл делает, что за непонятные цифры "0x%02x" и словосочетание в начале аргументе (unsigned char)text[i].
Не понял про '"bc\000aaaaaaaaa"'.
Речь об инициализации, насколько помню, шла в контексте кода в search()
for (i = 0; i < 12; i++)
...
if (... text[i] ...
т.е. о доступе к потенциально неопределенным байтам. Думаю в свете всего вышеизложенного это стало неактуальным.
Код в цитате выводит шестнадцатеричные значения 12 первых байт массива text[] (для иллюстрации, что там может быть что угодно). "0x%02x " -- этот формат говорит:
выведи пару символов `0` и `x`
выведи шестнадцатеричное значение (очередного) аргумента printf, который д.б. типа int
в случае одной цифры выведи лидирующий 0.
(А Вы почитайте man 3 printf, да и потренируйтесь).
'"bc\000aaaaaaaaa"' -- очень просто (в книжке по Си где-то обязательно есть) при записи символьных строк (ими можно также инициализировать массивы (вроде бы я уже показывал это выше)) любой символ можно записать в виде -- бэкслеш и дальше 3 цифры его восьмеричного кода.
- с какой функции вводить строку? fgets, gets или scanf?
Вводить строку лучше функцией fgets(), поскольку она проверяет переполнение буфера.
При использовании GNU (gcc и соответствующая библиотека libc) также удобна функция getline() (почитайте man getline, заодно освоите указатели). Как я понимаю, Вы используете винду, поэтому самостоятельная реализация getline (надеюсь, в недалеком будущем) м.б. отличным упражнением (а заодно и тестом на освоение Си)).