//==========================================================
char* replace ( char* lpString, char* lpMatch, char* lpReplace )
{
char buffer[128];
int match_count=0;
int str_len = strlen(lpString);
int match_len = strlen(lpMatch);
int repl_len = strlen(lpReplace);
int required;
char* pNext;
char* pDest;
pNext = lpString;
/* считаем кол-во вхождений подстроки lpMatch в lpString */
while ( (pNext = strstr(pNext,lpMatch)) != NULL )
{
match_count++; /* увеличиваем счётчик */
pNext++; /* смещаемся на найденую позицию */
}
/* если нет вхождений - возвращаем ноль */
if ( ! match_count ) return 0;
/* определение длины выходной строки */
required = str_len - match_len*match_count + repl_len*match_count;
/* выделение места для вых. строки и её обнуление */
char* output = new char[required];
output[0]=0;
pNext = lpString;
/* пока в строке будут встречаться lpMatch, будем заменять
на lpReplace, сдвигаясь после каждой замены по строке */
do
{
pDest = strstr(pNext,lpMatch);
/* если все замены сделаны - выходим */
if ( ! pDest ) break;
/* копируем в вых. строку фрагмент до lpMatch */
strncat(output,pNext,(pDest-pNext));
/* вместо lpMatch цепляем lpReplace */
strcat(output,lpReplace);
pNext = pDest+match_len;
}
while (1);
/* дописываем в вых. строку конец строки */
strcat(output,pNext);
/* возвращаем указатель на получившуюся строку */
return output;
}
Количество переменных можно подсократить, но чтобы понятней было, оставил как есть.
Вызывать примерно так:
//==========================================================
char* replace ( char* lpString, char* lpMatch, char* lpReplace )
{
char buffer[128];
int match_count=0;
int str_len = strlen(lpString);
int match_len = strlen(lpMatch);
int repl_len = strlen(lpReplace);
int required;
char* pNext;
char* pDest;
pNext = lpString;
/* считаем кол-во вхождений подстроки lpMatch в lpString */
while ( (pNext = strstr(pNext,lpMatch)) != NULL )
{
match_count++; /* увеличиваем счётчик */
pNext++; /* смещаемся на найденую позицию */
}
/* если нет вхождений - возвращаем ноль */
if ( ! match_count ) return 0;
/* определение длины выходной строки */
required = str_len - match_len*match_count + repl_len*match_count;
/* выделение места для вых. строки и её обнуление */
char* output = new char[required];
output[0]=0;
pNext = lpString;
/* пока в строке будут встречаться lpMatch, будем заменять
на lpReplace, сдвигаясь после каждой замены по строке */
do
{
pDest = strstr(pNext,lpMatch);
/* если все замены сделаны - выходим */
if ( ! pDest ) break;
/* копируем в вых. строку фрагмент до lpMatch */
strncat(output,pNext,(pDest-pNext));
/* вместо lpMatch цепляем lpReplace */
strcat(output,lpReplace);
pNext = pDest+match_len;
}
while (1);
/* дописываем в вых. строку конец строки */
strcat(output,pNext);
/* возвращаем указатель на получившуюся строку */
return output;
Ну оставлять без освобождения нехорошо, особенно если вызывать большое кол-во раз. Память надо освобождать.
Не знаю, почему Debug Error. У меня консольная vc++ 2003 и ничего не ругается. Может ты debug версию компилишь, и стоит попробовать release?
А вообще можно и по другому сделать:
вместо char* output = new char[required]; поставить
char* output = (char*) SysAllocStringByteLen(NULL,required);
А вместо delete[] new_string
SysFreeString( (BSTR) new_string );
Возможно надо будет указать линкеру либу, где эти ф-ции хранятся:
Кстати, созрел ещё один вопрос:
Если выделить например 10 байт, и начиная с адреса полученного от new, записать например 11 байт, то с чего это вдруг delete будет ориентироваться на число байт, которые я записал в этот кусок памяти?
При освобождении освобождается столько, сколько выделено, а не сколько записано. Или не так?
щас другая траба с вводом своей строки, вообщем вот всё что получилось:
/*
Задание: Удалить в тексте лишние пробелы
Реализация функции Replace !
*/
#include <windows.h>
#include <iostream.h>
//==========================================================
char* replace ( char* lpString, char* lpMatch, char* lpReplace )
{
// char buffer[128];
int match_count=0;
int str_len = strlen(lpString);
int match_len = strlen(lpMatch);
int repl_len = strlen(lpReplace);
int required;
char* pNext;
char* pDest;
pNext = lpString;
/* считаем кол-во вхождений подстроки lpMatch в lpString */
while ( (pNext = strstr(pNext,lpMatch)) != NULL )
{
match_count++; /* увеличиваем счётчик */
pNext++; /* смещаемся на найденую позицию */
}
// если нет вхождений - возвращаем ноль
if ( ! match_count ) return 0;
// определение длины выходной строки
required = str_len - match_len*match_count + repl_len*match_count;
// выделение места для вых. строки и её обнуление
char* output = new char[required+1];
output[0]=0;
pNext = lpString;
// пока в строке будут встречаться lpMatch, будем заменять
// на lpReplace, сдвигаясь после каждой замены по строке
do
{
pDest = strstr(pNext,lpMatch);
// если все замены сделаны - выходим
if ( ! pDest ) break;
// копируем в вых. строку фрагмент до lpMatch
strncat(output,pNext,(pDest-pNext));
// вместо lpMatch цепляем lpReplace
strcat(output,lpReplace);
pNext = pDest+match_len;
}
while (1);
// дописываем в вых. строку конец строки
strcat(output,pNext);
// возвращаем указатель на получившуюся строку
return output;
}
void main(){
int str_len_posle; //счётчик длинны строки до изменений
int str_len_do; //и после изменений
char* new_string="sadasd sadasd f"; //наша строка
do //цкикл пока до и после не будут равны...
{
str_len_do = strlen(new_string) - 1; //запоминаем
new_string = replace (new_string, " ", " " //убираем лишние пробелы
str_len_posle = strlen(new_string); //запоминаем
}
//Когда кол-во символов ДО изминений равно кол-ву символу ПОСЛЕ изминений
//ЗНАЧИТ изминения сделаны напрасно Но за то мы знаем когда выйти из цикла )
//Всмысле изменений небыло, т.к. все нужные изменения уже сделаны
while ( str_len_do != str_len_posle); //проверка условия выхода из цикла
//Если вышли - выводим нашу строку
cout<<new_string;
cin.get();
delete new_string;
}
char* new_string="sadasd sadasd f"; //наша строка
Надо ввести свою строку, проблемы:
1) Это ж указатель, а как записать то что ввиду с калвы через указатель я не пойму
2) Знаю что выделять память нужно, но опять таки... если введённая строка будет больше чем я памяти выделю? Я ж не знаю сколько заранее строка будет символов...
Хм, видимо ты невнимательно читал ф-цию replace Там специально возвращается ноль, если нет вхождений подстроки в строку. И не надо считать str_len_do, str_len_posle. И напрасных действий не будет.
На этом можно сэкономить все твои вызовы strlen и сделать цикл очень просто
Кроме того, ты выделяешь в цикле новые строки, не удаляя старые. Не хорошо.
И в чём проблема со вводом строки с клавиатуры? Засовывай в буфер заведомо достаточной длины:
char String[128]; //буфер для строки "sadasd sadasd f"
char Match[128]; //буфер для заменяемой строки (два пробела)
char Replace[128]; //буфер для заменяющей строки (один пробел)
char* new_string;
char* temp;
Если хочется иметь память под вводимую с клавиатуры строку точной длины, то можно конечно поставить обработчик исключений, и по исключению ACCESS_VIOLATION выделять новый кусок памяти и зачитывать уже в него. Но это геморрой, который ты сейчас вряд ли осилишь.
Возможно в с++ есть какие-то решения этой проблемы - не знаю. Пользоваться решениями из stdlib как-то не очень хочется.
Обрати внимание, что в ф-ции replace я таки заменил new char[required+1]; на
(char*) SysAllocStringByteLen(NULL,required);
Это надёжней и предсказуемей. И приведенный код замены пробелов не будет работать с new.
Можно вообще написать две простенькие ф-ции по выделению,обнулению первого байта и очистке памяти, и испольховать их вместо new и delete
кста, меня за read_console сегодня препод по программированию выругал, сказал что это мало того что велосипед самодельный ещё и извращение может лучше использовать вмесно неё cin.getline ... ??? Но всёравно, спасибо!
ну говорит мол лучше использовать готовые "приспособления" от самого C++ чем изобретать самодельные типа read_console... Я конечно гривой покивал спорить не с тобой не с ним немогу от если б по VB начал бы меня доставать, ото я б в бой ринулся а с С++ пока немогу
Ещё вопрос... точнее у меня препод спросил а я ответить не сомг, расскаж плиз...
P.S. (возращаемся к студентам)
array = new STUDENT[STUDENT_COUNT];
memset ( array, 0, STUDENT_COUNT*sizeof(STUDENT) );
Зачем там memset? Когда закоментировал тоже работает...
Ведь array = new STUDENT[STUDENT_COUNT]; и так создаёт массив и выделят память под него...
//==========================================================
char* replace ( char* lpString, char* lpMatch, char* lpReplace )
{
int match_count=0;
int str_len = strlen(lpString);
int match_len = strlen(lpMatch);
int repl_len = strlen(lpReplace);
int required;
char* pNext;
char* pDest;
pNext = lpString;
/* считаем кол-во вхождений подстроки lpMatch в lpString */
while ( (pNext = strstr(pNext,lpMatch)) != NULL )
{
match_count++; /* увеличиваем счётчик */
pNext++; /* смещаемся на найденую позицию */
}
// если нет вхождений - возвращаем ноль
if ( ! match_count ) return 0;
// определение длины выходной строки
required = str_len - match_len*match_count + repl_len*match_count;
// выделение места для вых. строки и её обнуление
char* output = new char[required+1];
output[0]=0;
pNext = lpString;
// пока в строке будут встречаться lpMatch, будем заменять
// на lpReplace, сдвигаясь после каждой замены по строке
do
{
pDest = strstr(pNext,lpMatch);
// если все замены сделаны - выходим
if ( ! pDest ) break;
// копируем в вых. строку фрагмент до lpMatch
strncat(output,pNext,(pDest-pNext));
// вместо lpMatch цепляем lpReplace
strcat(output,lpReplace);
pNext = pDest+match_len;
}
while (1);
// дописываем в вых. строку конец строки
strcat(output,pNext);
// возвращаем указатель на получившуюся строку
return output;
}
Хе-хе, а я вот всё жду, когда же ты на вылет проги по replace нарвешься
Долго ждал Короче, есть такая трабла: если многократно вызывать replace, то в какой-то момент прога вылетает с ошибкой, что инструкция по адресу 0x77f767cd обратилась к памяти 0х20202020 -память не может быть written. Хотя сама ф-ция нормально формирует строку. Как я понял, это кто-то из libc-овых strstr, strncat или strcpy что-то некорректно делает. Копаться в кишках ntdll, где происходит ошибка неохота, поэтому просто переделал replace, чтобы ни одной ф-ции из неё не вызывать. Получилось достаточно ничего. Многократный вызов никаких ошибок не вызывает.
//==========================================================
char* replace ( char* lpString, char* lpMatch, char* lpReplace )
{
int match_count=0;
int str_len=0;
int match_len=0;
int repl_len=0;
int required;
char* pOut;
char* pSrc;
char* output;
int i=0;
while ( lpString[str_len] ) str_len++; //длина lpString
if ( !str_len ) return 0;
while ( lpMatch[match_len] ) match_len++; //длина lpMatch
if ( !match_len ) return 0;
while ( lpReplace[repl_len] ) repl_len++; //длина lpReplace
pSrc = lpString;
while ( pSrc[0] ) //подсчёт кол-ва вхождений lpMatch в lpString
{
i=0;
while ( pSrc && (pSrc==lpMatch) ) i++;
if ( i == match_len )
{
match_count++;
pSrc += i;
}
else pSrc++;
}
if ( ! match_count ) return 0;
required = str_len - ((match_len- repl_len)*match_count); //длина новой строки
if ( 0 == (output = new char[required+1]) ) return 0; //и получение памяти под неё
pOut = output;
pSrc = lpString;
while ( pSrc[0] ) //поиск фрагментов и замена на новые
{
if ( pSrc[0] != lpMatch[0] ) //копируем символы не подлежащие замене, в вых.строку
{
pOut[0] = pSrc[0];
pOut++; pSrc++;
}
else //если встретился символ, с которого начинается lpMatch
{
i = 0;
while ( pSrc && (pSrc==lpMatch) ) i++;
if ( i == match_len ) //и lpMatch найдена целиком
{
for (i=0; i<repl_len; i++) //вместо неё в вых. строку копируем lpReplace
pOut = lpReplace;
pOut += i; pSrc += match_len;
}
else pSrc++; //если совпал только первый символ lpMatch, продолжаем
} //копировать старую строку в вых. строку
}
pOut[0]=0; //завершаем вых. строку нулём
return output;
}
выделение памяти сделано через new, освобождение значит должно быть через delete. Но можно и использовать SysAllocStringByteLen/SysFreeString. Разницы нет.
Пробуй
А что касается memset ( array, 0, STUDENT_COUNT*sizeof(STUDENT) ); то это после выделения памяти под массив структур, производится очистка этой памяти - затирание нулями. На всякий случай. После выделения там всякий мусор, вот и обнуляем эту память. Вообще, эти ф-ции описаны в msdn, можно прочитать, что они делают.