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

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

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

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

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

Результаты опроса: Хорошо ли вышел класс String
Безусловно 0 0%
Вполне 0 0%
Сойдет 0 0%
Очень плохо 2 100.00%
Хорошо, но std-шный лучше 0 0%
Отлично, но std-шный не хуже 0 0%
Опрос с выбором нескольких вариантов ответа. Голосовавшие: 2. Вы ещё не голосовали в этом опросе

Ответ
 
Опции темы Поиск в этой теме
Старый 06.10.2017, 00:05   #1
Андрей Цапко
Пользователь
 
Регистрация: 10.04.2017
Сообщений: 66
По умолчанию Как узнать размер массива по ссылке

Здравствуйте. Подскажите. У меня есть функция которая разбивает строку на части (http://php.net/manual/ru/function.explode.php), есть класс по аналогии со строками в PHP. Функция создает массив строк и разбивает в него строку. Скажите пожалуйста как узнать его размер (массив передается из функции по ссылке) и можно ли через try catch понять что мы обращаемся к недоступной памяти?
Вот весь код.
Код:
#ifndef PHP_EXPLODE
#define PHP_EXPLODE 1

#include "string.cpp"
#include "substr_count.cpp"
#include <cstring>

namespace php{
	
	String* explode(const String &delimiter, String string){
		int size=substr_count(string, delimiter);
		char *token;
		String *result=new String[++size];

		token=strtok(string.value, delimiter.value);
		for(unsigned int i=0; i<size; i++){
			result[i]=token;
			token=strtok(NULL, delimiter.value);
		}
		delete token;
		return result;
	}

}

#endif

#include <iostream>
using std::cout;
using std::endl;

int main(){
	php::String *array;
	array=php::explode(" ", "Hello World!");
	cout<<array[0].str()<<endl;
	cout<<array[1].str()<<endl;
	
	try{
		if(array[2]){
			throw 1;
		}else{
			throw 0;
		}
	}catch(int a){
		cout<<a<<endl;
	}
	return 0;
}
Цитата:
#ifndef PHP_STRING
#define PHP_STRING 1

namespace php{

class String{

friend unsigned int strlen(const String &);
friend String base64_encode(const String &);
friend String* explode(const String &, String);
friend int substr_count(const String &, const String &, unsigned int);
friend int substr_count(const String &, const String &, unsigned int, unsigned int);

public:
String(){
value=new char[1];
value[0]='\0';
}
String(const char *_str){
value=strcpy(_str);
}
~String(){
delete value;
}

//Операторы присвоения
String& operator=(const String &_str){
value=strcpy(_str.value);
return *this;
}
String& operator=(const char *_str){
value=strcpy(_str);
return *this;
}
String& operator=(const int &number){
value=strcpy(strval(number));
return *this;
}

//Операторы добавления
String& operator+=(const String &_str){
value=strsum(value, _str.value);
return *this;
}
String& operator+=(const char *_str){
value=strsum(value, _str);
return *this;
}
String& operator+=(const int &number){
value=strsum(value, strval(number));
return *this;
}

//Операторы сложения
String operator+(const String &_str){
String result=strsum(value, _str.value);
return result;
}
String operator+(const char *_str){
String result=strsum(value, _str);
return result;
}
String operator+(const int &number){
String result=strsum(value, strval(number));
return result;
}

//Получение значения
const char* str()const{
return value;
}
const char* str(){
return value;
}

private:
char *value;

char* strcpy(const char *str){
unsigned int size=strlen(str);
char *result=new char[size+1];
int i;

for(i=0; i<size; i++){
result[i]=str[i];
}
result[i]='\0';
return result;
}

char* strsum(const char *str1, const char *str2){
unsigned int size1=strlen(str1);
unsigned int size2=strlen(str2);
char *result=new char[size1+size2+1];
int i=0;

for(int j=0; j<size1; j++){
result[i]=str1[j];
i++;
}
for(int j=0; j<size2; j++){
result[i]=str2[j];
i++;
}
result[i]='\0';
return result;
}

char* strval(int number){
bool negative=false;
short int capacity=1;
int delimetr=capacity*10;
char *result;

if(number<0){
number=-number;
negative=true;
capacity++;
}

while(number>=delimetr){
delimetr*=10;
capacity++;
}

result=new char[capacity+1];
while(number>0){
result[--capacity]=number%10+'0';
number/=10;
}

if(negative){
result[0]='-';
}
return result;
}

unsigned int strlen(const char *str){
unsigned int size=0;
while(str[size]!=0){
size++;
}
return size;
}
};

}
#endif
Если можете подскажите пожалуйста как сделать дружескую функцию с класссом ofstream, не подключая его в файле с классом строки (что бы не обязательно было вообще использовать ofstream)

где то видел
Код:
friend std::ostream& operator<<(std::ostream&, const String&);

std::ostream& operator<<(std::ostream& os, const String& obj)
{
    return os << obj.str;
}
, но для этого нужно подключить файл iostream. Заранее спасибо (просьба не спрашивать зачем создан класс String. Я знаю что подобный есть в std библиотеке)
Андрей Цапко вне форума Ответить с цитированием
Старый 06.10.2017, 03:03   #2
alexzk
Форумчанин
 
Регистрация: 12.04.2017
Сообщений: 889
По умолчанию

И у вас носороговый слон выведен...Помесь С и С++, взято все самое худшее от обоих.

Вот так разбивать:

Код:
std::vector<std::string> split(const std::string &str, const std::string &delim)
{   
    const size_t delim_pos = str.find(delim);

    if (delim_pos == std::string::npos)
        return {str};
    std::vector<std::string> ret{str.substr(0, delim_pos)};
    std::vector<std::string> tail = split(str.substr(delim_pos + delim.size(), std::string::npos), delim);
    ret.insert(ret.end(), tail.begin(), tail.end());
    return ret;
}
А то, что вы там с массивами (пеленка кода!, кто ее читает?) ...хз) В языке вообще нет понятия массива, как такового. Есть указатели и блоки памяти. Пользуйтесь вектором.
alexzk вне форума Ответить с цитированием
Старый 06.10.2017, 06:00   #3
Croessmah
Вредный кошак
Участник клуба
 
Аватар для Croessmah
 
Регистрация: 14.10.2012
Сообщений: 1,159
По умолчанию

new[] с delete?
Croessmah вне форума Ответить с цитированием
Старый 06.10.2017, 06:16   #4
alexzk
Форумчанин
 
Регистрация: 12.04.2017
Сообщений: 889
По умолчанию

ух...решил почитать еще кода

Код:
char *token;
		String *result=new String[++size];

		token=strtok(string.value, delimiter.value);
		for(unsigned int i=0; i<size; i++){
			result[i]=token;
			token=strtok(NULL, delimiter.value);
		}
		delete token;
		return result;
Цитата:
Parameters
str
C string to truncate.
Notice that this string is modified by being broken into smaller strings (tokens).
Alternativelly, a null pointer may be specified, in which case the function continues scanning where a previous successful call to the function ended.
Что означает, что
1. strtok память не выделяет и
2. strtok портит исходную строку.

Далее,
Код:
result[i]=token;
Загоняем в массив указатели в пределах сломаной исходной строки string.value, т.о. эти указатели будут верны, пока существует исходная строка.

Далее

Код:
delete token;
Здесь мы убиваем последний кусок исходной строки...но,
Цитата:
A null pointer is always returned when the end of the string (i.e., a null character) is reached in the string being scanned.
Т.о. это эквивалентно
Код:
delete NULL;
....конкретное поведение тут будет зависить от компилера, по моему. Видел я и краши в таком коде. Upd: у вас завершение цикла не по указателю, а по счетчику...так что тут возможно удаление указателя в середине блока = бум и ой.


В итоге что имеем? Сомнительное удаление нуля и попорченую исходную строку, кроме того, "массив" результата верен, пока жива исходная строка. Бред.
Ах да, исходя из
Цитата:
Alternativelly, a null pointer may be specified, in which case the function continues scanning where a previous successful call to the function ended.
получаем, что функция СОХРАНЯЕТ свое состояние. Если вы задумаете использовать свои строки в многопоточной программе и параллельно обрабатывать 2 текста = результат не предсказуем.

Последний раз редактировалось alexzk; 06.10.2017 в 06:50.
alexzk вне форума Ответить с цитированием
Старый 06.10.2017, 11:03   #5
Андрей Цапко
Пользователь
 
Регистрация: 10.04.2017
Сообщений: 66
По умолчанию

Я не хочу использовать std библиотеки так что вектор отпадает. С токеном я не много не понял. result это массив объектов. при присвоении данные из token копируются, так что после удаления токена данные не портяться. Исходная строка тоже не портиться потому что при передаче параметров функции создается копия строки, соответственно вне функции все идет своим чередом. Счетчик получается из функции. Функция находит вхождение подстроки в строку, то есть я заранее знаю сколько токенов я могу получить из строки. Подскажите как узнать размер массива возвращаемого этой функцией, возвращается то ссылка на массив
Андрей Цапко вне форума Ответить с цитированием
Старый 06.10.2017, 11:23   #6
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,493
По умолчанию

