Все технические форумы на одном сайте Удобный поиск информации с популярных форумов в одном месте
Вопрос: Работа строками, удалить и заменить до определенного символа

Дано строка. До первой точки удалить все запятые. После первой точки все символы-"5", заменить на "+"-символы. Помогите пожалуйста...
Ответ: вышло спасибо)))

package com.company;
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Main {
 
    public static void main(String[] args) {
        String str = "фы,в,а прdfverrо,лд,жэ. йцук5ен гш5щз5rfrf55rf5ъ: яч5сми5ть5бю";
 
        String Str1 = str.substring(+ 0, str.indexOf('.'));
        String A = Str1.replaceAll(",", "");
 
        String Str2 = str.substring(str.indexOf('.'));
        String B = Str2.replace ('5', '+');
 
        String result = A + B;
        System.out.print(result);
// write your code here
    }
}
Вопрос: Jpg.SaveToStream(mStream) Как ускорить работу ?

В интернеты не посылать, уже все что есть прочитано. 
И так:
1. Программа "Удаленный рабочий стол"
2. Делаю скрин в Bitmap
3. Bitmap перевожу в Jpeg
4. Jpeg (пробовал и Bitmap)  сохраняю в MemoryStream

И тут то начинается самое интересное. Очень медленная работа строки 
Код
 Jpg.SaveToStream(mStream); 
 Причем если не закоментировать сохранение в поток, то сервер от клиента начинает пропускать сообщения (строки). Кто сталкивался с такой проблемой и знает как ускорить работу подобного кода? Или возможно есть варианты как переписать его. По ощущениям сохранениесохранение в файл проходит значительно быстрее, что очень странно 
Код
  Bmp.SaveToFile(ExtractFilePath(ParamStr(0))+'/'+IntToStr(i)+'.bmp' ); 
 Ниже есть ссылки на аналогичные проблемы, ну путей решения так и не предложено. Заранее всем благодарен за вразумительные ответы! 





Это сообщение отредактировал(а) crazynetwork - 9.5.2016, 13:46
Ответ:
Хотя смотрю нашелся еще товарищ, который написал свой варпер

Код

//Кодирование изображения
procedure EncodeJpegTurbo(Source: TFastDIB; Quality: Integer; OnEncodedBuffer: TOnEncodedJpegBuffer);
var
  ScanLine: JSAMPROW;
  CompressedBuff: Pointer;
  CompressedSize: LongWord;
  JpegErr: jpeg_error_mgr;
  Jpeg: jpeg_compress_struct;
begin
  //Инициализация библиотеки
  InitLib;
 
  FillChar(Jpeg, SizeOf(Jpeg), 0);
  FillChar(JpegErr, SizeOf(JpegErr), 0);
 
  //Создаем структуру компрессора
  jpeg_create_compress(@Jpeg);
  try
    //Назначим дефолтный обработчик ошибок
    Jpeg.err := jpeg_std_error(@JpegErr);
 
    //Переопределим методы дефолтного обработчика. По умолчанию, при возникновении
    //любой ошибки в LibJPEG происходит закрытие приложения, и вывод ошибки в MessageBox
    JpegErr.error_exit := ErrorExit;
    JpegErr.output_message := OutputMessage;
 
    CompressedSize := 0;
    CompressedBuff := nil;
 
    //Используем свою реализацию jpeg_mem_dest из-за утечек памяти в стандартной.
    suJpegTurboMemDestUnit.jpeg_mem_dest(@Jpeg, @CompressedBuff, @CompressedSize);
    try
      jpeg.image_width := Source.Width;
      jpeg.image_height := Source.Height;
      jpeg.input_components := Source.Info.Header.BitCount div 8;
      jpeg.in_color_space := JCS_EXT_BGR;
 
      //Setting defaults
      jpeg_set_defaults(@Jpeg);
 
      //Качество сжатия
      jpeg_set_quality(@Jpeg, Quality, True);
 
      //Декодируем изображение
      jpeg_start_compress(@Jpeg, True);
      try
        while Jpeg.next_scanline < Jpeg.image_height do
        begin
          ScanLine := JSAMPROW(Source.Scanlines[Jpeg.image_height - Jpeg.next_scanline - 1]);
          jpeg_write_scanlines(@Jpeg, @ScanLine, 1);
        end;
      finally
        //Заканчиваем кодирование
        jpeg_finish_compress(@Jpeg);
      end;
 
      //Передаем буфер вызывающей процедуре
      if Assigned(OnEncodedBuffer) then
        OnEncodedBuffer(CompressedBuff, CompressedSize);
    finally
      //Освободим память
      FreeMemory(CompressedBuff);
    end;
  finally
    //Уничтожаем ненужные объекты
    jpeg_destroy_compress(@Jpeg);
  end;
end;

Вопрос: Работа с COM-портом в асинхронном режиме

Пробую разобраться с работой COM порта. Получилось запустить в синхронном режиме. Стало ясно, что в этом режиме, вызывая функцию чтения данных ReadFile(), я не знаю заранее есть ли данные для чтения. Можно циклически проверять их наличие, но это приводит к дополнительным расходам времени ЦП. Поэтому на практике часто удобней использовать асинхронный режим.
Я нашел вот такую статью и решил попробовать написать похожую программу в C++ Builder 6. Код такой:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
//---------------------------------------------------------------------------
 
 
 
#include <vcl.h>
#pragma hdrstop
 
#include <io.h>         // для работы с файлами
#include <fcntl.h>      // для работы с файлами
#include <sys\stat.h>   // для работы с файлами
 
 
#include "COMport.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------
 
 
 
 
//-Объявления глобальных переменных-----------------------------------------------------------------------------------------
#define BUFSIZE 255     //ёмкость буфера
 
unsigned char bufrd[BUFSIZE], bufwr[BUFSIZE]; //приёмный и передающий буферы
 
HANDLE COMport;     //дескриптор порта
 
//структура OVERLAPPED необходима для асинхронных операций, при этом для операции чтения и записи нужно объявить разные структуры
//эти структуры необходимо объявить глобально, иначе программа не будет работать правильно
OVERLAPPED overlapped;      //будем использовать для операций чтения (см. поток ReadThread)
OVERLAPPED overlappedwr;        //будем использовать для операций записи (см. поток WriteThread)
 
int handle;                 //дескриптор для работы с файлом с помощью библиотеки <io.h>
 
bool fl=0;  //флаг, указывающий на успешность операций записи (1 - успешно, 0 - не успешно)
 
unsigned long counter;  //счётчик принятых байтов, обнуляется при каждом открытии порта
 
 
 
char *buf_out;// = "Test string";
char *buf_in;
DWORD bc;
DCB *dcb;
 
 
char NumOut = 0;
char NumIn = 0;
 
String portname;
 
//--------------------------------------------------------------------------------------------------------------------------------
 
 
 
 
//-Объявления потоков---------------------------------------------------------------------------------------------------------------
HANDLE reader;  //дескриптор потока чтения из порта
HANDLE writer;  //дескриптор потока записи в порт
 
DWORD WINAPI ReadThread(LPVOID);
DWORD WINAPI WriteThread(LPVOID);
//--------------------------------------------------------------------------------------------------------------------------------
 
 
 
 
 
//-Поток ReadThead--------------------------------------------------------------------------------------------------------------------
 
void ReadPrinting(void);
 
//---------------------------------------------------------------------------
 
