2014 dxdy logo

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

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




На страницу 1, 2  След.
 
 Язык Си. Замены в строке.
Сообщение07.12.2013, 13:00 
Здравствуйте. Задача: Даны строки 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 
Что, по-вашему, делает strcpy?

 
 
 
 Re: Язык Си. Замены в строке.
Сообщение07.12.2013, 14:22 
arseniiv в сообщении #797272 писал(а):
Что, по-вашему, делает strcpy?


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

 
 
 
 Re: Язык Си. Замены в строке.
Сообщение07.12.2013, 14:45 
«Копирует» — это слишком общее описание. Внимательно разберитесь с ней — и всё получится.

 
 
 
 Re: Язык Си. Замены в строке.
Сообщение07.12.2013, 16:23 
arseniiv в сообщении #797295 писал(а):
«Копирует» — это слишком общее описание. Внимательно разберитесь с ней — и всё получится.


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

 
 
 
 Re: Язык Си. Замены в строке.
Сообщение07.12.2013, 16:41 
Что означает «вставляет»? Если вы имели в виду со сдвигом остальных символов вправо, то нет. Символы по конечному адресу переписываются новыми.

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

 
 
 
 Re: Язык Си. Замены в строке.
Сообщение07.12.2013, 16:57 
arseniiv в сообщении #797360 писал(а):
Что означает «вставляет»? Если вы имели в виду со сдвигом остальных символов вправо, то нет. Символы по конечному адресу переписываются новыми.

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


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

 
 
 
 Re: Язык Си. Замены в строке.
Сообщение07.12.2013, 17:09 
Можно и без переменной обойтись, если использовать memmove. Это уж как хотите.

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

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

 
 
 
 Re: Язык Си. Замены в строке.
Сообщение08.12.2013, 11:57 
Сделал через 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 
Разумеется, не будет работать. Вы же не поменяли строку
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 
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 
Нарисуйте же небольшие куски памяти (в виде клеточек как в кроссворде, например). Выберите конкретные s, s1, s2, лучше разных размеров. Нарисуйте начальную s и ту, которая вам нужна в результате (назовём её s'). Покомбинируйте перемещения кусков. Не обязательно идти от s к s', можно задом наперёд.

 
 
 
 Re: Язык Си. Замены в строке.
Сообщение08.12.2013, 22:28 
Может как-то так?

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

 
 
 
 Re: Язык Си. Замены в строке.
Сообщение08.12.2013, 23:05 
Ура!

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

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

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

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

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

 
 
 
 Re: Язык Си. Замены в строке.
Сообщение27.12.2013, 16:19 
А можно спросить, у тебя когда-нибудь было, чтобы отработал этот код:
printf ("\n Строка s1 больше строки s");
???
Потому как, я вижу, что в данной ситуации он никогда не сработает.

 
 
 [ Сообщений: 16 ]  На страницу 1, 2  След.


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group