Вопрос: VC++ Help Please ! (задачка) | Добавлено: 08.11.05 23:06 |
Автор вопроса: ![]() |
Ответы | Всего ответов: 67 |
Номер ответа: 46 Автор ответа: ![]() ![]() Вопросов: 0 Ответов: 1066 |
Профиль | Цитата | #46 | Добавлено: 14.11.05 09:59 |
//==========================================================
Количество переменных можно подсократить, но чтобы понятней было, оставил как есть.
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* new_string = replace ("My cool string", "My", "Your"
![]() printf ("%s\n", new_string); delete[] new_string; cin >>buffer; Возвращаемую строку, когда она не нужна больше, нужно освободить при помощи delete[] |
Номер ответа: 47 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Разработчик Offline Client Вопросов: 236 Ответов: 8362 |
Профиль | Цитата | #47 | Добавлено: 14.11.05 10:29 |
Спасибо!
У меня ящиков пива нехватит чтобы тебя отблагодарить! |
Номер ответа: 48 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Разработчик Offline Client Вопросов: 236 Ответов: 8362 |
Профиль | Цитата | #48 | Добавлено: 14.11.05 10:49 |
хм...
#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]; 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(){ char* new_string = replace ("My cool string", "My", "Your" ![]() //printf ("%s\n", new_string); cout<<new_string; delete[] new_string; } страшным страшным матом на меня ругается ![]() Debug Error! DAMAGE after normal block (#42) at 0x00431CE0 |
Номер ответа: 49 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Разработчик Offline Client Вопросов: 236 Ответов: 8362 |
Профиль | Цитата | #49 | Добавлено: 14.11.05 23:35 |
кста, без
delete[] new_string;
работает... пока так и оставил... |
Номер ответа: 50 Автор ответа: ![]() ![]() Вопросов: 0 Ответов: 1066 |
Профиль | Цитата | #50 | Добавлено: 15.11.05 05:40 |
Ну оставлять без освобождения нехорошо, особенно если вызывать большое кол-во раз. Память надо освобождать.
Не знаю, почему Debug Error. У меня консольная vc++ 2003 и ничего не ругается. Может ты debug версию компилишь, и стоит попробовать release? А вообще можно и по другому сделать: вместо char* output = new char[required]; поставить char* output = (char*) SysAllocStringByteLen(NULL,required); А вместо delete[] new_string SysFreeString( (BSTR) new_string ); Возможно надо будет указать линкеру либу, где эти ф-ции хранятся: #pragma comment(lib, "oleaut32.lib"
![]() #include <windows.h> #include <iostream> |
Номер ответа: 51 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Лидер форума ICQ: 216865379 Вопросов: 106 Ответов: 9979 |
Web-сайт: Профиль | Цитата | #51 | Добавлено: 15.11.05 05:44 |
Лажа здесь:
char* output = new char[required];
Надо выделять место еще и под завершающий \0: char* output = new char[required+1];
Кстати, char buffer[128]; нафиг не нужен |
Номер ответа: 52 Автор ответа: ![]() ![]() Вопросов: 0 Ответов: 1066 |
Профиль | Цитата | #52 | Добавлено: 15.11.05 06:12 |
Тогда два вопроса:
1. Почему strcat может успешно записать \0 в невыделенное место? 2. Почему у меня не ругается? P.S. О необходимости убрать переменные я уже намекал HACKER'у, но он видимо ленивый ![]() |
Номер ответа: 53 Автор ответа: ![]() ![]() Вопросов: 0 Ответов: 1066 |
Профиль | Цитата | #53 | Добавлено: 15.11.05 06:33 |
Кстати, созрел ещё один вопрос:
Если выделить например 10 байт, и начиная с адреса полученного от new, записать например 11 байт, то с чего это вдруг delete будет ориентироваться на число байт, которые я записал в этот кусок памяти? При освобождении освобождается столько, сколько выделено, а не сколько записано. Или не так? |
Номер ответа: 54 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Разработчик Offline Client Вопросов: 236 Ответов: 8362 |
Профиль | Цитата | #54 | Добавлено: 15.11.05 11:48 |
Надо выделять место еще и под завершающий \0:
char* output = new char[required+1]; пасибо, помогло... buffer убрал, тоже всё ок щас другая траба с вводом своей строки, вообщем вот всё что получилось: /*
Задание: Удалить в тексте лишние пробелы Реализация функции 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); //проверка условия выхода из цикла new_string = replace (new_string, " ", " " ![]() ![]() //Если вышли - выводим нашу строку cout<<new_string; cin.get(); delete new_string; } char* new_string="sadasd sadasd f"; //наша строка
Надо ввести свою строку, проблемы: 1) Это ж указатель, а как записать то что ввиду с калвы через указатель я не пойму ![]() 2) Знаю что выделять память нужно, но опять таки... если введённая строка будет больше чем я памяти выделю? Я ж не знаю сколько заранее строка будет символов... |
Номер ответа: 55 Автор ответа: ![]() ![]() Вопросов: 0 Ответов: 1066 |
Профиль | Цитата | #55 | Добавлено: 15.11.05 14:02 |
Хм, видимо ты невнимательно читал ф-цию replace ![]() На этом можно сэкономить все твои вызовы strlen и сделать цикл очень просто Кроме того, ты выделяешь в цикле новые строки, не удаляя старые. Не хорошо. И в чём проблема со вводом строки с клавиатуры? Засовывай в буфер заведомо достаточной длины: char String[128]; //буфер для строки "sadasd sadasd f"
char Match[128]; //буфер для заменяемой строки (два пробела) char Replace[128]; //буфер для заменяющей строки (один пробел) char* new_string; char* temp; printf ( "Input string: " ); read_console( String, sizeof(String) ); //получаем строку printf ( "Input match string: " ); read_console( Match, sizeof(Match) ); //получаем два пробела printf ( "Input replace string: " ); read_console( Replace, sizeof(Replace) ); //получаем замену /* временная строка */ temp = (char*) SysAllocStringByteLen( NULL, strlen(String)+1 ); strcpy (temp, String); while ( (new_string = replace (temp, Match, Replace)) != 0 ) { strcpy ( temp, new_string ); /*удаляем new_string*/ SysFreeString( (BSTR) new_string ); } /* на выходе имеем строку "sadasd sadasd f"*/ printf ("%s\n", temp); /*освобождаем временную строку*/ SysFreeString( (BSTR) temp ); Если хочется иметь память под вводимую с клавиатуры строку точной длины, то можно конечно поставить обработчик исключений, и по исключению ACCESS_VIOLATION выделять новый кусок памяти и зачитывать уже в него. Но это геморрой, который ты сейчас вряд ли осилишь. Возможно в с++ есть какие-то решения этой проблемы - не знаю. Пользоваться решениями из stdlib как-то не очень хочется. Обрати внимание, что в ф-ции replace я таки заменил new char[required+1]; на (char*) SysAllocStringByteLen(NULL,required); Это надёжней и предсказуемей. И приведенный код замены пробелов не будет работать с new. Можно вообще написать две простенькие ф-ции по выделению,обнулению первого байта и очистке памяти, и испольховать их вместо new и delete |
Номер ответа: 56 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Разработчик Offline Client Вопросов: 236 Ответов: 8362 |
Профиль | Цитата | #56 | Добавлено: 15.11.05 20:44 |
кста, меня за read_console сегодня препод по программированию выругал, сказал что это мало того что велосипед самодельный ещё и извращение ![]() |
Номер ответа: 57 Автор ответа: ![]() ![]() Вопросов: 0 Ответов: 1066 |
Профиль | Цитата | #57 | Добавлено: 15.11.05 21:09 |
В баню препода, вместе с его cin.getline !!!
API forever!!! |
Номер ответа: 58 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Разработчик Offline Client Вопросов: 236 Ответов: 8362 |
Профиль | Цитата | #58 | Добавлено: 16.11.05 13:40 |
ну говорит мол лучше использовать готовые "приспособления" от самого C++ чем изобретать самодельные типа read_console... ![]() ![]() ![]() ![]() ![]() Ещё вопрос... точнее у меня препод спросил а я ответить не сомг, расскаж плиз... P.S. (возращаемся к студентам) array = new STUDENT[STUDENT_COUNT];
memset ( array, 0, STUDENT_COUNT*sizeof(STUDENT) ); Зачем там memset? Когда закоментировал тоже работает... Ведь array = new STUDENT[STUDENT_COUNT]; и так создаёт массив и выделят память под него... |
Номер ответа: 59 Автор ответа: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Разработчик Offline Client Вопросов: 236 Ответов: 8362 |
Профиль | Цитата | #59 | Добавлено: 16.11.05 14:03 |
![]() /*
Задание: Удалить в тексте лишние пробелы Реализация функции Replace ! */ #include <windows.h> #include <iostream.h> //========================================================== 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; } void main(){ char String[128]; //буфер для строки "sadasd sadasd f" char Match[128]= " "; //буфер для заменяемой строки (два пробела) char Replace[128]= " "; //буфер для заменяющей строки (один пробел) char* new_string; char* temp; cout<<"Input string: \n"; cin.getline (String,128); /* временная строка */ temp = (char*) SysAllocStringByteLen( NULL, strlen(String) +1 ); strcpy (temp, String); //скопироали while ( (new_string = replace (temp, Match, Replace)) != 0 ) //цикл удаления пробелов { strcpy ( temp, new_string ); /*удаляем new_string*/ SysFreeString( (BSTR) new_string ); } /* на выходе имеем строку "sadasd sadasd f"*/ cout<<"\n"<<temp; /*освобождаем временную строку*/ SysFreeString( (BSTR) temp ); cin.get(); } User breakpoint called form code at 0x77f767cd |
Номер ответа: 60 Автор ответа: ![]() ![]() Вопросов: 0 Ответов: 1066 |
Профиль | Цитата | #60 | Добавлено: 16.11.05 14:57 |
Хе-хе, а я вот всё жду, когда же ты на вылет проги по 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, можно прочитать, что они делают. |
|