//главная функция потока, реализует приём байтов из COM-порта
DWORD WINAPI ReadThread(LPVOID)
{
COMSTAT comstat;        // структура текущего состояния порта, в данной программе используется для определения количества принятых в порт байтов
DWORD btr, temp, mask, signal;  // переменная temp используется в качестве заглушки
 
overlapped.hEvent = CreateEvent(NULL, true, true, NULL); // создать сигнальный объект-событие для асинхронных операций
SetCommMask(COMport, EV_RXCHAR);                     // установить маску на срабатывание по событию приёма байта в порт
while(1)                         // пока поток не будет прерван, выполняем цикл
  {
  WaitCommEvent(COMport, &mask, &overlapped);                   //ожидать события приёма байта (это и есть перекрываемая операция)
  signal = WaitForSingleObject(overlapped.hEvent, INFINITE);    //приостановить поток до прихода байта
 
  if(signal == WAIT_OBJECT_0)                       //если событие прихода байта произошло
    {
    if(GetOverlappedResult(COMport, &overlapped, &temp, true)) //проверяем, успешно ли завершилась перекрываемая операция WaitCommEvent
      if((mask & EV_RXCHAR)!=0)                 //если произошло именно событие прихода байта
        {
        ClearCommError(COMport, &temp, &comstat); // нужно заполнить структуру COMSTAT
        btr = comstat.cbInQue;                    // и получить из неё количество принятых байтов
        if(btr)                                   // если действительно есть байты для чтения
          {
          ReadFile(COMport, bufrd, btr, &temp, &overlapped); // прочитать байты из порта в буфер программы
          counter+=btr;                                      // увеличиваем счётчик байтов
          ReadPrinting();                                    // вызываем функцию для вывода данных на экран и в файл
          }
        }
    }
  }
}
 
 
//---------------------------------------------------------------------------
 
//выводим принятые байты на экран
void ReadPrinting()
{
Form1->MemoOut->Lines->Add((char*)bufrd);    //выводим принятую строку в Memo
memset(bufrd, 0, BUFSIZE);          //очистить буфер (чтобы данные не накладывались друг на друга)
 
}
 
 
 
 
 
//-Поток WriteThead-----------------------------------------------------------------------------------------------------------------------
 
//главная функция потока, выполняет передачу байтов из буфера в COM-порт
DWORD WINAPI WriteThread(LPVOID)
{
 
DWORD temp, signal; //temp - переменная-заглушка
 
overlappedwr.hEvent = CreateEvent(NULL, true, true, NULL);        //создать событие
while(1)
  {
  WriteFile(COMport, bufwr, strlen(bufwr), &temp, &overlappedwr);  //записать байты в порт (перекрываемая операция!)
  signal = WaitForSingleObject(overlappedwr.hEvent, INFINITE);    //приостановить поток, пока не завершится перекрываемая операция WriteFile
 
  if((signal == WAIT_OBJECT_0) && (GetOverlappedResult(COMport, &overlappedwr, &temp, true))) //если операция завершилась успешно
    {
    Form1->StatusBar->Panels->Items[0]->Text  = "Передача прошла успешно"; //вывести сообщение об этом в строке состояния
    }
 
  else
    {
    Form1->StatusBar->Panels->Items[0]->Text  = "Ошибка передачи"; // иначе вывести в строке состояния сообщение об ошибке
    }
 
  SuspendThread(writer);
 
  }
}
//-----------------------------------------------------------------------------------------------------------------------------------
 
 
 
 
 
 
 
 
 
 
void __fastcall TForm1::ConnectBtnClick(TObject *Sender)
{
COMMTIMEOUTS timeouts;
 
 
//-Открытие порта----------------------------------------------------------------------------------------------------------------
portname = ChoiceCOM->Text;
COMport=CreateFile(portname.c_str(), GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
 //здесь:
 // - portname.c_str() - имя порта в качестве имени файла,
 //   c_str() преобразует строку типа String в строку в виде массива типа char, иначе функция не примет
 // - GENERIC_READ | GENERIC_WRITE - доступ к порту на чтение/записть
 // - 0 - порт не может быть общедоступным (shared)
 // - NULL - дескриптор порта не наследуется, используется дескриптор безопасности по умолчанию
 // - OPEN_EXISTING - порт должен открываться как уже существующий файл
 // - FILE_FLAG_OVERLAPPED - этот флаг указывает на использование асинхронных операций
 // - NULL - указатель на файл шаблона не используется при работе с портами
 
if(COMport==INVALID_HANDLE_VALUE)
  {
  MemoOut->Lines-> Add("Не удалось открыть последовательный порт.");
  return;
  }
//-------------------------------------------------------------------------------------------------------------------------------------------
 
 
 
//-Инициализация порта----------------------------------------------------------------------------------------------------------------
dcb=(DCB*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DCB)); // Выделение области памяти для DCB из кучи и заполнение этой области нулями.
 
if(!GetCommState(COMport, dcb)) // Эта функция заполняет DCB информацией о текущем состоянии устройства, точнее о его настройках.
  {// Если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния.
  HeapFree(GetProcessHeap(),0,dcb); // Освобождение памяти из кучи.
  CloseHandle(COMport);
  MemoOut->Text  = "Не удалось считать DCB";
  return;
  }
 
//-Инициализация структуры DCB.
dcb->BaudRate = StrToInt(ChoiceSpeed->Text); // задаём скорость передачи 115200 бод
dcb->fBinary = TRUE;                         // включаем двоичный режим обмена
dcb->fOutxCtsFlow = FALSE;                   // выключаем режим слежения за сигналом CTS
dcb->fOutxDsrFlow = FALSE;                   // выключаем режим слежения за сигналом DSR
dcb->fDtrControl = DTR_CONTROL_DISABLE;      // отключаем использование линии DTR
dcb->fDsrSensitivity = FALSE;                // отключаем восприимчивость драйвера к состоянию линии DSR
dcb->fNull = FALSE;//TRUE                    // разрешить приём нулевых байтов
dcb->fRtsControl = RTS_CONTROL_DISABLE;      // отключаем использование линии RTS
dcb->fAbortOnError = FALSE;                  // отключаем остановку всех операций чтения/записи при ошибке
dcb->ByteSize = 8;                           // задаём 8 бит в байте
dcb->Parity = 0;                             // отключаем проверку чётности
dcb->StopBits = 0;                           // задаём один стоп-бит
//dcb->DCBlength=sizeof(DCB);
 
//-Загрузить структуру DCB в порт.
if(!SetCommState(COMport, dcb))
  {// Если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния.
  HeapFree(GetProcessHeap(),0,dcb); // Освобождение памяти из кучи.
  CloseHandle(COMport);
  MemoOut->Text = "Не удалось установить DCB.";
  return;
  }
 
//-Установка таймаутов.
timeouts.ReadIntervalTimeout = 0;     // таймаут между двумя символами
timeouts.ReadTotalTimeoutMultiplier = 0;  // общий таймаут операции чтения
timeouts.ReadTotalTimeoutConstant = 0;    // константа для общего таймаута операции чтения
timeouts.WriteTotalTimeoutMultiplier = 0; // общий таймаут операции записи
timeouts.WriteTotalTimeoutConstant = 0;   // константа для общего таймаута операции записи
 
//-Загрузить структуру таймаутов в порт.
if(!SetCommTimeouts(COMport, &timeouts))
  {// Если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния.
  CloseHandle(COMport);
  MemoOut->Text = "Не удалось установить тайм-ауты.";
  return;
  }
 
//-Установить размеры очередей приёма и передачи
//  SetupComm(COMport,2000,2000);
//---------------------------------------------------------------------------------------------------------------------------------------------
 
 
PurgeComm(COMport,PURGE_RXCLEAR); // Очистка буферов порта.
 
ConnectBtn->Enabled = false;
DisconnectBtn->Enabled = true;
 
 
 
//-Создание потоков на WINAPI:
 
// Cоздаём поток чтения, который сразу начнёт выполняться (предпоследний параметр = 0).
reader = CreateThread(NULL, 0, ReadThread, NULL, 0, NULL);
 
// Cоздаём поток записи в остановленном состоянии (предпоследний параметр = CREATE_SUSPENDED).
writer = CreateThread(NULL, 0, WriteThread, NULL, CREATE_SUSPENDED, NULL);
 
 
counter = 0;
 
//------------------------------------------------------------------------------------------------------------------------------------------------------
}
 
 
 
 
 
