Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: [C] Помогите решить простую задачу со строками  (Прочитано 11045 раз)
0 Пользователей и 1 Гость смотрят эту тему.
tumanovalex
Помогающий

ru
Offline Offline

« : 30-01-2009 13:23 » 

Нужно выделять в строке пары букв. В строке  t = "маланаламана" сначала нужно выделить "ма", потом "ал", потом "ла" и так далее. Причем в строку p нужно помещать только уникальные сочетания двух букв, например, должно быть одно "ма". У меня же в результата количество повторяющихся символов 1, а в строке p - строка "мааллааннааллааммаанна" - 2 ма, 2 на, 2 ла и т.д. Текст программы:
Код:
char *p, b[2], *t = "маланаламана";
int k = 0, nmax = 0, i = 0;
SetConsoleOutputCP(1251);
b[0] = '\0';
p = malloc(128);
p[0] = '\0';
nmax = strlen(t);
for(i=0; i<nmax; i++) {
  strncpy(b, t, 2);
  if(strstr(p, b)) {
    k++;
  }
  else {
    strncat(p, b, 2);
  }
  t++;
}
Помогите, пожалуйста, никак не пойму, почему в строке p у меня появляются дубли пар букв. Хотелось бы найти решений на С.

* 2symbol.zip (0.48 Кб - загружено 761 раз.)
« Последнее редактирование: 30-01-2009 13:27 от Вад » Записан
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 30-01-2009 13:46 » 

tumanovalex, у тебя b - строго говоря, не строка. Я сделал так:
Код:
char *b[3];
b[2] = '\0';
- после чего strstr стал работать корректно. Разумеется, это правка твоего решения на коленке.
Записан
tumanovalex
Помогающий

ru
Offline Offline

« Ответ #2 : 30-01-2009 16:34 » new

Спасибо большое! Работает. Только я не понял, почему у меня не работало. Вроде бы все правильно (по книгам) , а не работало. Может быть кто-нибудь объяснит, чтобы в будущем не допускать подобные ошибки.
« Последнее редактирование: 30-01-2009 16:42 от tumanovalex » Записан
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 30-01-2009 18:16 » 

tumanovalex, strstr сравнивает две null-terminated строки (на вхождение одной в другую). Собственно, она не знает, где твой массив заканчивается: для неё как первый символ, равный нулю, встретится - так и кончилась строка. Соответственно, если не дополнить твою b завершающим нулём, то нельзя сказать, сколько ещё символов, расположенных в памяти следом за b[1], попадёт в сравнение в качестве строки. Ну и в результате итог сравнения будет некорректный (скорее всего, не найдёт вхождения такой подстроки в p).
Записан
tumanovalex
Помогающий

ru
Offline Offline

« Ответ #4 : 31-01-2009 05:41 » 

Теперь все понятно, спасибо большое.
Записан
tumanovalex
Помогающий

ru
Offline Offline

« Ответ #5 : 31-01-2009 06:08 » 

Как оказалось, не все я понял. Попытался изменить код: char *b = "  "; Вроде бы, аналогично инициализации p, я должен получить 2 символа и завершающий ноль. Однако при использовании strncpy возникает ошибка компиляции. При b[3] = "  " все нормально. Почему возникает ошибка?
Записан
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 31-01-2009 07:15 » 

У меня компилятор C++, там, возможно, немного другое поведение для таких случаев, но у меня компилируется.

Тем не менее, такое решение работать точно не будет. Литералы, включая строковые ("<что-то>") являются безымянными константами и помещаются в константную область памяти. То есть, в примере с char* b = "  " указатель будет указывать на константную память. Поэтому все попытки записать туда что либо будут заканчиваться плохо.

upd. Посмотрел стандарт по C. Там написано, что в случае попытки записи в такой массив поведение не определено (что скорее всего значит "упадёт" Улыбаюсь )
Цитата
The contents of the arrays are modifiable. On the other hand, the declaration
char *p = "abc";
defines p with type ‘‘pointer to char’’ and initializes it to point to an object with type ‘‘array of char’’ with length 4 whose elements are initialized with a character string literal. If an attempt is made to use p to modify the contents of the array, the behavior is undefined.
« Последнее редактирование: 31-01-2009 07:33 от Вад » Записан
tumanovalex
Помогающий

ru
Offline Offline

« Ответ #7 : 31-01-2009 14:43 » 

У меня дает ошибку (Visual C++). Вообще- то как-то это все странно. Указатель p можно модифицировать, а  подобный ему указатель b - нет.
Записан
tumanovalex
Помогающий

ru
Offline Offline

« Ответ #8 : 31-01-2009 16:13 » 

Спасибо большое за помощь! Плохо я еще знаю С!
Записан
Вад
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #9 : 31-01-2009 16:38 » 

tumanovalex, ну вот такая вольность в стандарте - позволяет без ограничений инициализировать обычный указатель адресом read-only памяти. С оговоркой про неопределённое поведение.
Кстати, какая версия Visual C++? У меня на 2003й не компилировался другой фрагмент: "p = malloc(128);" - требовалось явно привести тип к char*. А с символами стандарт C++ выражается поточнее:
Цитата
An ordinary string literal has type “array of n const char” and static storage duration
То есть, это массив константных символов. Сам указатель, инициализированный адресом такого массива, модифицировать можно сколько угодно - нельзя трогать содержимое.

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

ru
Offline Offline

« Ответ #10 : 01-02-2009 08:10 » 

У меня Visual C++ 2005. Вообще-то в других программах у меня тоже компилятор требовал явного преобразования типа в malloc, а а в этой программе почему-то все обошлось. Странно. В MSDN о необходимости явного приведения типа тоже написано. Еще раз спасибо за помощь, по-моему теперь вопрос для меня разъяснился (по крайней мере, мне так кажется в настоящий момент;)
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines