2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу 1, 2  След.
 
 Язык Си. Замены в строке.
Сообщение07.12.2013, 13:00 


23/10/13
46
Здравствуйте. Задача: Даны строки S, S1 и S2. Заменить в строке S последнее вхождение строки S1 на строку S2.
У меня происходит замена, но всё, что есть строке, до этой подстроки у меня удаляется. Объясните пожалуйста, как это исправить?

Код:
#include <string.h>
#include <conio.h>
#include <iostream>

void main()
{
   setlocale(LC_CTYPE,"Russian");
   char s1[256], s2[256], s[256];
   char *buf;
   unsigned int i;

   printf("Введите строку s: ");
   gets(s);
   printf("Введите строку s1: ");
   gets(s1);
   printf("Введите строку s2: ");
   gets(s2);
   i=strlen(s)-strlen(s1)+1; //сравнение строк
   if (i>0)
   {
   strrev(s);
   strrev(s1);
   strrev(s2);
   buf = strstr(s, s1);
   if(buf) //условие наличия подстроки
   {
      strcpy(buf,buf+strlen(s1));//удаление последней подстроки
     strcpy(buf,s2);
     strrev(s);
   }
   else
     strrev(s);
   printf("%s\n", s); //вывод результата
   }
   else
      printf ("\n Строка s1 больше строки s");
   _getch();
}

 Профиль  
                  
 
 Re: Язык Си. Замены в строке.
Сообщение07.12.2013, 13:40 
Заслуженный участник


27/04/09
28128
Что, по-вашему, делает strcpy?

 Профиль  
                  
 
 Re: Язык Си. Замены в строке.
Сообщение07.12.2013, 14:22 


23/10/13
46
arseniiv в сообщении #797272 писал(а):
Что, по-вашему, делает strcpy?


Копирует строку s2 в buf

 Профиль  
                  
 
 Re: Язык Си. Замены в строке.
Сообщение07.12.2013, 14:45 
Заслуженный участник


27/04/09
28128
«Копирует» — это слишком общее описание. Внимательно разберитесь с ней — и всё получится.

 Профиль  
                  
 
 Re: Язык Си. Замены в строке.
Сообщение07.12.2013, 16:23 


23/10/13
46
arseniiv в сообщении #797295 писал(а):
«Копирует» — это слишком общее описание. Внимательно разберитесь с ней — и всё получится.


Ну, получается берёт первый символ строки s2 и вставляет его после buf, затем второй и так далее, правильно? Или же идёт замена?

 Профиль  
                  
 
 Re: Язык Си. Замены в строке.
Сообщение07.12.2013, 16:41 
Заслуженный участник


27/04/09
28128
Что означает «вставляет»? Если вы имели в виду со сдвигом остальных символов вправо, то нет. Символы по конечному адресу переписываются новыми.

При этом, внимание, конечный '\0' тоже копируется! (Подумайте, к чему это приведёт у вас.) Чтобы его не копировать, можно использовать strncpy.

 Профиль  
                  
 
 Re: Язык Си. Замены в строке.
Сообщение07.12.2013, 16:57 


23/10/13
46
arseniiv в сообщении #797360 писал(а):
Что означает «вставляет»? Если вы имели в виду со сдвигом остальных символов вправо, то нет. Символы по конечному адресу переписываются новыми.

При этом, внимание, конечный '\0' тоже копируется! (Подумайте, к чему это приведёт у вас.) Чтобы его не копировать, можно использовать strncpy.


Тогда как же сделать, чтобы оставалась левая часть, вставлялась s2 и после неё шла правая часть? Как-то скопировать правую часть в переменную а затем добавить её к тому, что мы получили после копирования s2 в buf?

 Профиль  
                  
 
 Re: Язык Си. Замены в строке.
Сообщение07.12.2013, 17:09 
Заслуженный участник


27/04/09
28128
Можно и без переменной обойтись, если использовать memmove. Это уж как хотите.

-- Сб дек 07, 2013 20:11:37 --

Кстати, форум ссылки не подчёркивает, а цвет кода переопределяет цвет ссылки, так что вы могли не заметить, что выше strncpy и memmove — это ссылки на справочник (один из возможных, просто первый попался). Почитайте там подробности, без которых обходиться никак нельзя.

 Профиль  
                  
 
 Re: Язык Си. Замены в строке.
Сообщение08.12.2013, 11:57 


23/10/13
46
Сделал через memmove, но если подстрок несколько, то удаляется несколько букв до вхождения, не могу понять почему.

Код:
#include <string.h>
#include <conio.h>
#include <iostream>