//--------------------------------------------------------------------------------------------------------------------------------------------
void __fastcall TForm1::DisconnectBtnClick(TObject *Sender)
{
 
//Примечание: так как при прерывании потоков, созданных с помощью функций WinAPI, функцией TerminateThread
//        поток может быть прерван жёстко, в любом месте своего выполнения, то освобождать дескриптор
//        сигнального объекта-события, находящегося в структуре типа OVERLAPPED, связанной с потоком,
//        следует не внутри кода потока, а отдельно, после вызова функции TerminateThread.
//        После чего нужно освободить и сам дескриптор потока.
 
if(writer)      //если поток записи работает, завершить его; проверка if(writer) обязательна, иначе возникают ошибки
  {
  TerminateThread(writer,0);
  CloseHandle(overlappedwr.hEvent); //нужно закрыть объект-событие
  CloseHandle(writer);
  }
 
if(reader)         //если поток чтения работает, завершить его; проверка if(reader) обязательна, иначе возникают ошибки
  {
  TerminateThread(reader,0);
  CloseHandle(overlapped.hEvent);   //нужно закрыть объект-событие
  CloseHandle(reader);
  }
 
CloseHandle(COMport);                  //закрыть порт
COMport=0;              //обнулить переменную для дескриптора порта
 
ConnectBtn->Enabled = true;
DisconnectBtn->Enabled = false;
 
NumIn=0;
NumOut=0;
}
//--------------------------------------------------------------------------------------------------------------------------------
 
 
 
 
//---------------------------------------------------------------------------
void __fastcall TForm1::SendBtnClick(TObject *Sender)
{
memset(bufwr,0,BUFSIZE);             // очистить программный передающий буфер, чтобы данные не накладывались друг на друга
PurgeComm(COMport, PURGE_TXCLEAR);   // очистить передающий буфер порта
strcpy(bufwr,MemoOut->Text.c_str()); // занести в программный передающий буфер строку из Edit1
ResumeThread(writer);                // активировать поток записи данных в порт
}
//---------------------------------------------------------------------------

При запуске программы, отправка вроде работает, но на входе ничего нет. Мне кажется, что ошибка где-то в функции DWORD WINAPI ReadThread(LPVOID), а именно не выполняется условие if(signal == WAIT_OBJECT_0). Подскажите, где я накосячил?
Ответ:
Сообщение от Alexey9891
Я принципиально хочу решить задачу средствами WINAPI.
Что я могу тут сказать, удачи ...

Добавлено через 2 минуты
Ибо так делать (отсутствует синхронизация с VCL) нельзя:
C++
1
2
3
4
5
void ReadPrinting()
{
Form1->MemoOut->Lines->Add((char*)bufrd);    //выводим принятую строку в Memo
memset(bufrd, 0, BUFSIZE);          //очистить буфер (чтобы данные не накладывались друг на друга)
}
Вопрос: Массовый переброс/удаление строк между таблицами

Здравствуйте, форумчане!

Вопросов несколько, поэтому я засунул их в спойлеры. Настоятельно прошу: не ругать, что что-то не так использую/спрашиваю

Вопрос 1. Массовое удаление строк после DISTINCT-селекта
Кликните здесь для просмотра всего текста

Задача была такая.
DISTINCT-ом по трем столбцам + уникальному идентификатору пользователя (4-й столбец) получить выборку, которую выводим на дбгрид. Всё хорошо до того момента, когда нужно удалить все записи одного уникального трио пользователя. Собственно говоря, пришлось развести на два query.
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
with dm.qry_del do
   begin
      SQL.Clear;
      SQL.Add('DELETE FROM tbl1 WHERE uid = ' + QuotedStr(edt_uid) + ' AND udb = ' + QuotedStr(FormatDateTime('YYYY-MM-DD', StrtoDate(dbgr1.Fields[0].Value))) + ' AND utm = ' + QuotedStr(FormatDateTime('HH:mm:ss', dbgr1.Fields[1].Value)) + ' AND utp = ' + QuotedStr(dbgr1.Fields[2].Value) + ';');
      ExecSQL;
      SQL.Clear;
   end;
with dm.qry_dis do
   begin
      Close;
      Open;
   end;
Вспоминая всеми любимый ADOTable, есть довольно простецкая функция Delete, удаляющая наведенную запись без необходимости перечисления данных под запрос. Безусловно, при использовании приложения по принципу "одно окно-один пользователь" это удобно, но при групповой работе возникнет вопрос с накопившимися копиями.
Можно ли из полученного результата DISTINCT-SELECT запроса как-то более быстро удалять одно выбранное уникальное трио пользователя?
Или остается только такой метод?..


Вопрос 2. Удаление строки_Query-запроса, выбранной из dbgrid
Кликните здесь для просмотра всего текста
У меня есть дбгрид (уже другой, на другой форме, не взаимодействующий с первым вопросом), в котором есть (очевидно) строки. Структура дбгрида (да, собственно, извлекаемой из БД информации): три колонки для визуальной работы, четыре невидимые для отсева "своих" строк. Вопрос схож с первым, но все равно отличие есть.
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if dm.qry_all.RecordCount<>0 then
      begin
        with dm.qry_all_del do
          begin
            SQL.Clear;
            SQL.Add('DELETE FROM (' + dm.qry_all.SQL.Text + ') WHERE Aname = ' + QuotedStr(dm.qry_all.FieldByName('Aname').AsString) + ' AND Binfo = ' + QuotedStr(dm.qry_drrep.FieldByName('Binfo').AsString) + ';');
            ExecSQL;
            SQL.Clear;
          end;
        with dm.qry_all do
          begin
            Close;
            Open;
          end;
      end
        else ShowMessage('Пустоту удалить нельзя!');
 
