Последние новости

YoungCoder теперь и на Stepikе. Записывайтесь: https://vk.cc/75rISy

Чтобы записаться на курс, необходимо зарегистрироваться на Степике: https://vk.cc/75rIC4

Это моя личная ссылка-приглашение на Stepik для вас. Регистрируясь по этой ссылке, записываясь на курсы и решая задачи, Вы помогаете автору данного сайта принять участие в конкурсе платформы Stepik! Подробности конкурса здесь: https://vk.cc/75rKuS

воскресенье, 4 августа 2013 г.

Занятие 14. Строки и символьные массивы в языке Си.


Добрый день друзья. На прошлом занятии мы разобрались с одномерными массивами. Сегодня разберемся с одним их частным случаем - символьными строками.  С ними мы уже даже сталкивались. В самом первом уроке. Помните, выводили на экран строчку 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);
}

Рис.3. Символьный массив после объявления
Как видите, для вывода строк можно использовать стандартную функцию printf(), для которой предусмотрен специальный спецификатор %s. В остальном никаких отличий здесь нет.

Теперь разберемся, как присвоить значение строке. Есть несколько способов. 

  • Как и любая переменная, строка может быть инициализирована (т.е. ей присвоено некоторое значение) непосредственно при её объявлении.
Листинг 14.3
#include <stdio.h> 
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); 
}

В этом случае, компилятор сам посчитает количество символов для хранения строки в кавычках, и сам учтет заключительный символ ‘\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); 
}

Результат работы этой программы представлен на следующем рисунке.
Рис. 4. Вывод на экран символьного массива без нулевого элемента в конце

 Как можете заметить, вывелись первый символ, потом один символ пропущенный (с мусором), дальше второй символ, сохраненный нами в программе, а дальше пошел неконтролируемый мусор. Не контролируемый потому что непонятно даже, сколько там символов вывелось, но явно не оставшиеся два символа.

Ввод и вывод строк.

Теперь рассмотрим, как можно ввести  строку символов с клавиатуры.
Возникает естественное желание воспользоваться стандартной функцией scanf(). Попробуем.

Листинг 14.6
#include <stdio.h> 
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(){
      char str[17];
      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); 
}

Функция принимает три аргумента.
  1. Массив символов, в который необходимо записать  вводимую строку.
  2. Количество символов, которые может считать функция с учетом символа конца строки. В нашем случае это 10, т.е. рабочих из них девять, и один зарезервирован для конца строки.
  3. Откуда читать данные. В нашем случае указан стандартный поток ввода.
Попробуем в нашей программе Листинг 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); 
}

Результат выполнения это программы:

Рис.9. Использование стандартных функций вывода строки puts(), fputs(). Особенности вывода.
Как видите, функция puts является обратной к функции gets(). Она выводит строку заменяя символ конца строки на символ переноса строки. И поэтому то, что выводи функция fputs() оказывается на новой строке. А вот функция fputs() дополнительного переноса строки не делает. 

На этом на сегодня всё. На следующем уроке будем разбирать стандартные функции, которые работают со строками.

Задания для самостоятельной практической работы.

  •  На вход программе подается строка, длинной не более 100 символов. Напишите программу, которая определяет длину этой строки, без учета нулевого символа.
  • Напишите программу, которая переводит данную строку в нижний регистр. Т.е. и строки "Hello WorlD" должна получиться строка "hello world"
  • На вход программе подается строка, длинной не более 100 символов. Определить, является ли она перевертышем. Например, как слово "шалаш" или "топот". Учтите что строка может содержать пробелы, их учитывать не нужно. Например, строка "А роза упала на лапу Азора" будет являться перевертышем.
  • Пользователь вводит две строки. Необходимо сравнить их между собой, и вывести yes если строки полностью совпадают, или no в противном случае. Регистр учитывать не нужно. Т.е строки "Hello WorlD" и "hello world" считаются двумя одинаковыми строками.
  • Напишите программу, которая читает из файла строку, длинной не более 200 символов. И считает количество вхождения в строку всех используемых в ней символов,без учета регистра. На вход поступает строка состоящая из букв латинского алфавита и пробелов. Программа должна вывести в первой строке длину введенной строки. В следующих строках встречаемые символы и их количество. Например, для строки "hello world", вывод будет следующим.