void main()
{
   setlocale(LC_CTYPE,"Russian");
   char s1[256], s2[256], s[256];
   char *buf;
   unsigned int i;

   printf("Введите строку s: ");
   gets(s);
   printf("Введите строку s1: ");
   gets(s1);
   printf("Введите строку s2: ");
   gets(s2);
   i=strlen(s)-strlen(s1)+1; //сравнение строк
   if (i>0)
   {
   strrev(s);
   strrev(s1);
   strrev(s2);
   buf = strstr(s, s1);
   if(buf) //условие наличия подстроки
   {
      strcpy(buf,buf+strlen(s1));//удаление последней подстроки
     memmove(buf,s2,strlen(s2));   
     strrev(s);
   }
   else
     strrev(s);
   printf("%s\n", s); //вывод результата
   }
   else
      printf ("\n Строка s1 больше строки s");
   _getch();
}

 Профиль  
                  
 
 Re: Язык Си. Замены в строке.
Сообщение08.12.2013, 13:44 
Заслуженный участник


27/04/09
28128
Разумеется, не будет работать. Вы же не поменяли строку
strcpy(buf,buf+strlen(s1));//удаление последней подстроки
(и комментарий потом тоже поменяйте).

Пускай перед этой строкой s1 = "ABC\0", s2 = "DEFGHI\0", а buf указывает на кусок "ABCJKLMN\0". Тогда эта ваша строка изменит этот кусок на "JKLMN\0MN\0" (а может сделать и не это, а чёрт-те что, т. к. области памяти перекрываются, и именно для таких случаев нужна была бы здесь memmove). Следующий оператор сделает с ним "DEFGHIMN\0" (а если бы s2 = "DE\0", получилось бы "DELMN\0MN\0").

Кусок по адресу buf+strlen(s1) надо сдвигать не в одно и то же место каждый раз, а ровно туда, где он нужен. Возьмите бумажку и проверьте, куда.

 Профиль  
                  
 
 Re: Язык Си. Замены в строке.
Сообщение08.12.2013, 15:05 


23/10/13
46
arseniiv в сообщении #797681 писал(а):
Разумеется, не будет работать. Вы же не поменяли строку
strcpy(buf,buf+strlen(s1));//удаление последней подстроки
(и комментарий потом тоже поменяйте).

Пускай перед этой строкой s1 = "ABC\0", s2 = "DEFGHI\0", а buf указывает на кусок "ABCJKLMN\0". Тогда эта ваша строка изменит этот кусок на "JKLMN\0MN\0" (а может сделать и не это, а чёрт-те что, т. к. области памяти перекрываются, и именно для таких случаев нужна была бы здесь memmove). Следующий оператор сделает с ним "DEFGHIMN\0" (а если бы s2 = "DE\0", получилось бы "DELMN\0MN\0").

Кусок по адресу buf+strlen(s1) надо сдвигать не в одно и то же место каждый раз, а ровно туда, где он нужен. Возьмите бумажку и проверьте, куда.


Я понимаю, о чём Вы говорите, но у меня всё равно ничего не получается. Не могу понять как изменить эту строчку так, чтобы сдвигалось туда, куда нужно.

 Профиль  
                  
 
 Re: Язык Си. Замены в строке.
Сообщение08.12.2013, 15:38 
Заслуженный участник


27/04/09
28128
Нарисуйте же небольшие куски памяти (в виде клеточек как в кроссворде, например). Выберите конкретные s, s1, s2, лучше разных размеров. Нарисуйте начальную s и ту, которая вам нужна в результате (назовём её s'). Покомбинируйте перемещения кусков. Не обязательно идти от s к s', можно задом наперёд.

 Профиль  
                  
 
 Re: Язык Си. Замены в строке.
Сообщение08.12.2013, 22:28 


23/10/13
46
Может как-то так?

Код:
memmove(result,s,buf-s);
          strcat(result,s2);
          strcat(result,buf+strlen(s1));
      strrev(result);

 Профиль  
                  
 
 Re: Язык Си. Замены в строке.
Сообщение08.12.2013, 23:05 
Заслуженный участник


27/04/09
28128
Ура!

Хотя можно обойтись работой на месте, где находится s. Если, конечно, его хватает. Тогда достаточно работы только с той её частью, на которую указывает buf, как и раньше.

-- Пн дек 09, 2013 02:06:25 --

Точнее, не совсем ура.

Пока работать всё же не будет: memmove не добавляет '\0' после скопированного куска памяти, т. к. это «общая» функция. С ней придётся дописывать ноль вручную. Если его не дописать, strcat будет приписывать не туда. Повезёт только если result был, например, до того забит нулями.

Использование memmove здесь вообще необязательно. Я же упоминал strncpy. Правда, там тоже надо вручную приписывать '\0', если он не попадает в число символов, которые надо скопировать.

 Профиль  
                  
 
 Re: Язык Си. Замены в строке.
Сообщение27.12.2013, 16:19 


22/01/13
1
А можно спросить, у тебя когда-нибудь было, чтобы отработал этот код:
printf ("\n Строка s1 больше строки s");
???
Потому как, я вижу, что в данной ситуации он никогда не сработает.

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 16 ]  На страницу 1, 2  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group