{сам dm.qry_all.SQL.Text:= 'SELECT * FROM drrep WHERE uid = ' + QuotedStr(edt_uid) + ' AND udb = ' + QuotedStr(FormatDateTime('YYYY-MM-DD', dtp_date.Date)) + ' AND utm = ' + QuotedStr(FormatDateTime('HH:mm:ss', dtp_time.Time)) + ' AND utp = ' + QuotedStr(cbf_type.Items[cbf_type.ItemIndex])'
подсовывается после взаимодействия с формой (т.е. отдали нужные данные форме, она по изменению элементов создает такой запрос на сервер (правда, через SQL.Add, но это не должно иметь значения, т.к. очистки/закрытия_запроса после возврата результата нету)}
Возникает такая ошибка:
Project prj1.exe raised exception class EOleException with message '[MySQL][ODBC 8.0(w) Driver][mysqld-8.0.19]You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(SELECT * FROM tbl1 WHERE uid = 'testuser' AND udb = '2020-03-01' AN' at line 1'.
Т.е. вроде правильно подсунули запрос по типу "приплюсовал строку", но берет и обрывает запрос. И даже не там, где мог быть стык QuotedStr, а тупо в серединке слова.

Ладно. Заменяем запрос на полноценный:
Delphi
1
2
3
4
5
6
7
8
9
//тот же кусок кода
with dm.qry_all_del do
          begin
            SQL.Clear;
            SQL.Add('DELETE FROM (SELECT * FROM drrep WHERE uid = ' + QuotedStr(edt_uid) + ' AND udb = ' + QuotedStr(FormatDateTime('YYYY-MM-DD', dtp_date.Date)) + ' AND utm = ' + QuotedStr(FormatDateTime('HH:mm:ss', dtp_time.Time)) + ' AND utp = ' + QuotedStr(cbf_type.Items[cbf_type.ItemIndex]) + ') WHERE Aname = ' + QuotedStr(dm.qry_all.FieldByName('Aname').AsString) + ' AND Binfo = ' + QuotedStr(dm.qry_drrep.FieldByName('Binfo').AsString) + ';');
            ExecSQL;
            SQL.Clear;
          end;
//тот же кусок кода
Та же ошибка.
Может он ругается на условия внутри подзапроса?

Подвопрос: Можно ли как-то проще удалять строку из БД по этой же строке из результата Query-запроса_с_SELECT-ом_и_условиями?


Вопрос 3. Автонумерация подгрупп
Кликните здесь для просмотра всего текста
Само собой, БД требует создавать столбец с уникальным ключом для всех записей.
Возникает такая проблема, что при добавлении "своих" строк, которые имеют уникальное трио, хочется их пронумеровать и оставить эту нумерацию в БД. Это легко делается при INSERT-е на SELECT-е для выборки "своих" строк (из вопроса 2):
Delphi
1
SQL.Add('INSERT INTO tbl1 (..., ..., groupednum......) VALUES (..., ..., ' + QuotedStr(InttoStr(dm.qry_all.RecordCount+1)) + ', ..., ......);');
Можно ли настроить таковую автонумерацию по принципу A_I MySQL? (я думаю нет, но вдруг...)

Здесь же возникает вопрос с удалением строки из подгруппы и изменением автонумерации(см. спойлер).
Кликните здесь для просмотра всего текста
Как изменять нумерацию подгруппы при удалении из неё строки? Например (сразу извинюсь, не знаю, как работать с таблицей в редакторе, поэтому хоть так)
Код
col     1  ------> 1 -> 1
         2  ------> 2 -> 2
         3  delete   _ ->
         4  ------> 4 -> 3
         5  ------> 5 -> 4
Конечно, можно на удаление UPDATE-ить все строки в NULL, затем проходится циклом по ним всем и пронумеровывать их заново. Но целесообразно ли так это делать?..



Очень важный вопрос (для меня так точно)
Вопрос 4. Пакетная переброска данных из таблицы в таблицу
Кликните здесь для просмотра всего текста

У меня есть необходимость из одной таблицы перебрасывать "свои" "выбранные по необходимому трио" строки в другую таблицу. У меня есть две мысли на этот счет:
1) Берем INSERT-им все результирующие "свои" "выбр-по-трио" строки в таблицу 2. Затем удаляем их из таблицы 1. Согласитесь, громоздко получится.
2) Смена структуры таблицы: убираем таблицу 2, а в таблице 1 создаем колонку, по которой мы определяем принадлежность к мнимым таблицам 1 и 2. Очень удобно, просто UPDATE-им такой флаг до нужной цифры/величины, и всё.

У кого есть какое мнение на такое действие? Может есть команда SQL, позволяющая пробрасывать сразу (по принципу "Ctrl+X - Ctrl+V") всю информацию?

Не по теме:

Сейчас окажется, что наилучшим решением является вариант 2 :D
Я пока работаю по 1-му варианту, эх...




И последний вопрос (надеюсь, ничего не забыл, но если что, я напишу еще)
Вопрос 5. ПАРАМЕТРЫыыыы
Кликните здесь для просмотра всего текста

С параметрами меня познакомил krapotkin, за блог и работу которого я очень благодарен.
Этот вопрос я подымал в , но из-за глюков я временно съехал с работы с ним.

Меня интересует:
1) необходимость и процедура объявления параметров при дизайне и разработке программы;
2) особенности работы (безусловно, они очень хорошо расписаны в блоге krapotkin, но хотелось бы конкретики и специфики по ADO - т.к. глючили-бездействовали данные при воздействии на них - параметры просто не воспринимались сервером;
3) присвоение типов И значений параметрам в ADO-конструкциях;
4) может есть какая-нибудь бесплатная/посильная по цене студенту литература?


Сразу всем премного благодарен за любую помощь/знания/опыт!!!
Ответ: Литература огонь!!!

Ключ r_id, но он не фигурирует в клиенте. Это базовый номер строки в БД со свойствами PK/NN/AI.
В клиенте фигурирует трио "дата-время-тип", уникальный логин и, после весьма , после которого я поменял структуру таблиц БД, флаг принадлежности (f/r, правда, я его добавляю в SQL.Add через QuotedStr('f'), стремаюсь писать три кавычки подряд).
По трио+логин отсев своих строк, флаг распределяет данные из таблицы на две мнимые таблицы, поэтому значения не имеет.
Вопрос: Работа со схемами памяти, заменить getmem-freemem на new-dispose+setlength

Нужно переделать программу со схемы работы памяти [getmem-freemem] на вот такую схему работы памяти [new-dispose+setlength] с параметром-открытым массивом
Возможно возникнет необходимость в качестве значения указателя принять ссылку, которая не связывает с данным указателем никакого объекта, т.е. «пустую ссылку» – NIL.

Само задание
Умножить матрицу на заданное число X

Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
Uses CRT;
Const
  MAX_RANDOM_VALUE = 100;
  MAX_SIZE = 1000;
Type
  MyType = longint;
MyLine = ^Line;
  { "Строка" динамической матрицы }
Line = array[1..MAX_SIZE] of MyType;
{ Сама матрица - представляется как массив указателей на "строки" }
aArray = array[1..MAX_SIZE] of MyLine;
MyArray = ^aArray;
var
  Matr, sMatr:MyArray;
  N,M,R:Integer;
{--------------------------------------------------------}
{подпрограмма для формирования матрицы}  
procedure Input(var DynamicArray1:MyArray;var sDynamicArray:MyArray;var _N, _M:Integer; var _r:integer);
var
  I,J: byte;
  code: Integer;
  s: string;
begin
repeat
    Write('Enter the N (Integer): ');
    ReadLn(s);
val(s,_N,code);
if (code<>0) or(_N<0) then
      WriteLn('An incorrect value.');
until (code=0);
repeat
    Write('Enter the M (Integer): ');
    ReadLn(s);
    val(s,_M,code);
if (code<>0) or(_M<0) then
      WriteLn('An incorrect value.');
until (code=0);
repeat
    Write('Enter the R (Integer): ');
    ReadLn(s);
    val(s,_r,code);
if (code<>0) or(_r<0) then
      WriteLn('An incorrect value.');
until (code=0);
Randomize;
   { Выделяем память под указатели на "строки" }
GetMem(DynamicArray1, _N * SizeOf(MyLine));
{ И для каждой "строки" - выделяем память для хранения данных }
for I := 1 to _N do
    GetMem(DynamicArray1^[I], _N*SizeOf(MyType));
for I:=1 to _N do
for J:=1 to _M do
{ Немного изменяется способ обращения к элементу матрицы }
DynamicArray1^[I]^[J]:=random(MAX_RANDOM_VALUE);
  WriteLn;
  WriteLn('Matrix:');
  for I:=1 to _N do
begin
for J:=1 to _M do
      Write(DynamicArray1^[I]^[J]:3);
    WriteLn;
end;
end;
{--------------------------------------------------------}
{подпрограмма для умножения матрицы на число}  
procedure UmnMatr(var DynamicArray1:MyArray;var sDynamicArray:MyArray;var _N,_M:Integer; var _r: integer);
var
I,J:byte;
begin;
  GetMem(sDynamicArray, _N * SizeOf(MyLine));
{ И для каждой "строки" - выделяем память для хранения данных }
for I := 1 to _N do
    GetMem(sDynamicArray^[I], _N*SizeOf(MyType));
