c str c builder

БлогNot. Редактируемый список чего-то в C++ Builder

Редактируемый список чего-то в C++ Builder

Решим типовую задачу поддержки редактируемого списка (таблицы) на основе табличной компоненты TStringGrid из библиотеки VCL. Допустим, нам нужен список со столбцами «Фамилия» (строка до 30 символов длиной) и «Показатель» (целое или вещественное число до 8 символов длиной).

Для работы с данными добавим на форму компоненту StringGrid1 с вкладки Additional , установим ей в Инспекторе Объектов следующие свойства:

Справа от таблицы расположим Panel1 и изменим ему свойства:

У самой формы можно поставить

Визуально «подровняем» таблицу и панель инструментов, добавим на панель кнопки «Добавить» и «Удалить», выйдет примерно вот что (верх окна):

В Unit1.cpp (например, перед конструктором формы) опишем глобальные данные:

На событие OnResize формы выполним код:

Panel1->ClientW >ClientW >ClientWidth — Panel1->ClientWidth; StringGrid1->Left = 0; Panel1->Left = StringGrid1->ClientWidth+1; Panel1->Top = 0; StringGrid1->Top = 0; Panel1->ClientHeight = Form1->ClientHeight; StringGrid1->ClientHeight = Form1->ClientHeight; StringGrid1->ClientW >ClientWidth — Panel1->ClientWidth; StringGrid1->ColW >ColW >ClientWidth — StringGrid1->ColW >

30.09.2014, 17:57; рейтинг: 12641

Итак, в С++ Builder строки можно задать тремя разными способами: через специальный класс AnsiString, через массив символов char[] и через указатель на первый символ массива char*:

‘ > ; char String4 [ 7 ] = < 'H' , 'e' , 'l' , 'l' , 'o' , '!' , ' ' >;

Задание строк String3 и String4 на самом деле эквивалентно, просто если задавать строку так, как у нас задана строка String3, то её обязательно нужно сразу инициализировать, тогда циферку в квадратные скобки за вас вставит компилятор.

Использование класса AnsiString удобно тем, что заданные с его помощью строки являются динамическими и можно особо не париться с их размером. То есть можно писать, например, так:

AnsiString String1; String1=»Hello!»; String1=»Hello world!»;

И пофигу, что во втором случае строка стала длиннее, пускай Builder сам с этим разбирается.

Для символьных массивов такой фокус не прокатит от слова совсем. Для указателя прокатит, но нужно понимать, что при этом на самом деле не меняется исходный массив, а просто изменяется значение указателя и он начинает указывать на другой существующий массив (который кто-то создал, память под него выделил). При этом старый массив, на который указывал указатель, просто потеряется. Это чревато всякими утечками памяти и тому подобными косяками.

Строки, заданные как массив символов, должны оканчиваться нулём (по-другому их называют нультерминированные). Массив Char-ов может содержать нули, но при этом строкой считается всё, что содержится от начала массива до первого встреченного нулевого символа. Например, можно задать вот такой массив:

Если в этом случае попробовать посчитать длину строки TempStr, то она окажется равной пяти, то есть количеству элементов от начала строки до нультерминатора, без учёта его самого. (Как видите, элементы массива не обязательно писать в кавычках, как символы, можно и напрямую в hex).

Более того, один массив может содержать сразу две строки. Фактически в предыдущем примере так оно и есть. Если мы напишем вот такой код:

‘ > ; Edit1 — > Text = TempStr ; Edit2 — > Text = & TempStr [ 6 ] ; // &TempStr[6] — адрес шестого элемента (‘w’)

, то в Edit1 получим текст «Hello», а в Edit2 — текст «world».

Ещё одной фишкой является то, что в AnsiString элементы считаются с единицы, а в массивах символов (да и в любых вообще массивах) — с нуля (именно поэтому символ ‘w’ в предыдущем примере шестой, а не седьмой). То есть вот такой код:

‘ > ; AnsiString AStr = «Hello» ; Edit1 — > Text = Str [ 1 ] ; Edit2 — > Text = AStr [ 1 ] ;

char Str[]=<'H','e','l','l','o',''>; AnsiString AStr=»Hello»; Edit1->Text=Str[1]; Edit2->Text=AStr[1];

выведет в поле Edit1 символ ‘e’, а в поле Edit2 символ ‘H’.

Да, кстати, как видите, элементы AnsiString тоже можно получить по индексам, совсем как элементы массива.