Цитата:
Сообщение от Андрей Цапко Посмотреть сообщение
Подскажите как узнать размер массива возвращаемого этой функцией
Никак, средства языка этого не позволяют.
Напишите структуру/класс в котором будет указатель на данные и размер.
waleri вне форума Ответить с цитированием
Старый 06.10.2017, 11:58   #7
alexzk
Форумчанин
 
Регистрация: 12.04.2017
Сообщений: 889
По умолчанию

Цитата:
Сообщение от Андрей Цапко Посмотреть сообщение
Я не хочу использовать std библиотеки так что вектор отпадает. С токеном я не много не понял. result это массив объектов. при присвоении данные из token копируются, так что после удаления токена данные не портяться. Исходная строка тоже не портиться потому что при передаче параметров функции создается копия строки, соответственно вне функции все идет своим чередом. Счетчик получается из функции. Функция находит вхождение подстроки в строку, то есть я заранее знаю сколько токенов я могу получить из строки. Подскажите как узнать размер массива возвращаемого этой функцией, возвращается то ссылка на массив

Код:
char* strcpy(const char *str){
unsigned int size=strlen(str);
char *result=new char[size+1];
int i;

for(i=0; i<size; i++){
result[i]=str[i];
}
result[i]='\0';
return result;
}
strlen пользуем, а memcpy уже библиотеки не хочу? ... кстати, а если строка содержит в себе 0 ? А если я в нее файл на 5Гб грузануть как в буфер хочу?

Код:
String(){
value=new char[1];
value[0]='\0';
}
String(const char *_str){
value=strcpy(_str);
}
~String(){
delete value;
}

//Операторы присвоения
String& operator=(const String &_str){
value=strcpy(_str.value);
return *this;
}
Это вы тоже нормальным считаете?

Создали новуб память в 1 байт:

Код:
String(){
value=new char[1];
value[0]='\0';
}
Потеряли созданую память в 1 байт (ну или любую другую, если уже было присваивание)
Код:
String& operator=(const String &_str){
value=strcpy(_str.value);
return *this;
}
При удалении объекта вообще всякую память потеряли (нада delete [])

Код:
~String(){
delete value;
}
.....кароче, это все на цитаты разбирать, буквально каждую строчку, как делать не нужно...ну и выше я там писал, в многопоточной программе вашу реализацию нельзя использовать никак.
alexzk вне форума Ответить с цитированием
Старый 06.10.2017, 12:02   #8
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,695
По умолчанию

Цитата:
....конкретное поведение тут будет зависить от компилера, по моему.
Нет, по стандарту delete есть nullptr
p51x вне форума Ответить с цитированием
Старый 06.10.2017, 12:06   #9
alexzk
Форумчанин
 
Регистрация: 12.04.2017
Сообщений: 889
По умолчанию

Цитата:
Сообщение от p51x Посмотреть сообщение
Нет, по стандарту delete есть nullptr
Согласен, там оговорка "если не ноль". Но, я точно помню - видел/искал краш, когда в удаляторе shared_ptr написал
delete []p;

C тех пор всегда пишу

if (p) delete []p; //delete p

...возможно было на арм...не вспомню)
alexzk вне форума Ответить с цитированием
Старый 06.10.2017, 12:14   #10
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,695
По умолчанию

http://en.cppreference.com/w/cpp/language/delete

Цитата:
If expression evaluates to a null pointer value, no destructors are called, and the deallocation function may or may not be called (it's implementation-defined), but the default deallocation functions are guaranteed to do nothing when handed a null pointer.

(until C++14)
If expression evaluates to a null pointer value, no destructors are called, and the deallocation function is not called.

(since C++14)
p51x вне форума Ответить с цитированием
Ответ


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

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Как узнать выделенный размер документа. valerij Microsoft Office Excel 10 26.07.2015 11:48
Как узнать размер массива String^ calypso Общие вопросы C/C++ 4 12.11.2013 14:53
Как узнать размер изображения Lokos Мультимедиа в Delphi 3 21.12.2009 16:44
Как узнать размер файла? photozaz Общие вопросы Delphi 4 01.08.2008 00:29
Как узнать размер массива мандарин Общие вопросы Delphi 2 30.05.2007 19:18