for I:=1 to _N do
for J:=1 to _M do
{ Немного изменяется способ обращения к элементу матрицы }
sDynamicArray^[I]^[J]:=DynamicArray1^[I]^[J]* _r;
end;
{--------------------------------------------------------}
{подпрограмма для вывода результата работы программы}
procedure Print(DynamicArray1:MyArray;sDynamicArray:MyArray;_N, _M:Integer);
var
I,J:byte;
begin;
  WriteLn('Matrix * R:');
for I:=1 to _N do
begin
for J:=1 to _M do
      Write(sDynamicArray^[I]^[J]:4);
WriteLn;
end;
end;
{--------------------------------------------------------}
{подпрограмма для освобождения памяти}
procedure FreeOutput(DynamicArray1:MyArray;sDynamicArray:MyArray;_N, _M:Integer);
var
I,J:byte;
begin;
{ Освобождаем память в обратном порядке: }
  { Сначала - удаляем все "строки" }
for I := 1 to _N do
FreeMem(DynamicArray1^[I], _N*SizeOf(MyType));
{ А теперь и указатели на них ... }
FreeMem(DynamicArray1, _N * SizeOf(MyLine));
{ Освобождаем память в обратном порядке: }
  { Сначала - удаляем все "строки" }
for I := 1 to _N do
FreeMem(sDynamicArray^[I], _N*SizeOf(MyType));
{ А теперь и указатели на них ... }
FreeMem(sDynamicArray, _N * SizeOf(MyLine));
end;
{--------------------------------------------------------}
{основная программа}
begin;
  ClrScr;
  Input(Matr,sMatr,N,M,R);
  UmnMatr(Matr,sMatr,N,M,R);
  Print(Matr,sMatr,N,M);
  FreeOutput(Matr,sMatr,N,M);
  WriteLn;
  WriteLn('Press <Enter> for exit...');
ReadLn;
end.
Ответ: Турбо Паскаля у меня нет. Проверено на fpc в режиме совместимости.

Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
Uses CRT;
const
  MAX_RANDOM_VALUE = 100;
  MAX_SIZE = 1000;
 
type
  MyType = longint;
  MyLine = ^Line;
  { "Строка" динамической матрицы }
  Line = array[1..MAX_SIZE] of MyType;
  { Сама матрица - представляется как массив указателей на "строки" }
  aArray = array[1..MAX_SIZE] of MyLine;
  MyArray = ^aArray;
 
var
  Matr, sMatr: MyArray;
  N, M, R: Integer;
{--------------------------------------------------------}
{подпрограмма для формирования матрицы}  
procedure Input(var DynamicArray1: MyArray; var sDynamicArray: MyArray; var _N, _M: Integer; var _r: integer);
var
  I, J: byte;
  code: Integer;
  s: string;
begin
  repeat
    Write('Enter the N (Integer): ');
    ReadLn(s);
    val(s, _N, code);
    if (code <> 0) or (_N < 0) then
      WriteLn('An incorrect value.');
  until (code = 0);
  repeat
    Write('Enter the M (Integer): ');
    ReadLn(s);
    val(s, _M, code);
    if (code <> 0) or (_M < 0) then
      WriteLn('An incorrect value.');
  until (code = 0);
  repeat
    Write('Enter the R (Integer): ');
    ReadLn(s);
    val(s, _r, code);
    if (code <> 0) or (_r < 0) then
      WriteLn('An incorrect value.');
  until (code = 0);
  Randomize;
   { Выделяем память под указатели на "строки" }
  new(DynamicArray1);
  { И для каждой "строки" - выделяем память для хранения данных }
  for I := 1 to _N do
    new(DynamicArray1^[I]);
  for I := 1 to _N do
    for J := 1 to _M do
      { Немного изменяется способ обращения к элементу матрицы }
      DynamicArray1^[I]^[J] := random(MAX_RANDOM_VALUE);
  WriteLn;
  WriteLn('Matrix:');
  for I := 1 to _N do
  begin
    for J := 1 to _M do
      Write(DynamicArray1^[I]^[J]:3);
    WriteLn;
  end;
end;
{--------------------------------------------------------}
{подпрограмма для умножения матрицы на число}  
procedure UmnMatr(var DynamicArray1: MyArray; var sDynamicArray: MyArray; var _N, _M: Integer; var _r: integer);
var
  I, J: byte;
begin;
  new(sDynamicArray);
  { И для каждой "строки" - выделяем память для хранения данных }
  for I := 1 to _N do
    new(sDynamicArray^[I]);
  for I := 1 to _N do
    for J := 1 to _M do
      { Немного изменяется способ обращения к элементу матрицы }
      sDynamicArray^[I]^[J] := DynamicArray1^[I]^[J] * _r;
end;
{--------------------------------------------------------}
{подпрограмма для вывода результата работы программы}
procedure Print(DynamicArray1: MyArray; sDynamicArray: MyArray; _N, _M: Integer);
var
  I, J: byte;
begin;
  WriteLn('Matrix * R:');
  for I := 1 to _N do
  begin
    for J := 1 to _M do
      Write(sDynamicArray^[I]^[J]:4);
    WriteLn;
  end;
end;
{--------------------------------------------------------}
{подпрограмма для освобождения памяти}
procedure FreeOutput(DynamicArray1: MyArray; sDynamicArray: MyArray; _N, _M: Integer);
var
  I, J: byte;
begin;
  { Освобождаем память в обратном порядке: }
    { Сначала - удаляем все "строки" }
  for I := 1 to _N do
    dispose(DynamicArray1^[I]);
  { А теперь и указатели на них ... }
  dispose(DynamicArray1);
  { Освобождаем память в обратном порядке: }
    { Сначала - удаляем все "строки" }
  for I := 1 to _N do
    dispose(sDynamicArray^[I]);
  { А теперь и указатели на них ... }
  dispose(sDynamicArray);
end;
{--------------------------------------------------------}
{основная программа}
begin;
  ClrScr;
  Input(Matr, sMatr, N, M, R);
  UmnMatr(Matr, sMatr, N, M, R);
  Print(Matr, sMatr, N, M);
  FreeOutput(Matr, sMatr, N, M);
  WriteLn;
  WriteLn('Press <Enter> for exit...');
  ReadLn;
end.
Вопрос: Вопросы начинающего - функции для работы со строковыми лексемами

Доброго времени суток, уважаемые!

На старости лет возникла необходимость переписать часть имеющихся наработок на perl/pascal на языке Си - "политика партии" поменялась, плюс кое-где возникают проблемы с производительностью. Плюс есть желание к саморазвитию. Засел опять за книги, но дело идёт туго, Си для меня оказался очень причудливым языком, в особенности в части работы со строковыми данными, а как раз обработка строк в моих программах - краеугольный камень.
Для начала попытался написать несколько функций, которые занимаются подсчетом лексем в строке, вычисляют позицию заданной лексемы в строке и извлекают из строки лексему по порядковому номеру. И вроде бы всё даже работает, но поскольку некоторые моменты работы с указателями я постиг интуитивно, хотелось бы услышать мнение более опытных программистов о качестве данного кода, какие ошибки я мог допустить, и т.п. В общем - посмотрите, пожалуйста, и прокомментируйте, что стоит изменить-исправить.
Заранее спасибо.
Да, ещё момент - возможно, я изобретаю велосипед (хотя что-то не находил пока готовых библиотек с таким функционалом) - если так, то с благодарностью приму ссылки на готовенькое-проверенное, и тем не менее, все равно прошу прокомментировать мой код - учиться-то надо...

Собственно, код:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define STR_BUFFER 256                // максимальная длина строки
#define WD " ,.:;?!\t\n\r\"\"\'"      // символы-разделители

