Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 18.10.2010, 19:04   #1
kloffelin
Пользователь
 
Регистрация: 21.02.2010
Сообщений: 27
Печаль Библиотека для работы со строками

Всем доброго времени суток.
Пишу вот библиотеку для работы со строками. Функции strcopy и strlength работают нормально, а concat и reverse - некорректно. Найти ошибку не могу
Заранее спасибо.

P.S. Сорри что нет комментариев, но я думаю и без них здесь можно разобраться.

Код библиотеки:
Код:
strcopy (char s1[], char s2[])
					{
						int  i=0;
						while (s1[i]!=NULL)
						{
							s2[i]=s1[i];
							i++;
						}
						return(0);
					}

int strlength(char s[])
			 {
					int	i=0;
					int len=0;
					while (s[i]!=NULL)
					{
						len++;
						i++;
					}
					return (len);
			 }

concat(char s1[],char s2[])
					{
					 int	i=0,lens1,lens2;
					 lens1=strlength(s1);
					 lens2=strlength(s2);
					 while (i!=lens2)
					 {
						 s1[lens1+i]=s2[i];
						 i++;
					 }
					 return (0);
					}


reverse(char m[])
				{
				int i,l;
				char x[1];

					l=strlength(m);

					for(i=0;i<l/2;i++)
					{
						 x[0]=m[i];
						 m[i]=m[l-i];
						 m[l-i]=x[0];
					}
					return (0);
				}
kloffelin вне форума Ответить с цитированием
Старый 18.10.2010, 19:23   #2
coNsept
Форумчанин
 
Аватар для coNsept
 
Регистрация: 14.12.2009
Сообщений: 716
По умолчанию

Попробуй такой вариант реверса

Код:
void Reverse(char String[])
{
  int i , j , Temp;

  for (i = 0, j = strlen(String) - 1; i < j; i++, j--)
  { 
    Temp = String[i]; 
    String[i] = String[j]; 
    String[j] = Temp; 
  }
}
coNsept вне форума Ответить с цитированием
Старый 18.10.2010, 19:31   #3
kloffelin
Пользователь
 
Регистрация: 21.02.2010
Сообщений: 27
По умолчанию

Цитата:
Сообщение от coNsept Посмотреть сообщение
Попробуй такой вариант реверса

Код:
void Reverse(char String[])
{
  int i , j , Temp;

  for (i = 0, j = strlen(String) - 1; i < j; i++, j--)
  { 
    Temp = String[i]; 
    String[i] = String[j]; 
    String[j] = Temp; 
  }
}
спасибо! работает. А с concat не можешь помочь? я уже не знаю че с ней делать
kloffelin вне форума Ответить с цитированием
Старый 18.10.2010, 20:15   #4
coNsept
Форумчанин
 
Аватар для coNsept
 
Регистрация: 14.12.2009
Сообщений: 716
По умолчанию

Ты же s1 инициализируешь уже в самом начале, когда аргументом его передаешь в функцию.
Выделяй память под новую строку, с размером 1, 2 строки, и только потом копируй слова.
coNsept вне форума Ответить с цитированием
Старый 18.10.2010, 20:20   #5
kloffelin
Пользователь
 
Регистрация: 21.02.2010
Сообщений: 27
По умолчанию

Цитата:
Сообщение от coNsept Посмотреть сообщение
Ты же s1 инициализируешь уже в самом начале, когда аргументом его передаешь в функцию.
Выделяй память под новую строку, с размером 1, 2 строки, и только потом копируй слова.
сейчас попробую..

думал сделать так:
Код:
concat(char s1[],char s2[])
					{
					 int	i=0,
							j=0,
							len=strlength(s1)+strlength(s2);
					 char str [len];
					 while (i!=strlength(s1))
					 {
						 str[j]=s1[i];
						 i++;
						 j++;
					 }
					 i=0;
					 while(i!=strlength(s2))
					 {
						str[j]=s2[i];
						i++;
						j++;
					 }
					 s2[0]=NULL;
					 for (i=0;i<len;i++)
						s2[i]=str[i];
					 return (0);
					}
но выдает ошибку в строке char str [len];

Через динамику делать, мне кажется, не желательно, т.к. это библиотека и работать она должна работать максимально быстро. Может можно это как-то проще сделать...

Последний раз редактировалось Stilet; 19.10.2010 в 13:23.
kloffelin вне форума Ответить с цитированием
Старый 18.10.2010, 21:11   #6
Гром
Старожил
 
Аватар для Гром
 
