Консультация № 176763
18.02.2010, 14:03
43.65 руб.
0 2 1
Требуется написать программу на языке Си (стандарт ANSI, среда разработки — по усмотрению) Код программы прошу снабдить подробными комментариями.
Задание: Найти в исходной строке все вхождения (но не более девяти) заданной подстроки и заменить их на другую строку с указани¬ем номера очередного вхождения.
Допустимые символы - прописные русские буквы; символ-разделитель '_'.
Результаты вывести на экран. Максимально возможную по условиям задачи длину LenMax строки и саму строку символов ввести с клавиатуры. Если введенная пользователем исходная строка содержит символы, не являющиеся допустимыми, выдать сообщение об ошибке и первый недопустимый символ. Прекратить решение задачи.
[i]Пример:[/i]
Исходная строка: ПОЛИЛИ_ЛИЛИЮ
Какую подстроку заменить: ЛИ
На какую подстроку заменить: СТО
Результат: ПОСТО1СТО2_СТОЗСТО4Ю

По возможности прошу приложить исполняемый файл.

Обсуждение

давно
Профессор
230118
3054
20.02.2010, 21:49
общий
Botsman:
На стандартном С нельзя работать с русскими символами. Тут надо подключать дополнительные библиотеки, которые зависят от среды.
Неизвестный
22.02.2010, 19:30
общий
это ответ
Здравствуйте, Botsman.

Иходный код программы приведен в приложении. Дополнительно исполняемый файл и исходный код в кодировке DOS (CP-866) (18.8 кб)

Я старался писать на "чистом Си", но не могу гарантировать полное соответствие стандарту, поскольку давно привык использовать расширения C++ даже в простых программах.
Если будете компилировать программу сами, то перед компиляцией необходимо сконвертировать исходный код в кодировку DOS (CP-866), поскольку именно эта кодировка используется в консоли. В противном случае, будет проблема с русскими буквами: в программе — таблица Windows 1251, в консоли — CP-866.

Проверено: MSVC 6.0, консоль Windows

Успехов!

Приложение:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char szAllowedChars[] = "_АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";

/* ввод строки с клавиатуры с проверкой на недопустимые символы */
int check_string( char* str )
{
size_t i;
/*
Для надежности, лучше использовать fgets( str, iMaxLen, stdin ),
поскольку она позволяет задать размер буфера для вводимой строки
Для простоты, здесь используется функция gets(), но в ней нет проверки на
переполнение буфера. gets() заменяет '\n' на NULL, а fgets() - нет.
*/
gets( str );
/* проверяем строку на отсутствие недопустимых символов */
if( (i = strspn( str, szAllowedChars )) != strlen( str ) ) {
printf( "Illegal character in string '%s' at position %d (1-based): %c\n",
str, i+1, str[i] );
return -1;
}
return 0;
}


int main()
{
int iMaxLen, n;
char *pszSource, *pszSearch, *pszReplace, *p;
int iCount, iLenSearch, iLenRepl;
char tmp[32];

printf( "Enter maximum allowed string length: " );
/* лучше использовать пару gets/sscanf, чем просто scanf.
см. также замечание о gets/fgets в функции check_string()
*/
gets( tmp );
if( sscanf( tmp, "%d", &iMaxLen ) != 1 ) {
printf( "Wrong input! Integer value is expected.\n" );
return 1;
}

pszSource = 0;
pszSearch = 0;
pszReplace = 0;

/* while(1){} в сочетании с break - простой способ избежать goto или
повторяющегося кода, когда нужно выполнять проверку многих условий,
а при ошибке выполнять очистку и выход.
*/

while( 1 ) {
if( (pszSource = (char*)malloc( ++iMaxLen )) == NULL ||
(pszSearch = (char*)malloc( iMaxLen )) == NULL ||
(pszReplace = (char*)malloc( iMaxLen )) == NULL )
{
printf( "Not enough memory!" );
break;
}

printf( "Enter source string: " );
if( check_string( pszSource ) != 0 )
break;

printf( "Search for substring: " );
if( check_string( pszSearch ) != 0 )
break;

printf( "Replace with: " );
if( check_string( pszReplace ) != 0 )
break;

/* подготавливаем нужные переменные */
iCount = 0; /* номер найденной подстроки */
iLenSearch = strlen( pszSearch ); /* длина искомой подстроки */
iLenRepl = strlen( pszReplace ) + 1; /* длина замены, +1 для номера вхождения */

/* если строка замены длиннее искомой подстроки, то возможно переполнение */
if( iLenRepl > iLenSearch ) {
n = ( iLenRepl - iLenSearch )*9 + strlen( pszSource );
if( n >= iMaxLen ) {
if( !(p = (char*)realloc( pszSource, n+1 )) ) {
printf( "Not enough memory!" );
break;
}
pszSource = p;
}
/* iMaxLen далее не используется */
}

p = pszSource; /* указатель на начало области поиска */
/* ищем очередное вхождение подстроки в строку */
while( p && iCount < 9 && (p = strstr( p, pszSearch )) != NULL ) {
++iCount; /* номер очередного вхождения искомой подстроки */

if( iLenSearch != iLenRepl )
/* сдвигаем или раздвигаем строку
используем memmove(), поскольку исходная и целевая области могут перекрываться
(и, обычно, перекрываются в задачах такого типа)
*/
memmove( p+iLenRepl, p+iLenSearch, strlen( p+iLenSearch )+1 );

/* вставляем замену на освобожденное место
используем memcpy(), поскольку здесь исходная и целевая области не перекрываются,
а memcpy() быстрее, чем memmove() - нет проверки на перекрытие областей
*/
memcpy( p, pszReplace, iLenRepl-1 );

/* вставляем номер замены, прибавляем '0' для преобразование числа в символ */
p[iLenRepl-1] = iCount + '0';

/* продвигаем указатель для дальнейшего поиска */
p += iLenRepl;
}
printf( "Result: %s\n", pszSource );
break;
}
/* освобождаем память, выделенную под строки.
передача нулевого указателя в функцию free() не является ошибкой,
поэтому проверку перед вызовом не делаем
*/
free( pszSource );
free( pszSearch );
free( pszReplace );
return 0;
}
5
Спасибо!
Форма ответа