// Функции для работы с лексемами

int wordcount(const char *str, const char *worddelim)
/*
 Возвращает число лексем в строке str, разделенных разделителями worddelim
*/
{
  int i, count, len;

  count = i = 0;
  len = strlen(str);

  while (i<=len)
    {
      while ((i<=len) && (strchr(worddelim, str[i]) != NULL)) i++; // пока текущий символ из worddelim, двигаемся к концу
      if (i<=len) count++;                                         // начало лексемы, увеличиваем счётчик лексем
      while ((i<=len) && (strchr(worddelim, str[i]) == NULL)) i++; // пока текущий символ НЕ из worddelim, двигаемся к концу
    }
  return count;
}

int wordpos(const unsigned int n, const char *str, const char *worddelim)
/*
 Возвращает позицию лексемы номер n в строке str с разделителями worddelim
 Если лексемы номер n не существует, возвращает -1
*/
{
  int i, count, len;

  count = i = 0;
  len = strlen(str);

  while ((i<=len) && (count != n))
    {
      while ((i<=len) && (strchr(worddelim, str[i]) != NULL)) i++;   // пока текущий символ из worddelim, двигаемся к концу
      if (i<=len) count++;                                           // начало лексемы, увеличиваем счётчик лексем
      if (count != n)                                                // если это не лексема номер n - ищем следующую.
        while ((i<=len) && (strchr(worddelim, str[i]) == NULL)) i++; // пока текущий символ НЕ из worddelim, двигаемся к концу
      else
        return i;                                                    // это лексема номер n - возвращаем её позицию
    }
  return -1;                                                         // нет лексемы с номером n - возвращаем -1
}

char *extractword(const unsigned int n, char *str, char *worddelim)
/*
 Извлекает лексему номер n из строки str с разделителями worddelim и возвращает указатель на нее
 Если лексемы номер n нет, возвращает NULL
*/
{
  int i, j, len;
  char *word;

  word = NULL;
  len = strlen(str);
  i = wordpos(n, str, worddelim); // ищем позицию лексемы номер n

  if (i == -1) return word;      // лексемы номер n нет - возвращаем NULL

  if (wordpos(n+1, str, worddelim) != -1) j = wordpos(n+1, str, worddelim)-i; 
  // лексема не последняя - ее длина равна позиция следующей лексемы минус позиция искомой лексемы
  else j = len - i;
  // лексема последняя - ее длина равна длина строки минус позиция искомой лексемы

  word = (char *) calloc(j+1, sizeof(char)); // выделяем память под искомую лексему - длина лексемы плюс '\0'
  j = 0;
  while ((i<len) && (strchr(worddelim, str[i]) == NULL)) word[j++] = str[i++]; 
  word[strlen(word)] = '\0'; // копируем лексему из строки str во временную переменную word и завершаем ее '\0'
  return word;
}

// Проверяем, как это работает

int main()
{
  int i, wcount;
  char *s, *d1;

  s = (char *) calloc(STR_BUFFER, sizeof(char));
  d1 = (char *) calloc(STR_BUFFER, sizeof(char));

  strncpy(s, "Hello, my crazy world!", STR_BUFFER);
  printf(" String - \"%s\", delimeters - \"%s\"\n\n", s, WD);

  wcount = wordcount(s, WD);
  printf(" Word count - %u\n\n", wcount);

  for (i = 1; i <= 5; i++)
  {
    printf(" Word number %i start position - %i\n", i, wordpos(i, s, WD));
  }
  printf("\n");

  for (i = 1; i <= wcount; i++)
  {
    d1 = extractword(i, s, ". ");
    printf(" Word number %d - %s\n", i, d1);
  }

  free(s); free(d1);

  return 0;
}


Результат:

String - "Hello, my crazy world!", delimeters - " ,.:;?!
""'"

Word count - 4

Word number 1 start position - 0
Word number 2 start position - 7
Word number 3 start position - 10
Word number 4 start position - 16
Word number 5 start position - -1

Word number 1 - Hello,
Word number 2 - my
Word number 3 - crazy
Word number 4 - world!

Ответ:
Dima T
Выше уже написали что на лицо полное непонимание как это устроено. Если выделил память, то нельзя ее освобождать пока она используется (она используется т.к. ты возвращаешь на нее указатель), иначе либо вылетит при обращении к несуществующей памяти (в лучшем случае), либо память будет занята чем-то другим, а твой код это не поймет (такое вообще устанешь отлавливать).

Не серчайте, уважаемый. Я действительно пока плохо понимаю, как всё это работает, но хочу разобраться.
Dima T
Надо завести четкое правило где выделять память и где освобождать. Проще и понятнее это делать на вызывающей стороне, т.е. у тебя в main(), т.е. в твоих extractwordX() не должно быть ни calloc() ни free()

Тогда так. Буду пояснять, что именно я делаю, так будет виднее, понял ли я суть или нет.

1. Внутри функции объявим массив символов char s[STR_BUFFER], и туда будем копировать разбираемую строку.
Это будет массив локальный, под него память будет выделена статически, и после выхода из функции эта память будет освобождена автоматом (в принципе, как я понимаю, тут можно и malloc/calloc использовать, главное потом перед выходом из функции не забыть про free - правильно?)

2. Указатель на первый элемент этого массива (правильно говорить именно так, а не "указатель на эту строку" - верно?) будем передавать strtok, а возвращаемый ей указатель присвоим в качестве значения указателю word, который объявлен в теле основной программы и где ему же выделена память. (Тут, наверное, тоже можно использовать массив символов char word[STR_BUFFER], насколько я понимаю, если нам не важно экономить память в ходе выполнения программы)?

3. В теле основной программы calloc'ом выделяем память под разбираемую строку и лексемы (s и word) и затем вызываем функцию извлечения лексем. В заключении освобождаем память, выделенную для исходной строки и лексемы.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define WD " "
#define STR_BUFFER 256

void extractword4(char *word, const unsigned int n, const char *str, const char *worddelim)
{
  int i = 2;
  char s[STR_BUFFER]; // сюда поместим копию разбираемой строки
  char *p;

  // делаем локальную копию разбираемой строки
  strcpy(s, str);

  // получаем указатель на первую лексему
  p = strtok(s, worddelim); 
  // если нам нужна не первая лексема
  if (n != 1) 
    while ( i <= n && p != NULL ) 
    // перебираем, пока не дойдём до нужного номера или пока не кончатся лексемы
    {
      p = strtok(NULL, worddelim);
      i++;
    }
  // Если n-ая лексема найдена, копируем ее в буфер, переданный в функцию, иначе заносим туда \0
  if ( p != NULL) strcpy(word, p); else *word = '\0';
  return;
}

int main()
{
  char *s, *word;

  word = (char *) calloc(STR_BUFFER, sizeof(char));
  s = (char *) calloc(STR_BUFFER, sizeof(char));

  strncpy(s, "Hello, my crazy world!", STR_BUFFER);

  printf("\n tst3, String - %s\n", s);

  extractword4(word, 1, s, WD);
  printf(" Word #1 '%s' - %i\n", word, *word);
  extractword4(word, 2, s, WD);
  printf(" Word #2 '%s' - %i\n", word, *word);
  extractword4(word, 4, s, WD);
  printf(" Word #4 '%s' - %i\n", word, *word);
  extractword4(word, 6, s, WD);
  printf(" Word #6 '%s' - %i\n", word, *word);
  free(word); free(s);
  return 0;
}

Что теперь скажете?
Вопрос: Работа с (char *)

Здравствуйте.