Регистрация: 21.03.2009
Сообщений: 2,193
По умолчанию

1. Тут нужно использовать динамическое выделение памяти. malloc для Си, new для C++.
2. Не забывайте о нулевом символе в конце строки. Размер массива должен быть равен len+1 (len символов + символ '\0'). У меня из-за этого недавно были весьма-а-а мозголомные проблемы при освобождении памяти, когда забыл поставить +1...

Ну и еще - указывайте все-таки тип функций (тут вообще лучше void) - "неявный int" является плохим стилем, и даже не знаю, поддерживается ли C99. Стандартом C++ не поддерживается точно.
Простые и красивые программы - коды программ + учебник C++
Создание игры - взгляд изнутри - сайт проекта
Тема на форуме, посвященная ему же
Гром вне форума Ответить с цитированием
Старый 18.10.2010, 21:39   #7
kloffelin
Пользователь
 
Регистрация: 21.02.2010
Сообщений: 27
По умолчанию

Цитата:
Сообщение от Гром Посмотреть сообщение
1. Тут нужно использовать динамическое выделение памяти. malloc для Си, new для C++.
2. Не забывайте о нулевом символе в конце строки. Размер массива должен быть равен len+1 (len символов + символ '\0'). У меня из-за этого недавно были весьма-а-а мозголомные проблемы при освобождении памяти, когда забыл поставить +1...

Ну и еще - указывайте все-таки тип функций (тут вообще лучше void) - "неявный int" является плохим стилем, и даже не знаю, поддерживается ли C99. Стандартом C++ не поддерживается точно.
Вот переделал под динамику:
Код:
concat(char s1[],char s2[])
					{
					 int	i=0,
							j=0,
							len=strlength(s1)+strlength(s2);
					 char *str=new char [len+1];
					 while (i!=strlength(s1))
					 {
						 str[j]=s1[i];
						 i++;
						 j++;
					 }
					 i=0;
					 while(i!=strlength(s2))
					 {
						str[j]=s2[i];
						i++;
						j++;
					 }
					 s2[0]=NULL;
					 for (i=0;i<len;i++)
						s2[i]=str[i];
					delete str;
					 return (0);
					}
передаю в функцию строку s1[10]="1234567890" и s2[20]="0987654321". Строку s2 сделал больше чтобы было куда дописывать первую. После выполнения выдает "123456789009876543211234567890 " и не вылетает (хотя идет переполнение строки s2)..
вот не пойму почему так

а с типом функции понял) спасибо

Последний раз редактировалось kloffelin; 18.10.2010 в 21:57.
kloffelin вне форума Ответить с цитированием
Старый 19.10.2010, 13:15   #8
Гром
Старожил
 
Аватар для Гром
 
Регистрация: 21.03.2009
Сообщений: 2,193
По умолчанию

Знаете, переделайте лучше все через указатели char*, а не char[]. Тогда strcat (если я правильно понял, в результате strcat(s1, s2) для s2 фактически получаем s2 = s1 + s2) будет примерно такой:
Код:
void strcat(char* s1, char* s2)
{
int len1 = strlength(s1), len2 = strlength(s2);
char* str = new char[len1 + len2 + 1];
int i = 0, j = 0;
while (i < len1)
 str[j++] = s1[i++];
i = 0;
while (i < len2)
 str[j++] = s2[i++];
str[j] = 0;   //То же самое: str[j] = '\0';
delete[] s2;
s2 = str;
}
Здесь я в нескольких местах оптимизировал ваш код:
1. Не стоит производить вычисления длин строк при каждой итерации цикла. Лучше заранее сохранить эти значения в переменные.
2. while (i < len1) как-то более традиционно для C/C++, чем while (i != len1). Тем более что вдруг в теле цикла i увеличивается более чем на 1.
3. Запись str[j++] = s1[i++] позволяет убрать две лишние строчки из кода, т.к. постфиксный инкремент все равно возвращает значение, которое было до увеличения переменной.
4. Не забываем добавить в конец нулевой символ.
5. При использовании указателей нам нет необходимости держать строку s2 излишне большого размера только чтобы потом мы смогли туда поместить элементы еще одной строки. Памяти всегда расходуется столько, сколько надо, ни больше и не меньше. Да и копирования из str в s2 не нужно - мы просто присваиваем одному указателю значение другого.
6. Ну а раз тип функции void, то return в конце функции нам не нужен.
Цитата:
После выполнения выдает "123456789009876543211234567890 " и не вылетает (хотя идет переполнение строки s2)..
В принципе мы можем даже записать так:
Код:
char s[2];
for (int i = 0; i < 10; i++)
 s[i] = '!';
