Добрый день друзья. На прошлом занятии мы разобрались с
одномерными массивами. Сегодня разберемся с одним их частным случаем - символьными
строками. С ними мы уже даже
сталкивались. В самом первом уроке. Помните, выводили на экран строчку Hello world. Каждый символ в этой строке это элемент
одномерного массива.
Прочитайте улучшенную версию этого урока "Ввод и вывод символьных строк".
В новой версии:
- Ещё более доступное объяснение
- Дополнительные материалы
- 12 задач на программирование с автоматической проверкой решения
Рис.1. Символьный массив |
Как мы уже знаем, для хранения символов используются
элементы типа char. Значит для хранения строки, мы можем
использовать массив таких элементов. Единственным отличием такого массива,
будет являться последний элемент. Компьютеру же как-то надо понимать, когда
строка заканчивается? Это мы с вами видим, а у компьютера мозги кремниевые, он
только нулики и единички понимает, и в них же и хранит всю информацию. Поэтому
выбрали специальный символ, которым обозначается конец строки. Это символ с
кодом нуль , его обозначают следующим символом – '\0’. Помните, я рассказывал про то, что первые
32 значения в таблице кодов ASCII застолблены под служебные символы. Вот это пример одного из
них, самого первого. Изменим пример на
картинке выше, чтобы он больше соответствовал действительности.
Рис 2. Символьная строка |
Объявление и инициализация строк.
Как мы уже разобрались, необходимо использовать для хранения
строк массив символов. Никаких фокусов тут нет, и объявление массива символов
стандартное.
Листинг 14.1
char str[10];
Но сейчас это просто массив символов, а никакая не строка. Чтобы
это стало строкой, необходимо, чтобы последним в массиве символов был символ ‘\0’.
В объявленном выше массиве всего 10 элементов. Если мы будем
его использовать для хранения строки, нам стоит учитывать, что один элемент
(последний) у нас всегда будет занят, символом конца строки.
После того, как мы объявили массив символов, в нем будет
записан мусор. В этом можно убедиться, выполнив следующую программу.
Листинг
14.2
#include <stdio.h>
int main(){
char str[17];
printf("%s\n", str);
return(0);
}
int main(){
char str[17];
printf("%s\n", str);
return(0);
}
Рис.3. Символьный массив после объявления |
Как видите, для вывода строк можно использовать стандартную
функцию printf(), для
которой предусмотрен специальный спецификатор %s. В остальном никаких отличий здесь
нет.
Теперь разберемся, как присвоить значение строке. Есть
несколько способов.
- Как и любая переменная, строка может быть инициализирована (т.е. ей присвоено некоторое значение) непосредственно при её объявлении.
Листинг
14.3
#include <stdio.h>
int main(){
char str[17]="Hello world";
printf("%s\n", str);
return(0);
}
int main(){
char str[17]="Hello world";
printf("%s\n", str);
return(0);
}
При таком объявлении и инициализации, все свободные символы, так и останутся заполненными
мусором либо обнулятся. Тут в зависимости от компилятора. Вы можете это проверить
самостоятельно. Это будет первым заданием для самостоятельного выполнения к
этому уроку.
- Мы можем не задавать при инициализации размер массива.
Листинг 14.4
#include <stdio.h>
int main(){
char str[]="Hello world";
printf("%s\n", str);
return(0);
}
int main(){
char str[]="Hello world";
printf("%s\n", str);
return(0);
}
В этом случае, компилятор сам посчитает количество символов
для хранения строки в кавычках, и сам учтет заключительный символ ‘\0’. В
данном случае массив str
будет из 12 элементов.
Кстати, посмотрите на следующую программу. Она наглядно иллюстрирует, что массив
символов, без завершающего ‘\0’ это не
строка.
Листинг 14.5
#include <stdio.h>
int main(){
char str[5];
str[0]='a';
str[2]='b';
printf("%s\n", str);
return(0);
}
int main(){
char str[5];
str[0]='a';
str[2]='b';
printf("%s\n", str);
return(0);
}
Результат работы этой программы представлен на следующем
рисунке.
Рис. 4. Вывод на экран символьного массива без нулевого элемента в конце |
Как можете заметить, вывелись первый символ, потом один
символ пропущенный (с мусором), дальше второй символ, сохраненный нами в
программе, а дальше пошел неконтролируемый мусор. Не контролируемый потому что
непонятно даже, сколько там символов вывелось, но явно не оставшиеся два
символа.
Ввод и вывод строк.
Теперь рассмотрим,
как можно ввести строку символов с
клавиатуры.
Возникает естественное желание воспользоваться стандартной
функцией scanf(). Попробуем.
Листинг
14.6
#include <stdio.h>
int main(){
char str[17];
scanf("%s", str);
printf("%s\n",str);
return(0);
}
int main(){
char str[17];
scanf("%s", str);
printf("%s\n",str);
return(0);
}
Выполним эту программу. Введем, уже привычное нам, Hello world.
Результат работы программы на следующем рисунке.
Рис.5 Ввод строки с использованием функции scanf(). |
Как видите, в строку сохранилось лишь первое слово. Все дело
в реализации функции scanf.
Она считает пробел разделителем. Получается, таким способом мы можем считать
лишь строку, которая не содержит пробелов, т.е. мы можем считать одно слово.
Кстати, вы обратили внимание, что я не поставил перед именем
массива знак &, чтобы получить его адрес?
Это не ошибка. Просто имя массива, без указания номера элемента в
квадратных скобках, ссылается на адрес первого элемента массива. Т.е. нам тут
не нужно получать адрес, он и так у нас есть.
Это касается не только символьных массивов, а любых. Но пока это не
особо важно. С этим мы столкнемся, когда будем изучать указатели.
Вернемся к нашим баранам, как говорится. Мы хотели считать строку. Раз scanf() надежд возложенных на
неё не оправдала, должна быть какая-то другая функция. И она, конечно же, есть.
Функция gets().
Мы снова не будем углубляться в развернутый синтаксис, кому
интересно, тот может подробно посмотреть в любом справочнике.
Функция gets
принимает в качестве своего аргумента массив символов, в который она и
записывает считываемую из стандартного потока ввода строку. Концом ввода строки
является символ перенос строки ‘\n’, т.е. когда мы нажмем Enter на клавиатуре. Этот
символ последним считывается и при записи в массив заменяется символом конца строки ’\0’.
Следующая программа читает введенную строку и выводит её на
экран.
Листинг 14.7
#include <stdio.h>
int main(){
int main(){
char str[17];
gets(str);
printf("%s\n",str);
return(0);
}
gets(str);
printf("%s\n",str);
return(0);
}
Результат работы программы, на следующем рисунке.
Рис. 6. Ввод строки с использованием функции gets() |
Как видите, мы избавились от нашей проблемы. Но есть более
важная проблема. Когда мы предоставляем пользователю вводить строку, мы не
знаем, сколько он символов введет. Может так случиться, что мы объявили массив
на 10 элементов, а пользователь ввел 30. Тогда возникнет ошибка – переполнение буфера.
Поэтому использовать эту функцию использовать нужно очень осторожно, либо не
использовать вообще. А что же тогда использовать?
Функция fgets().
Сразу рассмотрим пример её использования.
Листинг 14.8
#include <stdio.h>
int main(){
char str[10];
fgets(str,10,stdin);
printf("%s\n",str);
return(0);
}
int main(){
char str[10];
fgets(str,10,stdin);
printf("%s\n",str);
return(0);
}
Функция принимает три аргумента.
- Массив символов, в который необходимо записать вводимую строку.
- Количество символов, которые может считать функция с учетом символа конца строки. В нашем случае это 10, т.е. рабочих из них девять, и один зарезервирован для конца строки.
- Откуда читать данные. В нашем случае указан стандартный поток ввода.
Попробуем в нашей программе Листинг 14.8 ввести нашу строку Hello world. В ней 12 символов.
Результат выполнения.
Рис.7. Ввод с помощью функции fgets(). |
Как видите, даже если мы введем больше, то функция считает
только определенное ей количество символов. Не больше.
Есть еще одно отличие. Функция gets() глотала наш перенос строки,
превращая его в символ конца строки. А вот функция fgets() его не «проглатывает». Введем,
какую-нибудь строку меньше 10 символов. И посмотрим что будет.
Рис.8. Иллюстрация особенностей ввода функции fgets(). |
Как видите, получилось два переноса строки. Один из самой
строки, другой из-за формат строки вывода.
С вводом разобрались. Теперь поколдуем над выводом. Кроме
стандартного printf()
есть еще несколько функций. По аналогии с функциями ввода.
Функции puts(),
fputs().
Синтаксис будет понятен из следующего примера
Листинг 14.9
#include <stdio.h>
int main(){
char str[12];
fgets(str,12,stdin);
puts(str);
fputs(str, stdout);
return(0);
}
int main(){
char str[12];
fgets(str,12,stdin);
puts(str);
fputs(str, stdout);
return(0);
}
Результат выполнения это программы:
Рис.9. Использование стандартных функций вывода строки puts(), fputs(). Особенности вывода. |
Как видите, функция puts является обратной к функции gets(). Она выводит строку
заменяя символ конца строки на символ переноса строки. И поэтому то, что выводи
функция fputs() оказывается
на новой строке. А вот функция fputs()
дополнительного переноса строки не делает.
На этом на сегодня всё. На следующем уроке будем разбирать
стандартные функции, которые работают со строками.
Задания для самостоятельной практической работы.
- На вход программе подается строка, длинной не более 100 символов. Напишите программу, которая определяет длину этой строки, без учета нулевого символа.
- Напишите программу, которая переводит данную строку в нижний регистр. Т.е. и строки "Hello WorlD" должна получиться строка "hello world"
- На вход программе подается строка, длинной не более 100 символов. Определить, является ли она перевертышем. Например, как слово "шалаш" или "топот". Учтите что строка может содержать пробелы, их учитывать не нужно. Например, строка "А роза упала на лапу Азора" будет являться перевертышем.
- Пользователь вводит две строки. Необходимо сравнить их между собой, и вывести yes если строки полностью совпадают, или no в противном случае. Регистр учитывать не нужно. Т.е строки "Hello WorlD" и "hello world" считаются двумя одинаковыми строками.
- Напишите программу, которая читает из файла строку, длинной не более 200 символов. И считает количество вхождения в строку всех используемых в ней символов,без учета регистра. На вход поступает строка состоящая из букв латинского алфавита и пробелов. Программа должна вывести в первой строке длину введенной строки. В следующих строках встречаемые символы и их количество. Например, для строки "hello world", вывод будет следующим.
d - 1
e - 1
h - 1
l - 3
o - 2
r - 1
w - 1
probel - 1
- Капитан Флинт зарыл клад на Острове сокровищ. Есть описание, как найти клад. Описание состоит из строк вида: "North 5", где первое слово – одно из "North", "South", "East", "West", а второе целое число – количество шагов, необходимое пройти в этом направлении. Напишите программу, которая по описанию пути к кладу определяет точные координаты клада, считая, что начало координат находится в начале пути, ось OX направлена на восток, ось OY – на север. На вход подается последовательность строк указанного формата. На выходе программа должна вывести координаты клада – два целых числа через пробел
Вход:
North 5
East 3
South 1
Выход: 3 4.
Если Вам понравился этот урок, расскажите о нем вашим друзьям. В этом Вам могут помочь кнопки основных социальных сетей, расположенные ниже. Вам остается всего лишь кликнуть по любой из них.
Самый непонятный урок для меня :(
ОтветитьУдалитьОсобенно с длинной строки.
"Количество символов, которые может считать функция с учетом символа конца строки. В нашем случае это 10, т.е. рабочих из них девять, и один зарезервирован для конца строки."
Почему 9 да еще и минус один под конец строки и того 8? А на выводе все равно получается, что считали и вывели 9 символов. (Листинг 14.8)
Последний символ 100% записывается в конец строки и считается n-ным (последним) элементом массива? Как этот символ считать? т.е. как написать for (i = 0; i == конец строки; i++); (ага пока читал извилина шевельнулась. Не знаю только в правильную ли сторону :) Получается так сделать нельзя т.к. мы сначала i приравниваем к целому числу, а потом хотим проверить не равено ли он символу. Тогда все равно не понятно как сделать такой цикл, что бы он выполнялся до конца строки).
char str[];
Если я введу с клавиатуры 'Hello world' и жмакну enter.
gets(str) - считает Hello world\0
fgets(str,11,stdin) - считает Hello worl\0\n
И длинна массива в обоих случаях будет 12 символов? Так?
Ну и продолжая тему с функциями ввода вывода. Получается:
puts(str) - выведет Hello world\0\n
fputs(str,stdout) - выведет Hello world\0
https://www.dropbox.com/s/17xhfz2melnuyjh/images.jpg
Я наверное коряво написал. Смотрите 10 можете считать. Из них рабочих 9. А десятый, который не рабочий как раз и зарезервирован под конец строки.
УдалитьВы забыли, что тип char совместим с целым типом. каждому символу соответствует число, код этого символа в таблице ASCII. Вот символу конца строки соответствует число нуль. Поэтому конец строки мы можем проверять как str[i] != 0;
Длина массива и длинна строки это разные вещи ведь. Длинна массива может быть и 100 элементов, а вот длина строки, которая хранится в этом массиве может быть и меньше. Например, Литстинг 14.3
Длинна массива str 17 элементов, а длина строки, которую мы туда поместили всего двенадцать. Из них, как мы уже разобрались 11 рабочие и последний, двенадцатый символ конца строки. )
Теперь, с учетом этих пояснений попробуйте ответить на свои последние вопросы или переформулировать их. Если не получится, напишите я или отвечу или дам еще подсказку. )
1 и 2
ОтветитьУдалить#include "stdio.h"
#include "locale.h"
int main () {
setlocale(LC_ALL, "Russian");
int k, i=0;
char str [100];
//0-99 рабочих (100) + 1 на конец строки.
printf("Введите строку, не больше 100 символов.\n");
fgets(str,100,stdin);
//считаем кол-во символов
while (str != 0) {
i++;
}
printf("Длинна строки = %d\n",i);
/////////////////////////////////
//ASCII - англ. символы в верхнем регистре имеют индекс [65,90], в нижнем [97,122]
//разница между верх. и ниж. ригистрах 32
//Переод в нижний регистр
for (k = 0; k < i; k++) {
if ((str[k] > 64)&&(str[k] < 91)) {
str[k]+=32;
}
}
printf("%s\n",str);
///////////////////
//Перевод в верхний регистр
for (k = 0; k < i; k++) {
if ((str[k] > 96)&&(str[k] < 123)) {
str[k]-=32;
}
}
printf("%s\n",str);
///////////////////
return (0);
}
char str [100];
Удалить//0-99 рабочих (100) + 1 на конец строки.
тут всего с 0 по 99, сотого нет. Чтобы уместить 100, нужно объявлять 101. Тогда будет как вы написали. Но это не важно. =))
Сама идея правильная, именно такое решение я и ожидал увидеть.
Но есть ошибки в коде. Например, цикл для длины строки бесконечный. Внимательно посмотрите на условие.=))
Этот комментарий был удален автором.
ОтветитьУдалить/*Месье знает толк в извращениях - думаю есть решение проще. И да я не выполнил условие "На вход программе.." т.к. не могу его проверить, т.к. компилятора под рукой нет, компилю онлайн, и нет возможности ввода.
ОтветитьУдалитьp.s. Почему то при вводе Русских символов не переводит в один регистр. Не пойму в чем дело.. вроде так же должно быть как и с анг. символами. Может просто компилятор не хочет с ними работать?
*/
#include "stdio.h"
#include "locale.h"
int main () {
setlocale(LC_ALL, "Russian");
int k, j, i=0, tmp=1;
char str[]="A roza upala na lapu Azora";
while (str[i] != 0){
i++;
}
//удаляем пробелы и переводим в один регистр.
for (k = 0; k < i; k++) {
if (str[k] == 32) {
for (j = k; j < i; j++){
str[j] = str[j+1];
}
i--; /*отнимаем от длинны строки каждый пробел т.к. мы его удалили*/
}
if (((str[k] > 64)&&(str[k] < 91))||((str[k] > 191)&&(str[k] < 223))) {
str[k]+=32;
}
}
///////////////////////////////////////
//сравниваем первый и последний символ.
for (k = 0, j = i-1; k < j; k++, j--) {
if (str[k] == str[j]) {
tmp+=2;
}
}
printf("Строка палиндром? - ");
if (tmp == i) {
printf ("YES");
} else printf ("NO");
return (0);
}
С Русскими символами кажется разобрался. Не ту таблицу посмотрел.
УдалитьДля преобразованию Русских символов такой код:
if ((str[i] > 127)&&(str[i] < 159)) {
if ((str[i] > 127)&&(str[i] < 144)) {
str[i]+=32;
} else {
str[i]+=80;
}
}
В программу встраивать не стал.
Длину строки и удаление пробелов нужно сделать за один цикл. Думаю туда же можно включить и преобразование регистра. =)) В общем, доведите программу до нормально вида, а то это даже вам, кажется извращением. =))
УдалитьИ не парьтесь с русскими символами. )) Выполняйте задание только для латиницы. Никакого отдельного интереса они не представляют. Принцип тот же. )
УдалитьВсе действительно в один While. Вот только для удаления пробелов потребовался еще один цикл, благо он меньше While на количество уже пройдены шагов, а так проскакивает столько же тиков.
Удалитьwhile (str[i] != 0) {
if (str[i] == 32) {
for (t = i; str[t] != 0; t++){
str[t] = str[t+1];
}
}
if ((str[i] > 64)&&(str[i] < 91)) {
str[i]+=32;
}
i++;
}
И снова нет! =))
УдалитьУ вас опять вложенные циклы.
Смотрите как должно быть.
1. Запускается программа.
2. Считываем данные в строку.
3. Приводим строку к стандартному виду (узнаем её длину, меняем регистр, удаляем пробелы.)
4. Проверяем строку палиндром она или нет и выводим ответ.
На 3 пункт нужен один цикл простой. Тут будет while скорее всего.
На 4 пункт еще один цикл простой. Тут удобней for.
И они не вложенные друг в друга.
Теперь немного по удалению пробелов. Почему бы вам не завести еще одну строку, в которой будет храниться строка в правильном виде. А не из-за одного пробела добегать перекопировывать целый хвост.Представьте, что у вас строка
"A ro za u p a l a n a l a p u A z o r a"
И так после каждого пробела, будет запускаться внутренний цикл и копироваться все не нужное влево на один символ. Это не экономно. =))
Сравнение строк, в отличии от предыдущей задачи не меняет сами строки :)
ОтветитьУдалить#include "stdio.h"
#include "locale.h"
int main () {
char str_1[100], str_2[100];
int i=0, tmp = 0, str_1_i = 0, str_2_i = 0;
pritnf("Введите две строки не больше 100 символов каждая. Все символы выше лимита будут обрезаны.\n");
printf("Введите первую строку: \n");
fgets(str_1,100,stdin);
printf("Введите вторую строку: \n");
fgets(str_2,100,stdin);
while (str_1[str_1_i] != 0) {
str_1_i++;
}
while (str_2[str_2_i] != 0) {
str_2_i++;
}
if (str_1_i == str_2_i) {
for (i = 0; i < str_1_i; i++) {
if (str_1[i] != str_2[i]) {
if (((str_1[i] - str_2[i]) == 32)||((str_2[i]-str_1[i]) == 32)) {
tmp++;
}
}
if (str_1[i] == str_2[i]) {
tmp++;
}
}
} else printf("No\n");
if (tmp == i) {
printf("YES\n");
} else printf("No\n");
return (0);
}
Как только вот это увидел
Удалитьwhile (str_1[str_1_i] != 0) {
str_1_i++;
}
while (str_2[str_2_i] != 0) {
str_2_i++;
}
if (str_1_i == str_2_i) {
for (i = 0; i < str_1_i; i++) {
if (str_1[i] != str_2[i]) {
if (((str_1[i] - str_2[i]) == 32)||((str_2[i]-str_1[i]) == 32)) {
tmp++;
}
}
if (str_1[i] == str_2[i]) {
tmp++;
}
}
Дальше читать не стал. Слишком сложно и муторно. Задача очень простая, чтобы решать её такими силами. =) Один цикл и два if максимум. =))) А быть может, даже проще можно. Одним if обойтись.Подумайте, что лишнего вы ищете и проверяете. =)) Например, так ли вам нужно знать длины строк? Ну и там еще посмотрите, что можно упростить.
как то так.
Удалитьwhile ((str_1[i] != 0)&&(str_2[i] != 0)) {
if ((str_1[i] != str_2[i])&&(fabs(str_1[i] - str_2[i]) != 32)) {
printf("NO\n");
return (0);
}
i++;
}
printf("YES");
return (0);
}
Не компилирую, но это правильно. Замечательно! Именно это я и хотел увидеть. =)))
УдалитьПопроще, да? Чем предыдущий код? ))
Хотя нет, условие плоховато для цикла.
Удалить"A roza upala na lapu Azora" и "a roza upala" вернет YES, но это же явный NO. )))
Так то оно так, но если ввести не только буквы, а ещё и цифры
Удалитьто введённые : R и 2 в разные строки, напишет yes.
Пятая. С предыдущими разобрался, но выкладывать уже думаю смысла нет, и так все разжевано.
ОтветитьУдалитьint main () {
char str[200], str_bp[200]="0", t;
int i = 0, k = 0, p = 0;
freopen("путь к файлу","r",stdin);
fgets(str,200,stdin);
while (str[i] != 0) {
if ((str[i] > 96)&&(str[i] < 123)) {
str[i]-=32;
}
if (str[i] != 32) {
str_bp[k] = str[i];
k++;
}
i++;
}
printf("%d", i);
p = i - k;
for (k = k-1; k > 0; k--) {
for (i = 0; i < k; i++) {
if (str_bp[i] > str_bp[i+1]) {
t = str_bp[i];
str_bp[i] = str_bp[i+1];
str_bp[i+1] = t;
}
}
}
printf("%s\n",str_bp);
i=0, k = -1;
while (str_bp[i] != 0) {
if (str_bp [i] != str_bp[i+1]) {
printf ("%c - %d\n", str_bp[i], i - k);
k = i;
}
i++;
}
printf ("probel - %d\n", p);
return(0);
}
Если сами разобрались, то конечно не стоит писать сюда. Хотя я бы почитал, как Вы решили проблему с удаление лишних пробелов. =)
УдалитьТеперь по пятой программе. Выводит она не то, что требуется. Лишнее есть. Снова мной замечены вложенные циклы. Мне это не нравится. Думаю можно сделать без этого. Кстати, стоит рассказать, чем мне так не нравятся вложенные циклы? )
Подумайте еще или хотя бы исправьте вывод. Уберите все лишнее. )))
Все у меня голова сегодня не варит :)
ОтветитьУдалитьПо последней задаче.
Можно ведь считывать введенное с клавиатуры таким образом:
сканф(строка)
и т.к. пробел сработает как разделитель еще раз считать но уже число после пробела тогда все легко.
Но если использовать фгетс и введенное полностью считать как сторку..тут посложнее и вот тут то похоже меня опять в дебри и понесло.
Что я хотел сделать читать строку до пробела и получить ASCII сумму направления.
Дальше читать от пробела до конца строки количество символов и получить разрядность.
Опять читать от пробела до конца строки получать int iй элемент умножать его на разрядность и отнимать от последней один разряд. т.о. получить число. Что то я сомневаюсь в рациональности такого метода :)
Не совсем понял, что вы хотите сделать. =))
УдалитьЯ лучше посмотрю Ваш код, когда вы его напишете, и прокомментирую более подробно. Посмотрим, что там можно улучшить и от чего можно избавиться, что оптимально, а что не очень. =)))
Спасибо урок очнь интересный.
ОтветитьУдалитьЗадание 1
#include ((stdio.h))//задание 1 защиту от дураков не делал
int main(){
char str[101];
int i=0;
printf(" Vvedite stroku simvolov, ne bolee 100\n");
gets(str);
do{//do
switch (str[i]){
case '\0':printf("vvedeno %d simvolov \n",i);return(0);
}
i++;}//do'
while(i!=101);
return(0);
}
вроде работает .
Да, хорошо.
Удалитьзадание 2
ОтветитьУдалить#include //задание 2 смена регистра вниз
#include
int main(){
char str[101];
int i=0;
printf(" Vvedite stroku simvolov, ne bolee 100\n");
gets(str);
do{//do
str[i]= tolower(str[i]);
i++;}//do'
while(str[i]); //проверка окончания строки
puts(str);
return(0);
}
Хаа, какой вы шустрый. Хвалю что знаете такую функцию, но нужно написать программу без использования стандартных функций. Основываясь на закономерностях таблицы символов ASCII. ))
Удалить#include ((stdio.h)).//задание 3 строка перевертыш
ОтветитьУдалить#include ((cctype))
int main()
{
char str[101];//строка
int i=0,n;// счётчики
printf(" Vvedite stroku simvolov, ne bolee 100\n");
fgets(str,101,stdin);//ввели строку
do{//do 1
switch (str[i]){
case ' '://ловим пробел
{
n=i;
i--;
do
{//do 2
str[n]=str[n+1];
n++;
}while(str[n-1]);//do 2' выбросили пробел
}//case ' '
default:str[i]=toupper(str[i]);
}//switch(str[i])
i++;
}while(str[i]);//do1' выбросили все пробелы и поменяли регистр
i-=2;
n=0;
do//do 3' проверка зеркальности
{if (str[n]!=str[i]) {printf (" Stroka - NE perevertysh. \n");return (0);}//проверка неравенства символов
else{ n++;i--;}
}while(n
}//switch(str[i])
i++;
}while(str[i]);//do1' выбросили все пробелы и поменяли регистр
//i=длинна строки без пробелов+ноль символ,k=кол-во пробелов
int kolvo[201],a;
kolvo[1]=k ;//кол во пробелов
kolvo[0]=i-1+k;//кол символов стр 30
i=0;
while(str[i]){
//stemp=str[i];
k=1;
a=i;// стр 35
do{
n=a+1;
if (str[n]==str[i])
{
k++;
do
{//do
str[n]=str[n+1];
n++;
}while(str[n-1]);//выбросили символ
}//if
else a++;
}while(str[a-1]);//выбросили все символы
i++;
kolvo[i+1]=k;
}// while(str[i])
printf( "%d\n", kolvo[0]);
i=0;
while(str[i+1])
{
printf(" %c\t%d\n", str[i],kolvo[i+2]);
i++;
}
printf( "probelov %d\n", kolvo[1]);
return(0);
}
Задание 6
#include ((stdio.h))// задание 6
int main()
{
char str[5];
int x=0,y=0,a,i=0;
printf (" Vvedite koordinaty v lyubom porydke.\n");
printf (" obrazec:\n");
printf (" North 5\n East 3\n South 1\n West 7\n");
printf (" Esli est' ne vse koordinaty, vvedite v konce 0\n");
do{
scanf("%s",&str);
switch (str[0]){
case'N': scanf("%d",&a);y+=a;break;
case'E': scanf("%d",&a);x+=a;break;
case'S': scanf("%d",&a);y-=a;break;
case'W': scanf("%d",&a);x-=a;break;
case'0': i=3;break;
default : i--;printf (" povtorite vvod pravilno.\n "); break;
}
i++;
}while(i<4);
printf("%d %d\n", x,y);
return(0);
}
Неправильно. Путь может состоять и из 100 шагов Например:
УдалитьNorth 5
East 3
South 2
North 2
East 12
South 1
West 22
=)))
И при некоторых данных происходит выход за пределы массива кажется.
Задание 3
ОтветитьУдалить#include .//задание 3 строка перевертыш
#include
int main()
{
char str[101];//строка
int i=0,n;// счётчики
printf(" Vvedite stroku simvolov, ne bolee 100\n");
fgets(str,101,stdin);//ввели строку
do{//do 1
switch (str[i]){
case ' '://ловим пробел
{
n=i;
i--;
do
{//do 2
str[n]=str[n+1];
n++;
}while(str[n-1]);//do 2' выбросили пробел
}//case ' '
default:str[i]=toupper(str[i]);
}//switch(str[i])
i++;
}while(str[i]);//do1' выбросили все пробелы и поменяли регистр
i-=2;
n=0;
do//do 3' проверка зеркальности
{if (str[n]!=str[i]) {printf (" Stroka - NE perevertysh. \n");return (0);}//проверка неравенства символов
else{ n++;i--;}
}while(n<i);//do 3'
printf ("Stroka - perevertysh.\n");
return(0);
}
Уже лучше, чем тот код, что выше. Но вы снова использовали стандартные функции. =))
УдалитьЗадание 4
ОтветитьУдалить#include // задание 4 проверка одинаковости строк без учёта регитра
#include //с русскими символами не работает
int main ()
{
char str1[101],str2[101];
int i=0;
printf("vvedite stroku\n");
fgets(str1,101,stdin);
printf("vvedite stroku\n");
fgets(str2,101,stdin);
do{//do перевод в один регистр str1
str1[i]= tolower(str1[i]);
i++;}//do'
while(str1[i]); //проверка окончания строки
i=0;
do{//do перевод в один регистр str2
str2[i]= tolower(str2[i]);
i++;}//do'
while(str2[i]); //проверка окончания строки
i=0;
while((i<100)&&((str1[i]!=0)&&(str2[i]!=0)))//проверка одинаковости
{
if(str1[i]!=str2[i]) {printf ("Stroki NE odinakovye\n ");return(0);}
else i++;
}//while
printf("Stroki odinakovye\n ",i );
return 0;
}
Аналогично.
УдалитьЗадание 5
ОтветитьУдалить#include // задание 5
#include
int main()
{
char str[201];
int i=0,n,k=0;
freopen ("D:\\myfyle.txt","r",stdin);
fgets(str,201,stdin);
puts(str);
do{//do 1
switch (str[i]){
case ' '://ловим пробел
{
n=i;
i--;
k++;//счётчик пробелов
do
{//do 2
str[n]=str[n+1];
n++;
}while(str[n-1]);//do 2' выбросили пробел
}//case ' '
default:str[i]=tolower(str[i]);//смена регистра подключить #include
}//switch(str[i])
i++;
}while(str[i]);//do1' выбросили все пробелы и поменяли регистр
//i=длинна строки без пробелов+ноль символ,k=кол-во пробелов
int kolvo[201],a;
kolvo[1]=k ;//кол во пробелов
kolvo[0]=i-1+k;//кол символов
i=0;
while(str[i]){
//stemp=str[i];
k=1;
a=i;//
do{
n=a+1;
if (str[n]==str[i])
{
k++;
do
{//do
str[n]=str[n+1];
n++;
}while(str[n-1]);//выбросили символ
}//if
else a++;
}while(str[a-1]);//выбросили все символы
i++;
kolvo[i+1]=k;
}// while(str[i])
printf( "%d\n", kolvo[0]);
i=0;
while(str[i+1])
{
printf(" %c\t%d\n", str[i],kolvo[i+2]);
i++;
}
printf( "probelov %d\n", kolvo[1]);
return(0);
}
Слишком громоздко. Можно проще, не забывайте про таблицу ASCII. =))
УдалитьВ пятом задании прямо просятся функции , но чей-то я не догоняю,как туда строку загнать...
ОтветитьУдалитьВсе намного проще.Присмотритесь, там можно обойтись и без строк. =)
УдалитьЭто я про 6 задание говорил. =) Но в 5 тоже все гораздо проще. )
УдалитьПочему второй раз выводится сначала мусор, а затем введённые символы причём количество не соответствует заявленному?
ОтветитьУдалить#include "stdio.h"
int main ()
{
char a[10], b[2];
fgets (a, 10, stdin);
fputs (a, stdout);
fgets (b, 2, stdout);
printf ("%s", b);
return (0);
}//main
Вы читаете из стандартного потока вывода, который в этот момент уже пустой. Оттуда ничего считать не может функция. Поэтому возникает ошибка. Я еще расскажу, о том как контролировать такие ошибки. Быть может добавлю даже в этот урок. =)
Удалитьзадание 1
ОтветитьУдалить#include "stdio.h"
int main(){
int i, j;
j = 0;
char str[101];
fgets(str, 101, stdin);
for(i = 0; i < 102; i++)
{
if(str[i] != '\n')
{
j++;
}
else
{
printf("%d\n", j);
}
}
return 0;
}
Хорошо.)
Удалитьзадание 4
ОтветитьУдалить#include "stdio.h"
#include "locale.h"
int main(){
setlocale(LC_ALL, "Russian");
char str_1[101];
char str_2[101];
int i = 0;
int k = 0;
//Пользователь вводит две строки. Необходимо сравнить их между собой, и
//вывести yes если строки полностью совпадают, или no в противном случае. Регистр учитывать
// не нужно. Т.е строки "Hello WorlD" и "hello world" считаются двумя одинаковыми строками.
fgets(str_1, 101, stdin);
fgets(str_2, 101, stdin);
for(i = 0; i < 101 ; i++ ) //&& (str_1[i] != 0 || str_2[i] != 0)
{
if(str_1[i] == str_2[i])
{
k++;
}
}
if(k == 101)
{
printf("=)\n");
}
else
{
printf("=(\n");
}
return 0;
}
Нет, не правильно. Вы не учли добавление про регистр. И само сравнение можно получше организовать, без счетчика условия после цикла. Подумайте на этим.))
Удалить#include "stdio.h"
Удалить#include "locale.h"
#include "ctype.h"
int main()
{
setlocale(LC_ALL, "Russian");
char str_1[101];
char str_2[101];
int i = 0;
int k = 0;
//Пользователь вводит две строки. Необходимо сравнить их между собой, и
//вывести yes если строки полностью совпадают, или no в противном случае. Регистр учитывать
// не нужно. Т.е строки "Hello WorlD" и "hello world" считаются двумя одинаковыми строками.
fgets(str_1, 101, stdin);
fgets(str_2, 101, stdin);
for(i = 0; i < 101 ; i++ )
{
str_1[i] = tolower(str_1[i]);
str_2[i] = tolower(str_2[i]);
if(str_1[i] != str_2[i])
{
printf("=(\n");
k = 1;
break;
}
}
if(k == 0)
{
printf("=)\n");
}
return 0;
}
может быть так?
Всё бы хорошо, но получается для использования одной функции tolower вы подключаете целую библиотеку дополнительно. Это не "айс", тем более, что такую функцию вы можете написать самостоятельно, что от вас и требуется, во втором задании. =)) Переделайте, чтобы было как надо. А потом поговорим еще про небольшую оптимизацию кода. Чтобы было покрасивее. )
Удалить#include "stdio.h"
Удалить#include "locale.h"
int main()
{
setlocale(LC_ALL, "Russian");
char str_1[101];
char str_2[101];
int i = 0;
int k = 0;
//Пользователь вводит две строки. Необходимо сравнить их между собой, и
//вывести yes если строки полностью совпадают, или no в противном случае. Регистр учитывать
// не нужно. Т.е строки "Hello WorlD" и "hello world" считаются двумя одинаковыми строками.
fgets(str_1, 101, stdin);
fgets(str_2, 101, stdin);
for(i = 0; i < 101 && str_1[i] != '\0' && str_2[i] != '\0'; i++ )
{
if ( str_1[i] <= 'Z' && str_1[i] >= 'A')
str_1[i] += 'z' - 'Z';
if ( str_2[i] <= 'Z' && str_2[i] >= 'A')
str_2[i] += 'z' - 'Z';
if(str_1[i] != str_2[i])
{
printf("=(\n");
k = 1;
break;
}
}
if(k == 0)
{
printf("=)\n");
}
return 0;
}
Уже лучше. Теперь давайте разберемся.
УдалитьСмотрите, обязательно ли нам нужна переменная k? Ведь можно обойтись без неё. Подумайте как можно избавиться от этой переменной и последнего if, в котором мы определяем, что выводить yes или no.
#include "stdio.h"
Удалить#include "locale.h"
int main()
{
setlocale(LC_ALL, "Russian");
char str_1[101];
char str_2[101];
int i = 0;
//Пользователь вводит две строки. Необходимо сравнить их между собой, и
//вывести yes если строки полностью совпадают, или no в противном случае. Регистр учитывать
// не нужно. Т.е строки "Hello WorlD" и "hello world" считаются двумя одинаковыми строками.
fgets(str_1, 101, stdin);
fgets(str_2, 101, stdin);
for(i = 0; i < 101 && str_1[i] != '\0' && str_2[i] != '\0'; i++ )
{
if ( str_1[i] <= 'Z' && str_1[i] >= 'A')
str_1[i] += 'z' - 'Z';
if ( str_2[i] <= 'Z' && str_2[i] >= 'A')
str_2[i] += 'z' - 'Z';
if(str_1[i] != str_2[i])
{
printf("=(\n");
return 0;
}
}
printf("=)\n");
return 0;
}
все попробовал, сработало return 0...теперь думаю почему же))
меня смущает, что сработало if()...return 0, так разве оператор for останавливаться должен? или это значит что конец работы целой, главной функции?
УдалитьИменно. Это означает конец работы главной фукции main. Если мы поняли, что строки не совпадают, то мы можем сразу заканчивать программу. Хотя здесь не обязательно выходить из программы так. Можно просто выйти из цикла. Знаете как это сделать?
Удалитьexit(1); вместо return 0;
Удалитьс break не вышло, с continue вроде как для других операторов?
Все нормально было. Это я ошибся. Так хорошо. Я подумал, что последний printf был внутри цикла, а он снаружи.
УдалитьЗадание 6
ОтветитьУдалить#include "stdio.h"
int main()
{
int x, y, z;
x = y = 0;
char side[10];
printf("vvdeite je\n");
scanf("%s %d", side, &z);
while(side[0])
{
switch(side[0])
{
case 'N': y += z; scanf("%s %d", side, &z); break;
case 'S': y -= z; scanf("%s %d", side, &z); break;
case 'W': x -= z; scanf("%s %d", side, &z); break;
case 'E': x += z; scanf("%s %d", side, &z); break;
default: printf("koords are x = %d, y = %d\n", x, y); side[0] = '\0';
scanf("%s %d", side, &z);
}
}
return 0;
}
Это плохой код, хотя мысли ваши верны. Тут даже зацикливание есть.
УдалитьДавайте-ка сначала словесно опишите, как должна работать программа.
1 инициализация всего что пригодится
Удалить2 просим ввести сторону и координаты
3 оператором switch определяем в какую сторону будет приращение
4 определяем default на окончание строки
5 чтобы цикл не прекращался просто так в конце просим ввести еще сторону и координаты и так до тех пор пока не встретится конец строки
В тех случаях, когда действие гарантировано выполнится хотя бы один раз, лучше использовать цикл с постусловием do ... while. У вас как раз такой случай. Переделайте, так будет гармоничнее и лучше. И добавьте считывание входных данных из файла.
Удалить#include "stdio.h"
Удалитьint main()
{
int x, y, z;
x = y = 0;
char side[10];
freopen("/Users/p1us/Desktop/input.txt", "r", stdin);
do
{
scanf("%s %d", side, &z);
printf("side[0] = %c\n", side[0]);
switch(side[0])
{
case 'N': y += z; break;
case 'S': y -= z; break;
case 'W': x -= z; break;
case 'E': x += z; break;
default: printf("koords are x = %d, y = %d\n", x, y); side[0] = '\0';
}
}
while(side[0] != '\0');
return 0;
}
единственное пришлось в фаил добавить последней строкой 0. В противном случаем будет дополнительный if. а без него новая строка не читается и получается зацикливание
Вот это гораздо лучше.
УдалитьХорошо, но вообще добавлять лишний 0 это неправильно. Нужно обходиться с теми данными, которые есть. =))
Добрый день! Спасибо за подробные уроки, многому научилась, благодаря Вам (и тем, кто выполняет задания - очень полезно вникать в чужой код!)
ОтветитьУдалитьНо я постоянно сталкиваюсь с проблемой -- не выполняются простейшие вещи. Например, листинг 14.9:
#include
int main ()
{
char str [12];
fgets (str,12, stdin);
puts (str);
fputs (str, stdout);
return (0);
}
Вбиваю все, как у Вас написано. Компиляция проходит успешно, без ошибок, без предупреждений. Но при выполнении программа прерывается сразу после ввода строки. И подобное происходит постоянно, в других задачах тоже (например, также частенько глючит switch, не выполняется printf в циклах с условиями). Работаю в Visual Studio 2010. Подскажите, пожалуйста, с чем может быть связана проблема?
Добрый день. Спасибо за приятные слова.
УдалитьЧто значит прерывается? Окошко ввода исчезает и вы не можете посмотреть результат? Скорее всего именно это. Тогда перейдите в раздел FAQ там описано, как решить подобную проблему.)))
Все будет как надо.
Спасибо за оперативный ответ! Все действительно как надо )
УдалитьСнова вопрос ) Очень надеюсь на Вашу помощь. Написала программу, которая как раз считывает строку через fgets. Все работает отлично. Если же без изменений вставляю ее как функцию в другую программу, считывания строки не происходит, как будто сразу введен enter. Может быть, следует очищать входной поток, т.к. для вызова этой функции используется меню и как раз-таки нужно нажать enter, чтобы она начала работу?? Тогда как это сделать? Кусок кода выглядит так (все не вставляю, т.к. не работает уже на данном этапе):
ОтветитьУдалить#include
#include
#include
#include
int main ()
{
system("cls");
char str [101];
char sep []=" ";
char *istr;
char *next_token = NULL;
printf ("Input new string here(max 100 symbols): ");
fgets (str,101,stdin);
printf ("\nEntered: %s\n", str);
А в чем вопрос? Код вроде рабочий. Я запустил у себя, все отработало как нужно. После того, как printf выводит строку на экран, я ввел строку свою и она потом вывелась нормально.
УдалитьВ том-то и дело. А когда программа становится функцией, случается вот что (попробуйте):
Удалить#include stdio.h
#include conio.h
#include stdlib.h
#include string.h
void input_string();
int main ()
{
printf("\tLaboratory work #2.\n\tCreated by \n\tCase 5.\n\nProgram working with strings welcomes you!\n\n");
printf("Press any key to continue");
_getch();
int id=1;
do
{
system("cls");
printf ("What will you do?\n\n1. Input string\n2. Exit\n\nChoose index (1 or 2), please: ");
char ch;
scanf( " %c", &ch);
switch(ch)
{
case '1':
input_string();
_getch();
break;
case '2':
printf ("\nQuit? (y/n):");
char answer;
scanf (" %c",&answer);
if (answer=='Y'||answer=='y')
{
printf ("\nGood bye!");
_getch();
id=0;
}
break;
default:
printf("\n\nSorry, index %с is unknown", ch);
break;
}
}
while (id==1);
return 0;
}
void input_string()
{
char str[100];
char sep []=" ";
char *istr;
char *next_token = NULL;
system("cls");
printf ("Input new string here(max 100 symbols): ");
fgets (str,100,stdin);
printf ("\nEntered: %s\n", str);
printf ("\n\nResult:\n\n");
istr= strtok_s(str, sep, &next_token);
const int N=50;
char* arrstr[N]={0};
int i=0, kol=0;
arrstr[i]=istr;
while (arrstr[i])
{
printf ("%s\n", arrstr[i]);
arrstr [++i]=strtok_s(NULL,sep, &next_token);
kol++;
}
printf ("\nKol: %d\n", kol);
int how_much=0, max=strlen(arrstr[0]);
printf ("\nMax: %d\n", max);
for (int k=0; kmax)
{
max=(strlen(arrstr[k])-1);
how_much=k;
}
}
printf ("\n\nMax: %d. How much: %d", max, how_much);
_getch();
}
Мои глаза!!! ))) Для вставки больших кусков кода используйте пожалуйста сервис pastebin. Во-первых, вставляется без ошибок, а во-вторых форматирование есть. Скиньте код туда, я посмотрю.
Удалить1 задачка)
ОтветитьУдалить#include
int main()
{
char arr[101];
int i, shet=0;
fgets(arr,101,stdin);
for(i=0;arr[i]!='\0';++i)
++shet;
printf("\nvvedeno %d simvolov:", i-1);
return (0);
}
Добрый день.
ОтветитьУдалитьНе совсем правильно.
1. Нет считывания из файла.
2. Что за прикол?
char str3[1];
Если вам нужен один символ, то используйте переменную типа char. А то какие-то танцы с бубном.
3. Не понятно, зачем в двух местах считаете количество символов в строке.
while(str1[x]!='\0'){
x++;
}
4. Все же лучше использовать int main(), нежели void main().
Это то, что сразу бросается в глаза. Исправьте.
Уже лучше, хотя поток перевели неправильно. Первый аргумент это полный путь к файлу.
ОтветитьУдалитьК тому же есть переменные, которые объявлены, но не используются. Например, в функции s_down переменная j.
Конечно можно сократить, но не особо нужно. Позже еще внимательнее посмотрю, может что-то еще есть, что я упустил.
Суть решения правильная, но вы снова забыли о формате входных данных (файл, строки определенного формата).
УдалитьПолный путь к файлу включает также и имя файла с расширением. Попробуйте скомпилировать, ничего не получится.
задание 1:
ОтветитьУдалить#include
#include
int main()
{
char mass[101];
int i=0,a=0;
printf(" Vvedite stroku simvolov, ne bolee 100\n");
fgets(mass,101,stdin);
for(int i=0;i<100;i++)
{
switch (mass[i])
{
case '\0':printf("vvedeno %d simvolov \n",a-1);
}
a++;
}
_getch();
}
Прошу подсказку, как решить второе задание...тут ничего не нашел, и не могу себе представить совершенно, как регистры менять, кроме как ввести ВСЕ буквы в верхнем регистре и потом сравнивать введеные, но тогда моя программа выглядет, как черновик первоклассника.
И еще просьба: как сделать "критическое" прекращение цикла? то есть вот мое решение задачи 1: а++ продолжает считать и если под конец ввести printf("%d",a) то а показывает 100...а вот чтобы при нахождении \0 сразу прекратился цикл..
заранее огромное спасибо!!
Подсказка.
УдалитьКаждой букве соответствует определенная цифра в ASCII таблице кодов. И все буквы, обратите внимание, идут друг за дружкой, сначала маленькие, потом большие. Кроме того, вот вам еще и кусочек кода:
char ch='a';
printf("%d %d", ch, ch);
Есть такая инструкция break; она прерывает выполнение текущего цикла, а есть еще continue, она прерывает только текущую итерацию. Кажется в уроках про циклы я о них писал. Посмотрите там еще, ну или в интернете.)
с тем разобрался, сделал каждое задание по отдельности, поэтому думаю выкладывать нет смысла..спасибо за подсказку!
Удалитьзаморочился с удалением пробелов..сперва начал решать с switch, никак не мог придумать, перешел на второй массив символов, который присваивает значения себе без пробелов, но выводит какой то мусор. Думаю связано с тем, что \0 не передается...может быть дадите какой нибудь совет, как можно передать все символы из одного массива в другой, без пробелов?
у меня вот так:
int d=0
while((i<100)&&(mass[i]!=0))
{
if((mass[i]<='a')&&(mass[i]>='z'))
{
mass_2[d]=mass[i];
}
}
printf("%s",mass_2);
но почему то не работает и выводит мусор.(
заранее спасибо!
Не совсем понимаю, что вы хотите сделать. Лучше сначала общую задачу сформулируйте, потом опишите ваш подход к её решению, а затем проблему. Может быть вы просто пытаете сделать огромный крюк.)
УдалитьВ первом массиве mass[] я записал какую-нибудь строку...потом я хочу сохранить строку в другом массиве mass_2 только без пробелов,чтобы потом можно было проверить перевертыш это или нет. Делаю я это при помощи :
Удалитьint d=0
while((i<100)&&(mass[i]!=0))
{
if((mass[i]<='a')&&(mass[i]>='z'))
{
mass_2[d]=mass[i];
}
i++;
}
но в mass_2 сохраняется введеная строка и много какого то мусора. вечерок посидел подумал. предполагаю, что выводит на экран мусор, так как в mass_2 передаются только символы, а \0 нет, так как мое условие в while oстанавливает работу цикла если mass[i]!=0
int d=0
Удалитьwhile((i<100)&&(mass[i]!=0))
{
if((mass[i]<='a')&&(mass[i]>='z'))
{
mass_2[d]=mass[i];
d++;
}
i++;
}
маленькая поправочка)
Ну ничего не мешает вам сделать после этих циклов mass__2[d]='\0'; и мусора не будет.
УдалитьНу а про пробелы, ну можно вот так изменить ваш код и всё будет в ёлочку.
int d=0,i=0;
while((i<100)&&(mass[i]!='\0'))
{
if((mass[i]!=32)){
mass_2[d]=mass[i];
d++;
}
i++;
}
mass_2[d]='\0';
т.е. копируем в цикле любые символы, кроме пробела. 32 это номер пробела.
А вот это условие
(mass[i]<='a')&&(mass[i]>='z')
мне не очень понятно, оно никогда не сработает. там вы наверное хотели поставить ИЛИ, но тогда вы исключили из копирования все маленькие буквы.
Но это таки крюк. Учитывая тот факт, что программа принимает строку откуда-то, например со стандартного входа или из файла, лучше сразу её посимвольно считывать, пока она не закончится а в массив копировать все символы, за исключением пробелов. Так будет получше.
Спасибо!
УдалитьВаш ответ сразу стал понятен,решил разобраться вот с этим решением но задался ОДИН только вопрос :
#include // задание 5
#include
#include
int main()
{
char str[201];
int i=0,n,k=0;
fgets(str,201,stdin);
puts(str);
do{
switch (str[i]){
case ' ': { n=i; printf("n=%d\n",n); i--; k++;//ловим пробел
do{
str[n]=str[n+1];
n++;
printf("sdesj n=%d\n",n);
}while(str[n-1]);//do 2' выбросили пробел
printf("sei4as n=%d\n",n);
}//case ' '
default:str[i]=tolower(str[i]);//смена регистра подключить #include
}//switch(str[i])
i++;
printf("sei4as i=%d\n",i);
}while(str[i]);//do1' выбросили все пробелы и поменяли регистр
//i=длинна строки без пробелов+ноль символ,k=кол-во пробелов
printf("%s",str);
_getch();
}
во втором do я заменил условие в скобка на while(str[n]!=0) и оно работает как надо, соответственно..НО главный вопрос почему оно работает так же правильно если в скобках стоит while(str[n-1])...Разве цикл не должен тогда быть бесконечным? или зачем там вообще -1?
Прошу помощи, заранее спасибо
У вас очень-очень плохой код.Советую вам его удалить и никогда никому не показывать. )
УдалитьОчень странно, что вы спрашиваете у меня, зачем в вашем коде -1. Кто ж знает, зачем вы её написали. Я бы поковырялся в нём, но как уже написал выше, сие оскорбляет моё чувство прекрасного. И да, это не имеет ничего общего с 5 заданием. Советую вам продумать, как должно всё работать, а потом писать код.
Это не мое решение, я его взял здесь из комментариев, чтобы на примере других поучиться и все понял, кроме вот этого -1))
УдалитьПятая головоломка
ОтветитьУдалитьhttp://ideone.com/6peo30
Работает, но это очень корявый код. Давайте вместе его исправим.
УдалитьВы делаете слишком много лишнего.
Во-первых, если вы разбиваете на функции программу, то стоит выделить в ней отдельно функцию изменения регистра, а не писать внутри какой-то другой функции.
Во-вторых, этого можно вообще избежать.
В-третьих, вы для каждого символа проходите подряд всю строчку. А представьте, что у вас строка была бы длинны 1000, тогда в сумме вы бы прошли 1000*1000 = 1000000 это очень нерационально. Вложенные циклы в такой ситуации зло.
Даю подсказку, написать эту программу можно не используя вложенные циклы.
Если интересно, заведите одну переменную и при каждом присваивании в программе увеличивайте её значение на 1. Потом, когда напишем хорошую версию сделаем там тоже самое и сравним результаты. Вы будете удивлены огромной разницей.
еще более точно получится, если учитывать все арифметические операции и сравнения.
Вариант без циклов, собран на двух счетчиках.
Удалитьhttp://ideone.com/5AVJex
Нет, всё равно не так. Сам подход к подсчету количества вхождений не верный.
УдалитьВы делаете так. берете первую букву алфавита и смотрите сколько раз она встречается в строке. Потом вторую и т.д. всего получится 26*длина строки операций. Это плохой способ.
Подумайте еще.)
Подсказка: Достаточно один раз пройтись по всей строке, чтобы получить сколько и каких символов в ней есть.
Удалитьhttp://ideone.com/y4aov4
ОтветитьУдалитьВот так уже гораздо лучше. Но давайте добьём её до конца. Не будет считывать строку и передавать её в функцию, а будем работать в основной программе. И вот еще, зачем массив из 123 элементов? Ведь можно же обойтись и 27.
УдалитьИ определение длины строки нам не нужно. Подсказка: символ конца строки '\0'.
http://ideone.com/8I4aLr
УдалитьНе, ну вы просто функцию убрали.
УдалитьТакая программа слетит с ошибкой выполнения. Обратите внимание на размерность массива и строки 24-25, 31-33.
И вот еще что, сделайте так, чтобы не использовалось fgets, это лишнее сначала считать строку полностью, потом проверять каждый отдельный её символ. Читайте сразу по одному символу. Вы уже близки к цели))
Ничего не вылетает, все работает. Получется, что ячейки в массиве называются: 0, 1, 97 - 122, всего 28 ячеек.
Удалить28 ячеек, но только не 0, 1, 97 - 122, а 0,1,2, ... , 27. А при обращении к arr[97] будет ошибка. Элементы в массиве нумеруются последовательно, нельзя так пропустить кусочек. Но так как компилятор Си не отслеживает выход за границы массива, то программа будет скомпилирована без ошибок, но работать не будет.
УдалитьНо она работает, я же проверяю прежде чем отослать сюда.
УдалитьХм, странно. А каким компилятором вы пользуетесь?
УдалитьVisual Studio 2008
Удалитьhttp://ideone.com/Zm2iDO
УдалитьВот даже тут работает
На ideone работает и такой код http://ideone.com/F5LezV
УдалитьЭто говорит о том, что они не следят за памятью.
Другое дело ваша VS. Не понимаю что не так, но есть явно какая-то ошибка. Этот код обращается к произвольному куску памяти и пишет в него, но ничего не происходит.А должен происходить run time error. Попробуйте создать новый проект с таким же кодом и запустить его там. C VS бывают всякие приколы.
Массив устроен так, что память под него выделяется в последовательных ячейках, при написании a[i] идет работа с указателем *(a+i) здесь a - адрес нулевого элемента массива. a и i складываются в адресной арифметике. При обращении *(a+97) мы выйдем из того куска памяти, который зарезервирован под массив.
Так что все же прошу вас переписать программу.) В Си массивы индексируются с нуля и последовательно, никаких 0,1,97,98 и т.д. быть не может.
http://ideone.com/RQhaSD
УдалитьНе очень понимаю почему длина строки всегда на нуле. Если считывать текст полностью то все впорядке.
Как-будто он в этом месте if( str[i] == 0) не видит 0, если считывать по одному символу.
Потому что вы читаете из файла символы. Вы никогда не встретите там нулевого символа, там будет только конец файла проверяется как == EOF.
УдалитьЕще одно замечание. Зачем нужна целая строка str[200], если в каждый момент мы работаем только с одним символом. Мы же не выводим потом всю строку на экран. Поэтому этот массив лишний, достаточно одной переменной типа char.
Далее, цикл лучше делать иначе. Либо использовать whihe. Либо используя for сделать что-то похожее на while. Это нужно для того, чтобы читать не 200 символов, а только столько, сколько есть в файле, пока не наткнемся на конец файла.
Вроде бы всё остальное нормально.)
http://ideone.com/53qqnV
УдалитьВот это уже совсем другой разговор.
УдалитьЯ там внес косметические изменения, посмотрите разберитесь.
http://ideone.com/SOmyUy
Спасибо за проявленный интерес. Действительно занятно наблюдать за эволюцией данного кода.
УдалитьПоследняя задачка
ОтветитьУдалитьhttp://ideone.com/66xk1x
Не совсем верно. Читайте данные из файла и не обязательно на входе 3 строчки, может быть и 15 и 0. Сами строки выводить не нужно. Программа должна вывести на экран только два числа.
Удалитьhttp://ideone.com/ZNldcp
Удалитьhttp://pastebin.ru/sAdpazcQ
ОтветитьУдалитьзадание 4.
Добрый день Александр.
УдалитьЭто 3 задание, как я понимаю.
Если на вход подать qwer1 1rewq выдает, что это не перевертыш.
http://pastebin.ru/5JGIVHyy
УдалитьУбрал +1 в одиннадцатой строке и заработало.
http://pastebin.ru/gqZIj3y7
ОтветитьУдалитьзаданиеt 5.Получилось наконец с freopen.И что интересно!Если просто выводить файл на печать,то строка ограничивается != EOF.А если в программе с операциями,то != 0.Иначе с длинной строки туфта получается.Почему так?
Приветствую! По 1й программе
ОтветитьУдалитьВопрос такой, когда вводишь символы в функции fgets, потом считаешь кол-во сиволов до чара '\0' получается на один знак больше, чем фактически было введено. Также, например, если ничего не вводить, а просто кликнуть энтер когда работает fgets, все равно выдает, что 1 символ был введен.
Похоже, что это специфика fgets, то есть он записывает в строку символ переноса строки?
int main()
{
char str[1000];
int count = 0;
printf("Enter a string\n");
fgets(str, 1000, stdin);
printf("%s\n", str);
for(int i = 0; i < 1000; i++)
{
if (str[i] == '\0')
{
break;
}
else
{
count++;
}
}
printf("number of chars in string: %d\n", count);
return(0);
}
//Задание 1
ОтветитьУдалить#include
#include
using namespace std;
int main()
{
setlocale(LC_ALL, "rus");
cout<<"Введите строку для проверки количества символов\n";
char stroka[100];
fgets(stroka,100,stdin);
for (int i=0;i<100;i++)
{
if(((stroka[i] < 65)||(stroka[i]>122))&&(stroka[i]!=32))
{
cout<<"Строка состоит из "<<i<<" символов\n"<<endl;
break;
}
}
return 0;
}
как в одном условии задать сразу 2 предела строки я не знаю ибо один другому помешает(в итоге 6 символов с 91 по 96 тоже считаються, а прописывать stroka[i]!=1, 2, 3 ,4 ,5 ,6 ,7..... сами понимаете)да и два условия лень писать было)
Удалитья вообще по началу хотел искать через \0 но потом решил что можно совсем без него обойтись, есть правда пара нюансов(таких как не восприятие любых символов кроме английских), но условие я выполнил 100%(цитата "Напишите программу, которая определяет длину этой строки, без учета нулевого символа")
УдалитьЗадание 2(Писал прямо по ходу прочтения урока)
ОтветитьУдалить//Урок 14
#include
#include
using namespace std;
int dmain()
{
setlocale(LC_ALL, "Rus");
char str[20];
fgets(str,20,stdin);
for(int i=0; i<20; i++)
{
if((str[i]>=65)&&(str[i]<=90))
{
str[i]+=32;
}
cout<122)
{
str[i]=32;
}
}
str[18]=32;
fputs(str, stdout);
return(0);
}
правда так и не понял почему он пробелы не ставит? потому тут обрывки попыток остались str[18]=0 :D
Удалитья почти сломал мозг, а потом решил отделить один файл от других и они заработали. По всей видимости Using namespace std; как то их обьеденял в одном проэкте.
ОтветитьУдалитьвышло так
//Задание 3
#include
#include
using namespace std;
int main()
{
setlocale(LC_ALL, "rus");
char str[100], str2[100];
int x;// темп
int k=0;//для создание безпробельной строки 2
cout<<"Введите строку для проверки, перевёртыш она или нет\n";
fgets(str,100,stdin);// считывание строки
for(int i=0; i<100;i++)
{
if ((str[i]>=65)&&(str[i]<=90))
{
str[i]+=32;
}//рабочее
if (str[i]!=32)
{
str2[k]=str[i];
k++;
}//рабочее
}
for(int i=0; i<100;i++)
{
if(str2[i]==0)
{
x=i-1;
break;
}
}
cout<<"первый символ = "<< str2[0]<<" последний символ = "<<str2[x-1]<<endl;
cout<<"Строка состоит из = "<< x<<"символa(ов)\n";
puts(str2);// получивщаяся строка
int y=x-1;
for(int i=0;i<=x-1;i++)
{
if(str2[i]==str2[y])
{
cout<<"Символ "<<i+1<<"="<<y+1<<"\n";
}
else
{
cout<<"Строка не перевертыш\n";
return 0;
}
y-=1;
}
cout<<"Строка является перевертышем\n";
return 0;
}
+1 -1 перестали работать инскримент и дискримент, хз почему так
Удалить//Задание 4
ОтветитьУдалить#include
#include
using namespace std;
int main()
{
setlocale(LC_ALL, "rus");
cout<<"Введите две строки, для проверки идентичные они или нет\n";
char set[100], set2[100];
fgets(set, 100, stdin);
fgets(set2, 100, stdin);
for (int i=0;i<100; i++)
{
if((set[i]<=90)&&(set[i]>=65))
{
set[i]+=32;
}
if((set2[i]<=90)&&(set2[i]>=65))
{
set2[i]+=32;
}
if (set[i]==set2[i])
{
cout<<"Символ "<<i+1 <<" в обоих строках одинаковый\n";
}
else
{
cout<<"Символ"<<i+1<<" не совподает в строках\nСтроки разные\n";
return 0;
}
}
cout<<"Строки идентичные"<<endl;
return 0;
}
Про пробелы в описании к заданию ни слова, их тоже проверяет на совпадение
Задание 5 Цикл в цикле(внутри 2 цикла if) и 2 if внутри первого
ОтветитьУдалить//Задание 5
#include
#include
using namespace std;
int main()
{
setlocale(LC_ALL, "rus");
char str[200], temp_c;
int temp=0, probel=0;
freopen("E:\\input.txt","r+",stdin);
fgets(str,200,stdin);
cout<<"В строке "<=0; x--)
{
if ((str[i]==str[x])&&(str[i]!=33)&&(str[i]!=32))
{
temp++;
str[x]=33;
}
}
if (str[i]==32)
{
probel++;
}
if ((temp_c!=33)&&(temp_c!=32))
{
cout<<temp_c<<"="<<temp<<endl;
}
temp=0;
}
cout<<"Пробелов= "<< probel<<endl;
return 0;
}
//Задание 6
ОтветитьУдалить#include
#include
#include
using namespace std;
int main()
{
setlocale(LC_ALL, "Rus");
char stroka[10];
char exit[]="exit";
char west[]="west";
char east[]="east";
char south[]="south";
char north[]="north";
int otvet[2]={0,0}, temp;
cout<<"Введите направление и кол-во шагов через пробел\nПример:North 5, west 3...\nДля окончания ввода введите \'q\'\n";
while (true)
{
cin>>stroka>>temp;
if (strncmp(stroka,exit,4)==0)
{
cout<<"Координаты: X="<<otvet[0]<<" Y="<<otvet[1]<<endl;
return 0;
}
if (strncmp(stroka,west,4)==0)
{
otvet[0]+=temp;
}
if (strncmp(east,stroka,4)==0)
{
otvet[0]-=temp;
}
if (strncmp(north,stroka,5)==0)
{
otvet[1]+=temp;
}
if (strncmp(south,stroka,5)==0)
{
otvet[1]-=temp;
}
if ( (strncmp(stroka,exit,4)!=0) && (strncmp(stroka,east,4)!=0) && (strncmp(stroka,west,4)!=0) && (strncmp(stroka,north,5)!=0) && (strncmp(stroka,south,5)!=0) )
{
cout<<"Вы ввели неверные данные\n";
}
}
return 0;
}
при вводе без пробела зацикливается и постоянно выдает "Вы ввели неверные данные",вылечить не смог. админ где же ты....
Огромное спасибо автору за простое и понятное объяснение!!!
ОтветитьУдалитьДа уж... Справочная информация нужна, а не - муссор, флинт и др...
ОтветитьУдалитьпомогите пожалуйста !
ОтветитьУдалитьчто такое оператор key и как работает.как вывести на экран yes и no