При работе с (char *) появился вопрос, когда надо освобождать ресурс, а когда нет.
Понятно, что после malloc()/calloc()/realloc() необходимо вызывать free(), но если мы инициализируем указатель так:
C
1
2
3
4
{
char *str1 = "string_1";
char str2[] = "string_2";
}
то получается, это указатели на 2 строки, значение указателей в стеке, а содержимое строк в куче? После выхода из блока указатели уничтожаются, а выделенная под строки память разыменовывается автоматически? Почему в данном случае не нужно вызывать free()?

Могу ли я передать, например, строку str1 наружу?
C
1
2
3
4
5
6
7
8
9
10
char *func()
{
char *str1 = "string_1";
return str1; // я возвращаю указатель на строку, но не будет ли затерта выделенная под строку память вне функции func()?
}
 
int main()
{
char *s = func();
}
Такая передача строки из функции func() безопасна? Или строка по указателю s может затереться при работе далее?
Ответ:
Сообщение от dexterov
Такая передача строки из функции func() безопасна? Или строка по указателю s может затереться при работе далее?
Строки, которые ты пишешь в коде своей программе, как, например, "string_1", во время компиляции будут размещаться в специальном сегменте программы, доступной только для чтения. Поэтому корректнее будет
C
1
2
3
4
5
const char *func()
{
const char *str1 = "string_1";
return str1; // я возвращаю указатель на строку, но не будет ли затерта выделенная под строку память вне функции func()?
}
что бы не было проблем в рантайме, если захочешь в эту строку что-нибудь написать.
А вот со строкой
C
1
char str2[] = "string_2";
Есть проблемы, ибо эта строка создается на стеке и при выходе из функции будет потерта.
Вопрос: Как ускорить поиск строки в строке?

задача: в тексте (75000 символов) найти нужное слово и вернуть все правильные результаты, ключевое - чтобы быстро работало, а вот тут и проблема.
Как делаю я - если коротко - сравниваю кусок текста с искомым словом - через for, и так от 0 до почти конца текста, где то 75000 раз.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
DateTime now = DateTime::Now;   //запрос текущего времени для определения времени начала работы
label1->Text = now.ToString();      //запомнили время начала работы
int n, n1; 
String^ s1;
String^ s = textBox1->Text->ToString(); //присвоили искомое слово
n =  richTextBox1->Text->Length;        //длинна текста в котором ищем
n1 = s->Length;                 //длинна искомого слова
     for (int i = 0; i < n - n1; i++)   //от 0 до конца массива за исключением конца текста равного длине искомого слова
    {
      if (richTextBox1->Text->Substring(i,n1) == s ) //сравнваем кусок текста с искомым словом
        {
                      listBox1->Items->Add(i+" "+richTextBox1->Text->Substring(i,n1); //если да то присвоить ответ - номер 1го элемента и найденное
        }
    }
DateTime now = DateTime::Now;   //запрос текущего времени для определения времени окончания работы
label2->Text = now.ToString();      //запомнили время окончания работы
Не устраивает время работы - от 2м38сек до 2м40сек, бывало даже 2м58сек (AMD A4-3305M 1.9 ГГц на едро из 2, и 6Гб ОЗУ - не современно но дышит и тянет). Хотя текст на 3500 символов проверяется меньше секунды, и по идее текст в 22 раз больше (75000 символов) должен обрабатываться секунды за 22, но по факту времени уходит в 7 раз больше расчётного.

Вопрос 1: как ускорить поиск? Может есть готовая функция в каком нибудь Memo, которую я не могу найти? Хотелось бы уложиться секунд в 30 на 1 прогон.

Вопрос 2 (не особо важно, но любопытно): почему время на обработку увеличилось не прямо пропорционально объему текста? Объём увеличился в 22 раза, а время в 160 раз.

Добавлено через 4 часа 21 минуту
Попробую перефразировать вопрос:
Когда речь о поиске в 100,000 символов есть ли готовые простые / встроенные функции / методы поиска, или нужно изучать сложные методы / алгоритмы типа алгоритма Кнута, Морриса и Пратта, алгоритм Боуера и Мара?? Если да то какие более быстрые?
Ответ:
Сообщение от my_name_123
rtbText это просто название переменной? не на что не влияющие?
Да. Да.

Сообщение от my_name_123
Можешь объяснить по ВСЕМ параметрам функции String::Compare(rtbText, i, s, 0, n1) == 0 ), или их всего 5 и все представлены .
Метод Compare позволяет сравнить две строки чтобы узнать равны ли они или одна больше/меньше другой. В данном случае мы используем перегрузку которая позволяет сравнить части двух строк. Аргументы следующие:
  • rtbText - первая строка
  • i - позиция внутри первой строки с которой нужно начать сравнение
  • s - вторая строка
  • 0 - позиция внутри второй строки с которой нужно начать сравнение. 0 очевидно означает начало
  • n1 - количество символов которое нужно сравнить

Сообщение от my_name_123
Я не нашёл нормального пояснения
читал?
Вопрос: Сравнить строки между собой в txt документе

Всем доброго времени суток. Помогите пожалуйста решить проблему. Имеется текстовый документ, который выглядит следующим образом:

Код:

55001.002      0.000     0.000     0.000     0.000     0.000     0.000 
55002.002      0.000     0.000     0.000     1.050     0.600     0.050 
55003.002      0.015     0.000     0.000     0.000     0.000     0.000 
55004.002      0.000     0.000     0.011     0.000     0.000     0.000 
55005.002      0.000     0.000     0.000     0.000     0.000     0.600 
55006.002      1.030     2.050     4.040     1.060     1.060     1.050 
55007.002      1.030     0.040     3.010     1.060     0.070     1.050 
55008.002      0.000     0.000     0.000     0.000     0.000     0.000 
55009.002      4.650     1.132     2.002     1.001     4.041     3.004 
55010.002      0.000     0.000     0.012     0.566     0.000     0.000

и т.д. Необходимо удалить те строки, в которых присутствует значение 0.000 и одинаковые значения в столбцах с предыдущей строкой, то есть из приведенного примера должна остаться только одна строчка:

Код:

55009.002      4.650     1.132     2.002     1.001     4.041     3.004

Удаление нулей я сделал, но вот строки, которые частично совпадают не могу удалить, делаю так:

Код:

procedure TForm1.Button1Click(Sender: TObject);
 var
 F1, F2: TStringList;
 i: integer;
 tmp: string;
 begin
  F1 := TStringList.Create;
  try
  F2 := TStringList.Create;
  try
  F1.LoadFromFile('file1.txt');
  for i := 0 to F1.Count - 1 do
  begin
    tmp := F1[i];
    if F2.IndexOf(tmp) = -1 then
    F2.Add(tmp);
  end;
  F2.SaveToFile('file2.txt');
  finally
  F2.Free;
 end;
 finally
 F1.Free;
 end;
 end;

Но т.к. строки не полностью совпадают, соответственно удаление не происходит. Как сравнить строки по столбцам между собой и удалить строки, если значение в столбце совпадает с предыдущей строкой? Спасибо