и надеяться на лучшее. Программа не заметит, что мы залезли в чужую память и не сможет выдать об этом предупреждение, и мы можем спокойно работать с совершенно левой частью памяти, надеясь, впрочем, только на то, что не похерим ничего важного (иногда везет, а иногда и нет). В этом заключается одна из главных опасностей работы с указателями - уследить за ними может быть весьма проблематично, и есть возможность залезть куда не просят и угробить важные данные, которые хранились там, куда мы сдуру залезли.
Иногда это проходит безнаказанно, а иногда и нет. Так что с указателями придется постоянно быть настороже и внимательно следить за тем, чтобы они не залезли куда не просят.
Простые и красивые программы - коды программ + учебник C++
Создание игры - взгляд изнутри - сайт проекта
Тема на форуме, посвященная ему же
Гром вне форума Ответить с цитированием
Старый 19.10.2010, 13:59   #9
pproger
C++ hater
СтарожилДжуниор
 
Аватар для pproger
 
Регистрация: 19.07.2009
Сообщений: 3,333
По умолчанию

2Гром
Цитата:
Знаете, переделайте лучше все через указатели char*, а не char[].
char[] как параметр функции аналогичен char *. ибо в си все массивы передаются по указателю


Цитата:
void strcat(char* s1, char* s2)
{
int len1 = strlength(s1), len2 = strlength(s2);
char* str = new char[len1 + len2 + 1];
int i = 0, j = 0;
while (i < len1)
str[j++] = s1[i++];
i = 0;
while (i < len2)
str[j++] = s2[i++];
str[j] = 0; //То же самое: str[j] = '\0';
delete[] s2;
s2 = str;

}
мда... никто так не реализовывает strcat) никакого выделения памяти не должно быть. ровно как и освобождения. не влезло в буфер - идут лесом. о присвоении недействительному указателю вообще молчу
I invented the term Object-Oriented, and I can tell you I did not have C++ in mind. (c)Alan Kay

My other car is cdr.

Q: Whats the object-oriented way to become wealthy?
A: Inheritance

Последний раз редактировалось pproger; 19.10.2010 в 14:03.
pproger вне форума Ответить с цитированием
Старый 19.10.2010, 14:29   #10
Гром
Старожил
 
Аватар для Гром
 
Регистрация: 21.03.2009
Сообщений: 2,193
По умолчанию

Цитата:
никто так не реализовывает strcat)
Как говорил Винни-Пух, "я реализовываю".
Цитата:
не влезло в буфер - идут лесом
Что значит "не влезло в буфер"? Это мы, значит, узнаем длину строки с помощью strlen (скажем, она равна len), а потом пытаемся уложить в len две строки - одна длины len, а вторая вообще пошла лесом, тут уже занято? Ну и какой тогда практический смысл от этой функции donotning()?
Или мы передаем в качестве параметра реальный размер? А почему в стандарте не передаем?
Или вообще плюем на параметр и strlen и лепим все как есть в чужую память?
Вот как сделать strcat("Hello, ", "world!") (естественно, вместо строковых литералов нормальные переменные, но это длиннее писать) без выделения дополнительной памяти? Если никак, то на кой оно нам вообще надо?
Цитата:
о присвоении недействительному указателю вообще молчу
Если бы недействительнОГО, я бы понял. А вот недействительнОМУ? Как тогда, интересно, реализовать какую-нибудь функцию resize()?
Код:
void resize(int* arr, int N, int NewN)
{
int* NewArr = new int[NewN];
//копирование
delete[] arr;
arr = NewArr;
}
Я бы сделал так. А вы?
Простые и красивые программы - коды программ + учебник C++
Создание игры - взгляд изнутри - сайт проекта
Тема на форуме, посвященная ему же
Гром вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
XMLGear - библиотека для полноценной работы с XML igorsolkin Общие вопросы по Java, Java SE, Kotlin 0 16.04.2010 17:53
Библиотека для WINAPI для работы с ORACL Golovastik SQL, базы данных 2 02.03.2010 19:42
Библиотека, расширяющая функции для работы с текстом (Delphi) a_n_n_a Помощь студентам 3 28.04.2009 10:42
Библиотека для работы с *.psd-файлами. vinni Мультимедиа в Delphi 3 23.10.2008 20:29
HELP!Си - программа для работы со строками + сумма строк в матрице! DUPLET Помощь студентам 1 20.12.2007 21:16