Поскольку AnsiString — это класс, то он имеет множество всяких полезных свойств и методов, позволяющих особо не париться с различными операциями над строками. Для массива вместо этого приходится пользоваться специальными библиотечными функциями или писать свои.

Как правило, самый частый вопрос, который возникает при работе со строками, — это преобразование типов, когда из AnsiString нужно получить массив Char или наоборот.

Итак, сначала получаем из AnsiString массив Char. Сделать это можно следующим образом:

AnsiString AStr=»Hello»; char Str1[10]=<'a','a','a','a','a','a','a','a','a','a'>; strcpy(Str1,AStr.c_str()); // копируем в существующий массив Edit1->Text=Str1;

AnsiString AStr=»Hello»; char *Str2; // создаём указатель, который пока ни к чему не привязан Str2 = new char[ Astr.Length() + 1 ]; // создаём новый массив, // привязываем к нему указатель strcpy(Str2,AStr.c_str()); // и копируем в этот массив Edit1->Text=Str2;

В первом случае нужно дополнительно проверить, чтобы массив, в который происходит копирование, был достаточного размера. Размер массива должен быть на 1 больше количества символов в строке (1 дополнительный элемент нужен для нультерминатора).

Как делать не нужно!

AnsiString AStr=»Hello»; char *Str2 = AStr.c_str();

В хэлповнике по Builder-у написано, что функция c_str() возвращает временный указатель на внутренний буфер строки в объекте AnsiString, который действителен только на время выполнения выражения, в котором он используется.

Для того, чтобы преобразовать массив char-ов в AnsiString можно использовать вот такой метод:

‘ > ; AnsiString AStr ; AStr = AnsiString ( Str1 ) ;

char Str1[]=<'H','e','l','l','o',''>; AnsiString AStr; AStr=AnsiString(Str1);

Преобразование выполняется до первого встреченного нультерминатора. То есть, если массив выглядел, скажем, вот так: <‘H’,’e’,’′,’l’,’o’,’′>, то после преобразования его в AnsiString, полученная строка будет выглядеть так: «He».

Некоторые полезные методы класса AnsiString

Как узнать количество символов в строке? Length
Как проверить — пустая строка или нет? IsEmpty
Как вставить подстроку внутрь строки? Insert
Как удалить часть строки? Delete
Как привести все символы строки к нижнему регистру? LowerCase
Как привести все символы строки к верхнему регистру? UpperCase
Как узнать, содержится ли подстрока в строке? Pos, AnsiPos
Как получить подстроку из строки? SubString
Как преобразовать строку в целое число? ToInt, ToIntDef
Как преобразовать целое число в строку? IntToHex
Как убрать пробелы в начале и в конце строки? Trim, TrimLeft, TrimRight

С AnsiString можно выполнять операции сложения и сравнения: + , == , != , > , ≥ ,

Добавить комментарий Отменить ответ

Для отправки комментария вам необходимо авторизоваться.

One task that always annoys me when I work with C is building strings. snprintf is all well and good if I know exactly the format I want. It falls down with anything that needs to be build iteratively and dynamically. Other languages that have built in strings will automatically create a new string when concatenating but C doesn’t actually have “strings”.

I realize that concatenating strings is really inefficient and should be avoided for all but the smallest and simplest string. To deal with this, a few other languages (Java, .Net) have StringBuilder objects which are very efficient. To make things easier on myself I wrote a simple string builder in C.

There are two different types of manipulation that’s supported. 1. Appending data. 2. Removing data. The builder only allows adding a few different types but it could be expanded for additional ones. The integer append is a good example of what can be done. As far as removing data goes, it’s beginning, end or all only. This doesn’t support insertion or removal in the middle because it’s unnecessarily complex and I’ve never seen a good use case for it.

The str builder object has a couple of guarantees. The internal data is always stored NULL terminated so it’s safe to use peek with something like printf . While this is intended for strings the length of the data in the object is known and adding a string optionally takes a length. So, you could use it with binary data.

The implementation isn’t all that complex. It’s a buffer to store the data that dynamically grows as necessary. The internal buffer never shrinks because having it, I haven’t found a real benefit. If you reuse the builder to build multiple strings you’re going to add data to it after clearing, truncating, or dropping. If it shrunk, it would shrink then immediately grow once more data is added.

The obligatory test app to show this actually works. Oh, and its output.

Оцените статью