11
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.

Если Вам понравился этот урок, расскажите о нем вашим друзьям. В этом  Вам могут помочь кнопки основных социальных сетей, расположенные ниже. Вам остается всего лишь кликнуть по любой из них.

120 комментариев :

  1. Самый непонятный урок для меня :(
    Особенно с длинной строки.
    "Количество символов, которые может считать функция с учетом символа конца строки. В нашем случае это 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

    ОтветитьУдалить
    Ответы
    1. Я наверное коряво написал. Смотрите 10 можете считать. Из них рабочих 9. А десятый, который не рабочий как раз и зарезервирован под конец строки.

      Вы забыли, что тип char совместим с целым типом. каждому символу соответствует число, код этого символа в таблице ASCII. Вот символу конца строки соответствует число нуль. Поэтому конец строки мы можем проверять как str[i] != 0;

      Длина массива и длинна строки это разные вещи ведь. Длинна массива может быть и 100 элементов, а вот длина строки, которая хранится в этом массиве может быть и меньше. Например, Литстинг 14.3
      Длинна массива str 17 элементов, а длина строки, которую мы туда поместили всего двенадцать. Из них, как мы уже разобрались 11 рабочие и последний, двенадцатый символ конца строки. )

      Теперь, с учетом этих пояснений попробуйте ответить на свои последние вопросы или переформулировать их. Если не получится, напишите я или отвечу или дам еще подсказку. )

      Удалить
  2. 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);
    }

    ОтветитьУдалить
    Ответы
    1. char str [100];
      //0-99 рабочих (100) + 1 на конец строки.

      тут всего с 0 по 99, сотого нет. Чтобы уместить 100, нужно объявлять 101. Тогда будет как вы написали. Но это не важно. =))

      Сама идея правильная, именно такое решение я и ожидал увидеть.
      Но есть ошибки в коде. Например, цикл для длины строки бесконечный. Внимательно посмотрите на условие.=))

      Удалить
  3. Этот комментарий был удален автором.

    ОтветитьУдалить
  4. /*Месье знает толк в извращениях - думаю есть решение проще. И да я не выполнил условие "На вход программе.." т.к. не могу его проверить, т.к. компилятора под рукой нет, компилю онлайн, и нет возможности ввода.

    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);
    }

    ОтветитьУдалить
    Ответы
    1. С Русскими символами кажется разобрался. Не ту таблицу посмотрел.
      Для преобразованию Русских символов такой код:
      if ((str[i] > 127)&&(str[i] < 159)) {
      if ((str[i] > 127)&&(str[i] < 144)) {
      str[i]+=32;
      } else {
      str[i]+=80;
      }
      }
      В программу встраивать не стал.

      Удалить
    2. Длину строки и удаление пробелов нужно сделать за один цикл. Думаю туда же можно включить и преобразование регистра. =)) В общем, доведите программу до нормально вида, а то это даже вам, кажется извращением. =))

      Удалить
    3. И не парьтесь с русскими символами. )) Выполняйте задание только для латиницы. Никакого отдельного интереса они не представляют. Принцип тот же. )

      Удалить
    4. Все действительно в один 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++;
      }

      Удалить
    5. И снова нет! =))
      У вас опять вложенные циклы.
      Смотрите как должно быть.
      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"
      И так после каждого пробела, будет запускаться внутренний цикл и копироваться все не нужное влево на один символ. Это не экономно. =))

      Удалить
  5. Сравнение строк, в отличии от предыдущей задачи не меняет сами строки :)

    #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);
    }

    ОтветитьУдалить
    Ответы
    1. Как только вот это увидел

      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 обойтись.Подумайте, что лишнего вы ищете и проверяете. =)) Например, так ли вам нужно знать длины строк? Ну и там еще посмотрите, что можно упростить.

      Удалить
    2. как то так.

      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);
      }

      Удалить
    3. Не компилирую, но это правильно. Замечательно! Именно это я и хотел увидеть. =)))

      Попроще, да? Чем предыдущий код? ))

      Удалить
    4. Хотя нет, условие плоховато для цикла.
      "A roza upala na lapu Azora" и "a roza upala" вернет YES, но это же явный NO. )))

      Удалить
    5. Так то оно так, но если ввести не только буквы, а ещё и цифры
      то введённые : R и 2 в разные строки, напишет yes.

      Удалить
  6. Пятая. С предыдущими разобрался, но выкладывать уже думаю смысла нет, и так все разжевано.

    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);
    }

    ОтветитьУдалить
    Ответы
    1. Если сами разобрались, то конечно не стоит писать сюда. Хотя я бы почитал, как Вы решили проблему с удаление лишних пробелов. =)

      Теперь по пятой программе. Выводит она не то, что требуется. Лишнее есть. Снова мной замечены вложенные циклы. Мне это не нравится. Думаю можно сделать без этого. Кстати, стоит рассказать, чем мне так не нравятся вложенные циклы? )

      Подумайте еще или хотя бы исправьте вывод. Уберите все лишнее. )))

      Удалить
  7. Все у меня голова сегодня не варит :)
    По последней задаче.
    Можно ведь считывать введенное с клавиатуры таким образом:
    сканф(строка)
    и т.к. пробел сработает как разделитель еще раз считать но уже число после пробела тогда все легко.
    Но если использовать фгетс и введенное полностью считать как сторку..тут посложнее и вот тут то похоже меня опять в дебри и понесло.

    Что я хотел сделать читать строку до пробела и получить ASCII сумму направления.
    Дальше читать от пробела до конца строки количество символов и получить разрядность.
    Опять читать от пробела до конца строки получать int iй элемент умножать его на разрядность и отнимать от последней один разряд. т.о. получить число. Что то я сомневаюсь в рациональности такого метода :)

    ОтветитьУдалить
    Ответы
    1. Не совсем понял, что вы хотите сделать. =))
      Я лучше посмотрю Ваш код, когда вы его напишете, и прокомментирую более подробно. Посмотрим, что там можно улучшить и от чего можно избавиться, что оптимально, а что не очень. =)))

      Удалить
  8. Спасибо урок очнь интересный.
    Задание 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);
    }
    вроде работает .

    ОтветитьУдалить
  9. задание 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);
    }

    ОтветитьУдалить
    Ответы
    1. Хаа, какой вы шустрый. Хвалю что знаете такую функцию, но нужно написать программу без использования стандартных функций. Основываясь на закономерностях таблицы символов ASCII. ))

      Удалить
  10. #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);
    }

    ОтветитьУдалить
    Ответы
    1. Неправильно. Путь может состоять и из 100 шагов Например:
      North 5
      East 3
      South 2
      North 2
      East 12
      South 1
      West 22
      =)))
      И при некоторых данных происходит выход за пределы массива кажется.

      Удалить
  11. Задание 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);
    }

    ОтветитьУдалить
    Ответы
    1. Уже лучше, чем тот код, что выше. Но вы снова использовали стандартные функции. =))

      Удалить
  12. Задание 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;
    }

    ОтветитьУдалить
  13. Задание 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);
    }

    ОтветитьУдалить
    Ответы
    1. Слишком громоздко. Можно проще, не забывайте про таблицу ASCII. =))

      Удалить
  14. В пятом задании прямо просятся функции , но чей-то я не догоняю,как туда строку загнать...

    ОтветитьУдалить
    Ответы
    1. Все намного проще.Присмотритесь, там можно обойтись и без строк. =)

      Удалить
    2. Это я про 6 задание говорил. =) Но в 5 тоже все гораздо проще. )

      Удалить
  15. Почему второй раз выводится сначала мусор, а затем введённые символы причём количество не соответствует заявленному?
    #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. Вы читаете из стандартного потока вывода, который в этот момент уже пустой. Оттуда ничего считать не может функция. Поэтому возникает ошибка. Я еще расскажу, о том как контролировать такие ошибки. Быть может добавлю даже в этот урок. =)

      Удалить
  16. задание 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;
    }

    ОтветитьУдалить
  17. задание 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;
    }

    ОтветитьУдалить
    Ответы
    1. Нет, не правильно. Вы не учли добавление про регистр. И само сравнение можно получше организовать, без счетчика условия после цикла. Подумайте на этим.))

      Удалить
    2. #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;
      }
      может быть так?

      Удалить
    3. Всё бы хорошо, но получается для использования одной функции tolower вы подключаете целую библиотеку дополнительно. Это не "айс", тем более, что такую функцию вы можете написать самостоятельно, что от вас и требуется, во втором задании. =)) Переделайте, чтобы было как надо. А потом поговорим еще про небольшую оптимизацию кода. Чтобы было покрасивее. )

      Удалить
    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 && 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;
      }

      Удалить
    5. Уже лучше. Теперь давайте разберемся.
      Смотрите, обязательно ли нам нужна переменная k? Ведь можно обойтись без неё. Подумайте как можно избавиться от этой переменной и последнего if, в котором мы определяем, что выводить yes или no.

      Удалить
    6. #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...теперь думаю почему же))

      Удалить
    7. меня смущает, что сработало if()...return 0, так разве оператор for останавливаться должен? или это значит что конец работы целой, главной функции?

      Удалить
    8. Именно. Это означает конец работы главной фукции main. Если мы поняли, что строки не совпадают, то мы можем сразу заканчивать программу. Хотя здесь не обязательно выходить из программы так. Можно просто выйти из цикла. Знаете как это сделать?

      Удалить
    9. exit(1); вместо return 0;
      с break не вышло, с continue вроде как для других операторов?

      Удалить
    10. Все нормально было. Это я ошибся. Так хорошо. Я подумал, что последний printf был внутри цикла, а он снаружи.

      Удалить
  18. Задание 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. 1 инициализация всего что пригодится
      2 просим ввести сторону и координаты
      3 оператором switch определяем в какую сторону будет приращение
      4 определяем default на окончание строки
      5 чтобы цикл не прекращался просто так в конце просим ввести еще сторону и координаты и так до тех пор пока не встретится конец строки

      Удалить
    3. В тех случаях, когда действие гарантировано выполнится хотя бы один раз, лучше использовать цикл с постусловием do ... while. У вас как раз такой случай. Переделайте, так будет гармоничнее и лучше. И добавьте считывание входных данных из файла.

      Удалить
    4. #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. а без него новая строка не читается и получается зацикливание

      Удалить
    5. Вот это гораздо лучше.
      Хорошо, но вообще добавлять лишний 0 это неправильно. Нужно обходиться с теми данными, которые есть. =))

      Удалить
  19. Добрый день! Спасибо за подробные уроки, многому научилась, благодаря Вам (и тем, кто выполняет задания - очень полезно вникать в чужой код!)
    Но я постоянно сталкиваюсь с проблемой -- не выполняются простейшие вещи. Например, листинг 14.9:

    #include
    int main ()
    {
    char str [12];
    fgets (str,12, stdin);
    puts (str);
    fputs (str, stdout);
    return (0);
    }

    Вбиваю все, как у Вас написано. Компиляция проходит успешно, без ошибок, без предупреждений. Но при выполнении программа прерывается сразу после ввода строки. И подобное происходит постоянно, в других задачах тоже (например, также частенько глючит switch, не выполняется printf в циклах с условиями). Работаю в Visual Studio 2010. Подскажите, пожалуйста, с чем может быть связана проблема?

    ОтветитьУдалить
    Ответы
    1. Добрый день. Спасибо за приятные слова.

      Что значит прерывается? Окошко ввода исчезает и вы не можете посмотреть результат? Скорее всего именно это. Тогда перейдите в раздел FAQ там описано, как решить подобную проблему.)))
      Все будет как надо.

      Удалить
    2. Спасибо за оперативный ответ! Все действительно как надо )

      Удалить
  20. Снова вопрос ) Очень надеюсь на Вашу помощь. Написала программу, которая как раз считывает строку через 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);

    ОтветитьУдалить
    Ответы
    1. А в чем вопрос? Код вроде рабочий. Я запустил у себя, все отработало как нужно. После того, как printf выводит строку на экран, я ввел строку свою и она потом вывелась нормально.

      Удалить
    2. В том-то и дело. А когда программа становится функцией, случается вот что (попробуйте):

      #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();

      }

      Удалить
    3. Мои глаза!!! ))) Для вставки больших кусков кода используйте пожалуйста сервис pastebin. Во-первых, вставляется без ошибок, а во-вторых форматирование есть. Скиньте код туда, я посмотрю.

      Удалить
  21. 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);
    }

    ОтветитьУдалить
  22. Добрый день.
    Не совсем правильно.
    1. Нет считывания из файла.
    2. Что за прикол?

    char str3[1];
    Если вам нужен один символ, то используйте переменную типа char. А то какие-то танцы с бубном.
    3. Не понятно, зачем в двух местах считаете количество символов в строке.
    while(str1[x]!='\0'){
    x++;
    }

    4. Все же лучше использовать int main(), нежели void main().


    Это то, что сразу бросается в глаза. Исправьте.

    ОтветитьУдалить
  23. Уже лучше, хотя поток перевели неправильно. Первый аргумент это полный путь к файлу.
    К тому же есть переменные, которые объявлены, но не используются. Например, в функции s_down переменная j.

    Конечно можно сократить, но не особо нужно. Позже еще внимательнее посмотрю, может что-то еще есть, что я упустил.

    ОтветитьУдалить
    Ответы
    1. Суть решения правильная, но вы снова забыли о формате входных данных (файл, строки определенного формата).

      Полный путь к файлу включает также и имя файла с расширением. Попробуйте скомпилировать, ничего не получится.

      Удалить
  24. задание 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 сразу прекратился цикл..

    заранее огромное спасибо!!

    ОтветитьУдалить
    Ответы
    1. Подсказка.
      Каждой букве соответствует определенная цифра в ASCII таблице кодов. И все буквы, обратите внимание, идут друг за дружкой, сначала маленькие, потом большие. Кроме того, вот вам еще и кусочек кода:
      char ch='a';
      printf("%d %d", ch, ch);

      Есть такая инструкция break; она прерывает выполнение текущего цикла, а есть еще continue, она прерывает только текущую итерацию. Кажется в уроках про циклы я о них писал. Посмотрите там еще, ну или в интернете.)

      Удалить
    2. с тем разобрался, сделал каждое задание по отдельности, поэтому думаю выкладывать нет смысла..спасибо за подсказку!

      заморочился с удалением пробелов..сперва начал решать с 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);
      но почему то не работает и выводит мусор.(

      заранее спасибо!

      Удалить
    3. Не совсем понимаю, что вы хотите сделать. Лучше сначала общую задачу сформулируйте, потом опишите ваш подход к её решению, а затем проблему. Может быть вы просто пытаете сделать огромный крюк.)

      Удалить
    4. В первом массиве 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

      Удалить
    5. int d=0
      while((i<100)&&(mass[i]!=0))
      {
      if((mass[i]<='a')&&(mass[i]>='z'))
      {
      mass_2[d]=mass[i];
      d++;
      }
      i++;
      }

      маленькая поправочка)

      Удалить
    6. Ну ничего не мешает вам сделать после этих циклов 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')

      мне не очень понятно, оно никогда не сработает. там вы наверное хотели поставить ИЛИ, но тогда вы исключили из копирования все маленькие буквы.

      Но это таки крюк. Учитывая тот факт, что программа принимает строку откуда-то, например со стандартного входа или из файла, лучше сразу её посимвольно считывать, пока она не закончится а в массив копировать все символы, за исключением пробелов. Так будет получше.

      Удалить
    7. Спасибо!
      Ваш ответ сразу стал понятен,решил разобраться вот с этим решением но задался ОДИН только вопрос :

      #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?

      Прошу помощи, заранее спасибо

      Удалить
    8. У вас очень-очень плохой код.Советую вам его удалить и никогда никому не показывать. )
      Очень странно, что вы спрашиваете у меня, зачем в вашем коде -1. Кто ж знает, зачем вы её написали. Я бы поковырялся в нём, но как уже написал выше, сие оскорбляет моё чувство прекрасного. И да, это не имеет ничего общего с 5 заданием. Советую вам продумать, как должно всё работать, а потом писать код.

      Удалить
    9. Это не мое решение, я его взял здесь из комментариев, чтобы на примере других поучиться и все понял, кроме вот этого -1))

      Удалить
  25. Пятая головоломка
    http://ideone.com/6peo30

    ОтветитьУдалить
    Ответы
    1. Работает, но это очень корявый код. Давайте вместе его исправим.
      Вы делаете слишком много лишнего.
      Во-первых, если вы разбиваете на функции программу, то стоит выделить в ней отдельно функцию изменения регистра, а не писать внутри какой-то другой функции.
      Во-вторых, этого можно вообще избежать.
      В-третьих, вы для каждого символа проходите подряд всю строчку. А представьте, что у вас строка была бы длинны 1000, тогда в сумме вы бы прошли 1000*1000 = 1000000 это очень нерационально. Вложенные циклы в такой ситуации зло.
      Даю подсказку, написать эту программу можно не используя вложенные циклы.

      Если интересно, заведите одну переменную и при каждом присваивании в программе увеличивайте её значение на 1. Потом, когда напишем хорошую версию сделаем там тоже самое и сравним результаты. Вы будете удивлены огромной разницей.
      еще более точно получится, если учитывать все арифметические операции и сравнения.

      Удалить
    2. Вариант без циклов, собран на двух счетчиках.
      http://ideone.com/5AVJex

      Удалить
    3. Нет, всё равно не так. Сам подход к подсчету количества вхождений не верный.
      Вы делаете так. берете первую букву алфавита и смотрите сколько раз она встречается в строке. Потом вторую и т.д. всего получится 26*длина строки операций. Это плохой способ.
      Подумайте еще.)

      Удалить
    4. Подсказка: Достаточно один раз пройтись по всей строке, чтобы получить сколько и каких символов в ней есть.

      Удалить
  26. Ответы
    1. Вот так уже гораздо лучше. Но давайте добьём её до конца. Не будет считывать строку и передавать её в функцию, а будем работать в основной программе. И вот еще, зачем массив из 123 элементов? Ведь можно же обойтись и 27.
      И определение длины строки нам не нужно. Подсказка: символ конца строки '\0'.

      Удалить
    2. Не, ну вы просто функцию убрали.
      Такая программа слетит с ошибкой выполнения. Обратите внимание на размерность массива и строки 24-25, 31-33.
      И вот еще что, сделайте так, чтобы не использовалось fgets, это лишнее сначала считать строку полностью, потом проверять каждый отдельный её символ. Читайте сразу по одному символу. Вы уже близки к цели))

      Удалить
    3. Ничего не вылетает, все работает. Получется, что ячейки в массиве называются: 0, 1, 97 - 122, всего 28 ячеек.

      Удалить
    4. 28 ячеек, но только не 0, 1, 97 - 122, а 0,1,2, ... , 27. А при обращении к arr[97] будет ошибка. Элементы в массиве нумеруются последовательно, нельзя так пропустить кусочек. Но так как компилятор Си не отслеживает выход за границы массива, то программа будет скомпилирована без ошибок, но работать не будет.

      Удалить
    5. Но она работает, я же проверяю прежде чем отослать сюда.

      Удалить
    6. Хм, странно. А каким компилятором вы пользуетесь?

      Удалить
    7. http://ideone.com/Zm2iDO
      Вот даже тут работает

      Удалить
    8. На ideone работает и такой код http://ideone.com/F5LezV
      Это говорит о том, что они не следят за памятью.

      Другое дело ваша VS. Не понимаю что не так, но есть явно какая-то ошибка. Этот код обращается к произвольному куску памяти и пишет в него, но ничего не происходит.А должен происходить run time error. Попробуйте создать новый проект с таким же кодом и запустить его там. C VS бывают всякие приколы.

      Массив устроен так, что память под него выделяется в последовательных ячейках, при написании a[i] идет работа с указателем *(a+i) здесь a - адрес нулевого элемента массива. a и i складываются в адресной арифметике. При обращении *(a+97) мы выйдем из того куска памяти, который зарезервирован под массив.

      Так что все же прошу вас переписать программу.) В Си массивы индексируются с нуля и последовательно, никаких 0,1,97,98 и т.д. быть не может.

      Удалить
    9. http://ideone.com/RQhaSD
      Не очень понимаю почему длина строки всегда на нуле. Если считывать текст полностью то все впорядке.
      Как-будто он в этом месте if( str[i] == 0) не видит 0, если считывать по одному символу.

      Удалить
    10. Потому что вы читаете из файла символы. Вы никогда не встретите там нулевого символа, там будет только конец файла проверяется как == EOF.

      Еще одно замечание. Зачем нужна целая строка str[200], если в каждый момент мы работаем только с одним символом. Мы же не выводим потом всю строку на экран. Поэтому этот массив лишний, достаточно одной переменной типа char.
      Далее, цикл лучше делать иначе. Либо использовать whihe. Либо используя for сделать что-то похожее на while. Это нужно для того, чтобы читать не 200 символов, а только столько, сколько есть в файле, пока не наткнемся на конец файла.
      Вроде бы всё остальное нормально.)

      Удалить
    11. Вот это уже совсем другой разговор.
      Я там внес косметические изменения, посмотрите разберитесь.
      http://ideone.com/SOmyUy

      Удалить
    12. Спасибо за проявленный интерес. Действительно занятно наблюдать за эволюцией данного кода.

      Удалить
  27. Последняя задачка
    http://ideone.com/66xk1x

    ОтветитьУдалить
    Ответы
    1. Не совсем верно. Читайте данные из файла и не обязательно на входе 3 строчки, может быть и 15 и 0. Сами строки выводить не нужно. Программа должна вывести на экран только два числа.

      Удалить
  28. Ответы
    1. Добрый день Александр.
      Это 3 задание, как я понимаю.
      Если на вход подать qwer1 1rewq выдает, что это не перевертыш.

      Удалить
    2. http://pastebin.ru/5JGIVHyy
      Убрал +1 в одиннадцатой строке и заработало.

      Удалить
  29. http://pastebin.ru/gqZIj3y7
    заданиеt 5.Получилось наконец с freopen.И что интересно!Если просто выводить файл на печать,то строка ограничивается != EOF.А если в программе с операциями,то != 0.Иначе с длинной строки туфта получается.Почему так?

    ОтветитьУдалить
  30. Приветствую! По 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);
    }


    ОтветитьУдалить
  31. //Задание 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;
    }

    ОтветитьУдалить
    Ответы
    1. как в одном условии задать сразу 2 предела строки я не знаю ибо один другому помешает(в итоге 6 символов с 91 по 96 тоже считаються, а прописывать stroka[i]!=1, 2, 3 ,4 ,5 ,6 ,7..... сами понимаете)да и два условия лень писать было)

      Удалить
    2. я вообще по началу хотел искать через \0 но потом решил что можно совсем без него обойтись, есть правда пара нюансов(таких как не восприятие любых символов кроме английских), но условие я выполнил 100%(цитата "Напишите программу, которая определяет длину этой строки, без учета нулевого символа")

      Удалить
  32. Задание 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);
    }

    ОтветитьУдалить
    Ответы
    1. правда так и не понял почему он пробелы не ставит? потому тут обрывки попыток остались str[18]=0 :D

      Удалить
  33. я почти сломал мозг, а потом решил отделить один файл от других и они заработали. По всей видимости 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 -1 перестали работать инскримент и дискримент, хз почему так

      Удалить
  34. //Задание 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;
    }
    Про пробелы в описании к заданию ни слова, их тоже проверяет на совпадение

    ОтветитьУдалить
  35. Задание 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;
    }

    ОтветитьУдалить
  36. //Задание 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;
    }
    при вводе без пробела зацикливается и постоянно выдает "Вы ввели неверные данные",вылечить не смог. админ где же ты....

    ОтветитьУдалить
  37. Огромное спасибо автору за простое и понятное объяснение!!!

    ОтветитьУдалить
  38. Да уж... Справочная информация нужна, а не - муссор, флинт и др...

    ОтветитьУдалить
  39. помогите пожалуйста !
    что такое оператор key и как работает.как вывести на экран yes и no

    ОтветитьУдалить

Примечание. Отправлять комментарии могут только участники этого блога.