________
Код нужно оформлять по правилам:
тегом [CODE]..[/СODE]
(это кнопочка на панели форматирования с решёточкой #)
Не забывайте об этом!

Модератор.
Ответ:
Код:

procedure Button1Click(Sender: TObject);
const
  MaskColumn: string = '      ';
  ArIskl: array [0 .. 0] of string = ('0.000');
var
 FListStart: TStringList;
 FListRow1: TStringList;
 FListRow2: TStringList;
 FListResult: TStringList;
 j, RowS: integer;
 ResultBool: Boolean;
begin
  try
    FListStart := TStringList.Create;
    FListRow1 := TStringList.Create;
    FListRow2 := TStringList.Create;
    FListResult := TStringList.Create;
    FListResult.Clear;
    FListStart.LoadFromFile('D:\1.txt');
    RowS := 0;
    while pos('  ',FListStart.Text) <> 0 do   { Приводим к виду для использования разделителя}
    FListStart.Text := StringReplace(FListStart.Text,'  ',' ',[rfReplaceAll]);
    while RowS <= FListStart.Count - 1 do
    begin
      ResultBool := False; { Обнуляем переменную }
      FListRow1.Delimiter := ' '; { Разделитель }
      FListRow2.Delimiter := ' '; { Разделитель }
      FListRow1.DelimitedText := FListStart[RowS];
      FListRow2.Text := '';
      { Проверка добавляемой строки на наличие исключений }
      for j := 0 to FListRow1.Count - 1 do
        if MatchStr(FListRow1[j],ArIskl)  then
        ResultBool := True;
      { Исключений НЕТ}
      if ResultBool = False then
      begin
        ResultBool := False; { Обнуляем переменную }
        if RowS <> (FListStart.Count - 1) then
        FListRow2.DelimitedText := FListStart[RowS + 1]; { Берем следующую строку, если она есть}
        { сравниваем строки }
        if FListRow2.Count > 0 then
        for j := 0 to FListRow1.Count - 1 do
        if (FListRow1[j] = FListRow2[j]) then
        begin
          ResultBool := True;
          Break;
        end;
        { Все условя соблюдены, добавляем в результат}
        if ResultBool = False then
          FListResult.Add(FListStart[RowS]);
        RowS := RowS + 1; { Увеличиваем на 1, чтобы не сравнивать следующую строку после добавленой!!! Тут есть ньюанс! 
   Если этого не делать то ПО добавит  строку с 55007.002, ИМХО следующая строка не будет равна предыдущей и вроде бы как надо добавить эту строку.
 Тут либо вами условие поставлено не правльно, либо все таки в результате должно быть 2 строки}
      end;
      RowS := RowS + 1;
    end;
  finally
    FreeAndNil(FListStart);
    FreeAndNil(FListRow1);
    FreeAndNil(FListRow2);
    FListResult.Text :=  StringReplace(FListResult.Text,' ',MaskColumn,[rfReplaceAll]);;
    ShowMessage(FListResult.Text);
    //FreeAndNil(FListResult);
  end;
end;

Для работы MatchStr требуется в блок Uses добавить StrUtils
Для работы StringReplace требуется в блок Uses добавить SysUtils
Для работы TStringList требуется в блок Uses добавить System.Classes

P/S
Для понимания, я вам расписал все по разным листам. В идеале весь код можно сильно сократить, используя 2 листа и метод удаления строки.
Вопрос: В Entity Framework отмена изменений в БД, раздельное сохранение, работа с промежуточной таблицей

Entity Framework используется вместе с Windows Forms.
Привязка к DataGridView и TextBox-ам сделана через employeeBindingSource который:
C#
1
2
db.Employee.Load();
employeeBindingSource.DataSource = db.Employee.Local;
где db это контекст модели и глобальная переменная.
Далее предусмотрено добавление новых строк:
C#
1
employeeBindingSource.AddNew();
Отмена изменений:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var changed = db.ChangeTracker.Entries().Where(x => x.State != EntityState.Unchanged).ToList();
foreach (var obj in changed)
{
    switch (obj.State)
    {
        case EntityState.Modified:
            obj.CurrentValues.SetValues(obj.OriginalValues);
            obj.State = EntityState.Unchanged;
            break;
        case EntityState.Added:
            obj.State = EntityState.Detached;
            break;
        case EntityState.Deleted:
            obj.State = EntityState.Unchanged;
            break;
    }
}
employeeBindingSource.ResetBindings(false);
И фильтрация:
C#
1
employeeBindingSource.DataSource = db.Employee.Where(x => x.EmployeeId.ToString().Contains(textBox1.Text) && x.Surname.Contains(textBox2.Text)).ToList();
Как только отрабатывает фильтрация добавленные строки перестают удаляться при отмене изменений.
  1. А почему? Как это исправить?
  2. Сохранение изменений через db.SaveChanges(); это прикольно, но если на форме есть несколько таблиц, то это сохранит их все и не позволит откатывать изменения для каждой отдельно. Можно с этим что-то сделать? То, что при изменении одной таблицы правятся и соседние при работе не очевидно и как-то странно…
  3. Как поместить данные из связанной таблицы (имя параметра, а не его Id) в DataGridView, в отдельный DataGridViewComboBoxColumn и как с этим работать понятно, но как быть если между текущей и целевой таблицей есть промежуточная? Без DataGridView в принципе понятно, вручную ищем данные в промежуточной таблице, если их нет – добавляем, если они есть, выбираем нужную запись в промежуточной таблице. А вот как это вставить в DataGridView красиво в виде ComboBox? Как эти данные привязать?
Ответ:
Сообщение от t7000
Как сделать фильтрацию правильно и сохранить после неё возможность откатить создание новой записи, так и не понял…
Фильтрация (Select .. where ..) штука опасная при редактировании в гриде. Если, например, установлена фильтрация по фамилиям "Ива..", и юзер изменил фамилию в одной из строк на "Петров", то эта запись из грида просто пропадет. Это и произойдет при подтверждении изменений (SaveChanges) и последующей перечитке НД с сервера.

Фильтрацию нужно делать иначе, определив правила интерфейса. Например, есть телефонный справочник по предприятию. И есть возможность выборки абонентов по подразделениям с помощью например TreeView админструктуры.
Фильтрация по колонкам, как правило, успешно реализуется на клиенте путем "прятания" не подпадающих в фильтр строк.
Я бы не советовал использовать сплошную фильтрацию (как у Вас) в комбинации с правками в гриде. Для удобной работы с сеткой обычно применяется сортировка (Select .. order by..). Опять же любые манипуляции с датестом (сортировки, фильтры) делать только после фиксации накопившихся изменений. В случае с модальной формой-строкой эта проблема просто не возникает.

Сообщение от t7000
Если правильно понял, автоматическая привязка это только к соседней таблице. Если нужно проникать дальше, то всё нужно делать ручками ну и сразу всё сохранять…
Неправильно поняли. Есть такая штука "бизнес-логика сервера", в которой инкапсулированы правила, по которым организовано хранение всех данных в базе. Например, при снятии денег с карточки одного клиента эта сумма должна попадать на карточку другого клиента (классический пример). Т.е. изменение в одной записи таблицы автоматически должно приводить к изменению другой. Где реализована эта БЛ - на сервере (правильно) или на клиенте (сомнительно) - дело разработчика.
Можно, к примеру, реализовать это на сервере через триггер или SP
В первом случае изменять запись в датасете можно,- триггер автоматически изменит другую, зависимую запись. Но перечитать НД и обновить грид нужно обязательно !
Во втором в датасете вообще ничего менять не следует, нужно забирать новые значения и передавать их как параметры в соответствкющую SP. После чего опять же перечитывать датасет в гриде.

А можно все реализовать на клиенте. Но придется писать много кода для внесения правок как в "гридную" таблицу, так и в "сопутствующую" таблицу. При этом нужно все это аккуратно заворачивать в одну транзакцию, обрабатывать исключения и т.д.
И EF в этом деле Вам ничем не поможет ибо он розового понятия не имеет о Ваших "правилах" - ведь на сервере нет ничего - все у Вас в коде.

Добавлено через 14 минут
Резюмируем: в Вашем случае есть два надежных пути реализации задачи.

1. Делать все "по правилам", т.е. за раз правка только одной записи. Чтобы не было традиционных модальных форм модалка реализуется "искусственно" как было указано выше. При этом пользователь не заметит никаких изменений визуально, грид редактируется "как в Экселе".

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