powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Вопросы начинающего - функции для работы со строковыми лексемами
73 сообщений из 73, показаны все 3 страниц
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955197
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Доброго времени суток, уважаемые!

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

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

Код: plaintext
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.
#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!
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955213
YesSql
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Andrey Vahromkin,

есть готовая функция в стандартной библиотеке C/C++ strtok
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955378
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
YesSqlесть готовая функция в стандартной библиотеке C/C++ strtok
Благодарю, о наличии этой функции я знаю, здесь я сознательно пошёл на изобретение велосипеда, дабы лучше понять принципы работы с указателями и строками.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955391
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Для работы с strtok я написал вот такую обертку:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
char *extractword2(const unsigned int n, char *str, char *worddelim)
/*
 Извлекает лексему номер n из строки str с разделителями worddelim с помощью strtok и возвращает указатель на нее
 Если лексемы номер n нет, возвращает NULL
*/
{
  int i;
  char *s, *word;

  s = strdup(str);
  word = strtok(s, worddelim);
  if (n == 1) return word;
  for (i = 2; i <= n; i++) word = strtok(NULL, worddelim);
  return word;
}


И кстати, здесь у меня появился ещё один вопрос: я правильно понимаю - все объявленные внутри функции переменные и выделяемая им память после выхода из функции уничтожаются автоматически, а вся распределенная память также автоматически освобождается и в вызовах free перед выходом из функции нет нужды?
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955403
YesSql
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Andrey Vahromkin,

А что делает эта обертка? Кроме того что повторяет одно и то же. Зачем она нужна?
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955404
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey Vahromkinдабы лучше понять принципы работы с указателями и строками.

Дабы понять принципы работы с указателями, достаточно иметь представление об устройстве
оперативной памяти хотя бы на школьном уровне: в виде ряда пронумерованных коробочек.
Указатель это и есть коробочка, хранящая номер другой коробочки.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955416
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
YesSqlА что делает эта обертка? Кроме того что повторяет одно и то же. Зачем она нужна?
Мне кажется, это самоочевидно.
Допустим, нужно извлечь из строки source "aaa bbb ccc ddd eee" вторую и четвертую лексему.
Это можно сделать так:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
  int i;
  char *source, *w1, *w2, *s;
  [...]
  s = strdup(source);
  w1 = strtok(s, worddelim);
  w1 = strtok(NULL, worddelim);

  s = strdup(source);
  w2 = strtok(s, worddelim);
  for (i = 2; i<=4; i++) 
    w2 = strtok(NULL, worddelim);


Или так:
Код: plaintext
1.
2.
3.
4.
5.
  int i;
  char *source, *w1, *w2;

  w1 = extractword2(2, source, worddelim);
  w2 = extractword2(4, source, worddelim);



Второй вариант с функцией-оберткой над strtok _мне_ нравится больше. Потому что строка может быть существенно длиннее, и нужно извлекать из нее не 2, а 12 слов.
Если вы считаете, что лучше первый вариант - поясните, почему...

Dimitry Sibiryakov Дабы понять принципы работы с указателями, достаточно иметь представление об устройстве
оперативной памяти хотя бы на школьном уровне
Практика написания программ на Си _очень_ отличается от практики паскаля и даже Перла... Мне пока _очень_ сложно работать со строками на Си.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955417
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey VahromkinПрактика написания программ на Си _очень_ отличается от практики
паскаля и даже Перла.
Это потому, что в Си нет строк.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955419
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dimitry SibiryakovAndrey VahromkinПрактика написания программ на Си _очень_ отличается от практики
паскаля и даже Перла.
Это потому, что в Си нет строк.

Да, я заметил.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955422
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey VahromkinИ кстати, здесь у меня появился ещё один вопрос: я правильно понимаю - все объявленные внутри функции переменные и выделяемая им память после выхода из функции уничтожаются автоматически, а вся распределенная память также автоматически освобождается и в вызовах free перед выходом из функции нет нужды?
Нет. Неправильно поняли.
Если вы выделили память напрямую через malloc() или неявно через одну из стандартных функций (например strdup и многие другие - см. доки соотв. функций) то и удалять ее надо через free() вручную.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955427
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Anatoly MoskovskyЕсли вы выделили память напрямую через malloc() или неявно через одну из стандартных функций (например strdup и многие другие - см. доки соотв. функций) то и удалять ее надо через free() вручную.
Вот эти-то моменты у меня как раз и вызывают кучу недоумений. Которые не укладываются в нумерованные коробочки, о которых говорил Dimitry Sibiryakov.
Вот я объявляю в функции переменные:
Код: plaintext
1.
  char *s, *word;


Вот им неявно выделяют память
Код: plaintext
1.
2.
  s = strdup(str);
  word = strtok(s, worddelim);


А перед выходом память нужно вернуть. С s проблем нет
Код: plaintext
1.
2.
  free(s);
  return word;


А что теперь делать с word? После return вызывать free(word) бессмысленно, до - получим вместо результата бог знает что, и программа, скорее всего, вывалится с ошибкой. И как быть?
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955432
egorych
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey VahromkinИ как быть?прибить память после вызова функции extractword2
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955436
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey VahromkinВот эти-то моменты у меня как раз и вызывают кучу недоумений.
Которые не укладываются в нумерованные коробочки, о которых говорил Dimitry Sibiryakov.
И что там тебя не укладывается? Представь, что malloc пишет на коробочках твоё имя, а free
- его стирает. Оставлять коробочки подписанными, когда они тебе уже не нужны - нехорошо.
Класть или доставать что-то из неподписанных коробочек - нехорошо вдвойне.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955440
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey VahromkinА что теперь делать с word?
strtok не выделяет память - поэтому ничего не делать.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955441
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
И возвращать word тоже нельзя. Т.к. он указывает в память которую вы только что удалили.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955442
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
К счастью, есть одно простое и эффективное решение всех этих вопросов.
Пишите на С++ и не используйте строк в массивах char, а применяйте std::string.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955447
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
egorychприбить память после вызова функции extractword2
Как? Переменная объявлена внутри функции, и в вызывающей её программе она недоступна.
Dimitry SibiryakovИ что там тебя не укладывается?
Вот все это и не укладывается.
Я вошел из комнаты в кладовку и подписал 2 коробочки - s и word -правильно?
И положил что-то в эти коробочки. А потом коробочка s мне стала не нужна, и я говорю - free(s), то бишь, стираю с нее свое имя.
А дальше - то, что хранится в коробочке word мне надо как-то передать из кладовки в комнату - для этого я делаю return word в конце функции.
Теперь с коробочки word надо стереть имя, правильно? А как это сделать? Если до return - я потеряю содержимое коробочки, если после return - коробочка будет уже недоступна.
А тут мне ещё и говорят, что strtok работает как-то совсем иначе, чем я представлял... Я уже окончательно запутался.
Anatoly Moskovskystrtok не выделяет память - поэтому ничего не делать. И возвращать word тоже нельзя. Т.к. он указывает в память которую вы только что удалили.

Так, минуточку. Будьте добры - чуть подробнее.
strtok возвращает указатель на последнюю найденную лексему в строке - правильно? Раз есть указатель - значит, есть кусочек памяти на который он указывает, и эта память была как-то кем-то выделена - правильно? Или где же сама эта лексема тогда размещается?
Anatoly MoskovskyИ возвращать word тоже нельзя. Т.к. он указывает в память которую вы только что удалили.

Опять не понял - что я удалил, и где?
Anatoly MoskovskyПишите на С++
Да, возможно, это выход, но я сначала со своими примерами разобраться хочу... А то, чувствую, с c++ я тоже не подружусь, если сейчас все эти непонятки не проясню для себя.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955451
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Так, кажется, я понял свою ошибку - нельзя из функции возвращать адрес локальной переменной, по той самой причине, что сам и называл - переменная локальная и при выходе из функции она будет уничтожена. Правильно?
Теперь пытаюсь понять, как мне всё-таки вернуть из функции желаемое...
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955458
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey VahromkinА тут мне ещё и говорят, что strtok работает как-то совсем иначе,
чем я представлял...
Потому что не надо представлять. Её работа в деталях описана, например, на
http://en.cppreference.com/w/c/string/byte/strtok
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955539
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey VahromkinОпять не понял - что я удалил, и где?
Код: plaintext
1.
2.
3.
  word = strtok(s, worddelim);
  free(s);
  return word;


Ну вот же.
strtok возвращает указатель внутрь буфера на который указывает s, который вы присваиваете в word.
А потом удаляется память буфера s, и word теперь указывает вникуда
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955565
YesSql
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Andrey VahromkinYesSqlА что делает эта обертка? Кроме того что повторяет одно и то же. Зачем она нужна?
Мне кажется, это самоочевидно.
Допустим, нужно извлечь из строки source "aaa bbb ccc ddd eee" вторую и четвертую лексему.

Допустим у вас текст на 100К и вы хотите 100500 лексему, а затем 100501 лексему.
.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955826
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Значит, на данный момент я понял, что для возврата строки из функции нужно либо в функции выделить память под нее и потом можно возвращать указатель на эту область памяти (как раз это я и делал в варианте extractword без использования strtok):
Код: plaintext
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.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define WD " "
#define STR_BUFFER 256

char *extractword2(const unsigned int n, const char *str, const char *worddelim)
{
  int i;
  char *s, *word;

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

  word = strtok(s, worddelim);
  if (n != 1)
    for (i = 2; i <= n; i++) word = strtok(NULL, worddelim);

  printf("[extractword2] Word '%s' - %i\n", word, *word);

  free(s);
  return word;
}

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

  s = (char *) calloc(STR_BUFFER, sizeof(char));
  strncpy(s, "Hello, my crazy world!", STR_BUFFER);

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

  word = extractword2(2, s, WD);
  printf("Word #2 '%s' - %i\n", word, *word);
  free(word);

  word = extractword2(4, s, WD);
  printf("Word #4 '%s' - %i\n", word, *word);
  free(word);

  return 0;
}


Либо нужно предварительно выделить память, а в функцию передать указатель на эту выделенную область, чтобы функция помещала результат в нее:
Код: plaintext
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.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define WD " "
#define STR_BUFFER 256

void extractword3(const unsigned int n, const char *str, const char *worddelim, char **result)
{
  int i;
  char *s;

  s = (char *) calloc(STR_BUFFER, sizeof(char));
  strncpy(s, str, STR_BUFFER);

  *result = strtok(s, worddelim);
  if (n != 1)
    for (i = 2; i <= n; i++) *result = strtok(NULL, worddelim);
  printf("[extractword3] Word '%s' - %i\n", *result, **result);

  free(s);
}

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

  s = (char *) calloc(STR_BUFFER, sizeof(char));
  strncpy(s, "Hello, my crazy world!", STR_BUFFER);

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

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

  extractword3(2, s, WD, &word);
  printf("Word #2 - '%s' %i\n", word, *word);

  extractword3(4, s, WD, &word);
  printf("Word #4 - '%s' %i\n", word, *word);

  free(word);
  return 0;
}


Правильно ли я все понял? Какой вариант предпочтительнее? Мне extractword3 кажется нагляднее - после extractword2 следует вызов free, причина которого неочевидна...

Еще вопрос. Сначала в функциях extractword2 и extarctword3 вместо конструкции
Код: plaintext
1.
2.
3.
4.
  s = (char *) calloc(STR_BUFFER, sizeof(char));
  strncpy(s, str, STR_BUFFER);
...
  free(s);  


я использовал
Код: plaintext
1.
2.
3.
  s = strdup(str);
...
  free(s);


Но с использованием strdup программа падала в кору при втором вызове extractword2/extarctword3
Почему?? Я же явно освобождаю выделенную ею память перед выходом из функции. С calloc/strncpy все работает так, как должно...
Спасибо всем за терпение.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955924
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
extractword2() это бред. Ты выделил память, туда скопировал, чего-то там поделал и память освободил, но пытаешься вернуть указатель на кусок уже освобожденной памяти. Кроме того выделил память под word и проимел указатель на эту память, т.е. утечка памяти.
extractword3() тоже бред, но без утечки.

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

Надо завести четкое правило где выделять память и где освобождать. Проще и понятнее это делать на вызывающей стороне, т.е. у тебя в main(), т.е. в твоих extractwordX() не должно быть ни calloc() ни free()
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38955997
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima Textractword2() это бред. Ты выделил память, туда скопировал, чего-то там поделал и память освободил, но пытаешься вернуть указатель на кусок уже освобожденной памяти. Кроме того выделил память под word и проимел указатель на эту память, т.е. утечка памяти.
extractword3() тоже бред, но без утечки.

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

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

Это хороший совет, попробуйте сделать так
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956266
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
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) и затем вызываем функцию извлечения лексем. В заключении освобождаем память, выделенную для исходной строки и лексемы.

Код: plaintext
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.
#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;
}


Что теперь скажете?
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956276
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey VahromkinЧто теперь скажете?
Что ты так и не прочитал принципы работы strtok по ссылке, приведённой выше.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956289
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dimitry SibiryakovAndrey VahromkinЧто теперь скажете?
Что ты так и не прочитал принципы работы strtok по ссылке, приведённой выше.

Уважаемый, я неоднократно читал описание данной функции и по вашей ссылке, и в других источниках.
Возможно, я что-то не понял из прочитанного, но нам обоим было бы проще, если бы вы (раз уж находите время мне отвечать) отвечали бы несколько более развернуто.
В чем именно состоит моя ошибка?
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956380
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey VahromkinВ чем именно состоит моя ошибка?
В том, что Вы сделали алгоритм сложности O(N^2) вместо O(N). От утечек памяти Вы, конечно,
избавились, но использование strncpy преподнесёт вам очень неприятный сюрприз если входная
строка окажется длиннее буфера. На этом фоне пара избыточных проверок и копирований
туда-сюда уже сущие мелочи.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956407
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вархомкин. Strtok - это statefull функция. Конечный автомат по сути. А ты с ней пытаешся работать как со stateless.
В этом твой неверный подход. А всё остальное - это уже "сопуствующие мелочи".
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956415
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dimitry SibiryakovВ том, что Вы сделали алгоритм сложности O(N^2) вместо O(N). От утечек памяти Вы, конечно,
избавились, но использование strncpy преподнесёт вам очень неприятный сюрприз если входная
строка окажется длиннее буфера.
Ну strncpy я поначалу действительно принял за "безопасную" версию strcpy, однако позже узнал, что её следует либо заменить на strlcpy, либо использовать в сочетании с дополнительными проверками на нуль-терминирование копируемой строки. Однако в рамках данного вопроса не посчитал нужным что-то пока менять в этом направлении. Коварные особенности этой функции, тем не менее, держу в уме.
Dimitry SibiryakovНа этом фоне пара избыточных проверок и копирований туда-сюда уже сущие мелочи.
К сожалению, пока не понимаю, что именно избыточно... пока сам ищу и думаю...
maytonВархомкин.
Вахромкин :)
maytonStrtok - это statefull функция. Конечный автомат по сути. А ты с ней пытаешся работать как со stateless.
В этом твой неверный подход. А всё остальное - это уже "сопуствующие мелочи".
Будьте снисходительны, я с Си познакомился неделю назад от силы.
Можно то же самое, но по-русски?
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956418
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey VahromkinЧто теперь скажете?
Так работать будет, но медленно.
Andrey Vahromkin1. Внутри функции объявим массив символов char s[STR_BUFFER], и туда будем копировать разбираемую строку.
Это будет массив локальный, под него память будет выделена статически, и после выхода из функции эта память будет освобождена автоматом (в принципе, как я понимаю, тут можно и malloc/calloc использовать, главное потом перед выходом из функции не забыть про free - правильно?)
Сейчас правильно. Указатель на освобожденную память отсутствует, т.к. место ты выделил в main() (word = ...), выше косяк был именно в этом.
malloc/free тут тоже можно, но char s[STR_BUFFER] отработает быстрее.

Код уже рабочий, но наихудший по все параметрам. Все тормоза тут из-за копирования строки. Зачем? Она уже в памяти. Ищи разделитель и копируй в word только нужный кусок.

Еще в коде отсутствует проверка размеров буферов, т.е. если строка или слово будет более STR_BUFFER-1 символов, то вылезешь за пределы массивов. Это уже потенциальный косяк.

Если пишешь в целях самообучения указателям, то зачем использовать функции str...() ? Достаточно только указателей. Поизучай этот код.
Код: plaintext
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.
// Получение первого слова
// параметры: буфер для сохранения результата, размер буфера, исходная строка, символ разделитель
// возвращает указатель на разделитель после слова
const char* firstword(char *word, const int size, const char *str, char delim)
{
	char* end = word + size - 1; // указатель на последний элемент буфера
	while(*str != 0 && *str == delim) str++; // пропуск разделителей в начале строки
	// копирование первого слова
	while(word < end && *str != 0 && *str != delim) {
		*word = *str;
		word++;
		str++;
	}
	*word = 0;
	return str;
}

int main()
{
	char s[] = "  Hello, my   crazy world! ";
	char word[STR_BUFFER];
	const char* p = s;
	int i = 0;
	while(true) {
		p = firstword(word, STR_BUFFER, p, ' ');
		if(*word == 0) break;
		i++;
		printf("%d. '%s'\n", i, word);
	};

	system("pause");
	return 0;
}

...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956425
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey VahromkinЧто теперь скажете?

1) Вернуть strdup/free, т.к. в стеке выделять произвольные буферы не принято, особенно когда в реальном приложении буфер понадобится большим, и особенно не проверяя его размер при копировании.

2) Этот if лишний, т.к. перекрывается условием while
Код: plaintext
1.
2.
  if (n != 1) 
    while ( i <= n && p != NULL ) 



Остальное все - ок. Ф-я strtok используется верно, не знаю что mayton'у не нравится.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956429
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TВсе тормоза тут из-за копирования строки. Зачем? Она уже в памяти. Ищи разделитель и копируй в word только нужный кусок.
Потому что strtok модифицирует строку в которой ищет.
Если делать без strtok то можно не копировать.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956431
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey VahromkinБудьте снисходительны, я с Си познакомился неделю назад от силы.
Можно то же самое, но по-русски?
Советую взять какую-нибудь книгу по Си и почитать хотя бы про указатели, а лучше целиком.
Указатели тема не простая, но фундаментальная для Си, полностью тут никто расписывать не будет (много букав будет и уже расписано в книгах), а по обрывкам тяжело изучать. Лучше почитай, а что не поймешь - тут спроси.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956438
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Господа, всем большое спасибо за терпение и ответы, беру небольшой таймаут на изучение всего написанного.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956450
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey VahromkinБудьте снисходительны, я с Си познакомился неделю назад от силы.
Можно то же самое, но по-русски?
Зачем я должен быть снисходителен. Ты пишешь - "...на старости лет...". Это что?
Ты старый разработчик. Возможно ты - старше меня. И зачем я должен быть снисходителен?
Зачем нужно тебя жалеть и нянчить? Я описал проблему в "общих" терминах. Не на сях а "вообще". Функция strtok
имеет протокол или порядок работы. 1) модификация строки. 2) получение итератора на подстроки
разбитые сплиттером. 3) Работа с ними и освобождение памяти.

Твой код можно записать в 5-7 строчек и хватит. Не нужны там никакие чудовищные extractword4.

Впрочем тебе уже Анатолий это рассказывает.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956459
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Господа, всем большое спасибо за терпение и ответы, беру небольшой таймаут на изучение всего написанного.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956477
YesSql
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
FYI
одна из имплементаций strtok. Раз уж так много постов уделено этой функции
Код: plaintext
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.
/* Copyright (C) 1991,1996,1997,1999,2000,2001,2007
   Free Software Foundation, Inc.
   This file is part of the GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA.  */

#include <string.h>


static char *olds;

#undef strtok

/* Parse S into tokens separated by characters in DELIM.
   If S is NULL, the last string strtok() was called with is
   used.  For example:
	char s[] = "-abc-=-def";
	x = strtok(s, "-");		// x = "abc"
	x = strtok(NULL, "-=");		// x = "def"
	x = strtok(NULL, "=");		// x = NULL
		// s = "abc\0=-def\0"
*/
char *
strtok (s, delim)
     char *s;
     const char *delim;
{
  char *token;

  if (s == NULL)
    s = olds;

  /* Scan leading delimiters.  */
  s += strspn (s, delim);
  if (*s == '\0')
    {
      olds = s;
      return NULL;
    }

  /* Find the end of the token.  */
  token = s;
  s = strpbrk (token, delim);
  if (s == NULL)
    /* This token finishes the string.  */
    olds = __rawmemchr (token, '\0');
  else
    {
      /* Terminate the token and make OLDS point past it.  */
      *s = '\0';
      olds = s + 1;
    }
  return token;
}


...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956482
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
maytonAndrey VahromkinБудьте снисходительны, я с Си познакомился неделю назад от силы.
Можно то же самое, но по-русски?
Зачем я должен быть снисходителен. Ты пишешь - "...на старости лет...". Это что?
Это было вступлением к беседе. Вычеркните, если вас оно раздражает.
maytonТы старый разработчик. Возможно ты - старше меня. И зачем я должен быть снисходителен?
Зачем нужно тебя жалеть и нянчить?
Мне бы не хотелось вступать в дискуссии, не имеющие отношения к вопросу, но так, на всякий случай - поинтересуйтесь значениями слова "снисхождение". С жалостью там ничего общего нет. "Нянчить" меня вы действительно не обязаны, но раз уж решили ответить на вопрос "чайника", будьте добры использовать минимум жаргонизмов и терминов на иностранных языках, отвечайте так, чтобы вас можно было понять.

maytonТвой код можно записать в 5-7 строчек и хватит. Не нужны там никакие чудовищные extractword4.
Тело моей функции состоит из 11 строк.
После спокойного ознакомления с написанным вами и остальными, думается, уложусь и в озвученные вами 5-7.
4 лишние строки делают функцию "чудовищной"?
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956505
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey Vahromkin4 лишние строки делают функцию "чудовищной"?
Производительность тут теряется на бесполезных итерациях. Указатели это не просто другой синтаксис, по сравнению с другими ЯП, это совсем другие возможности, но сначала надо суть понять, чтобы эти возможности задействовать. Поэтому читай книжку.
Мой пример выше поизучай 17628531
Можешь еще парсер строки CSV посмотреть, тоже близкая тема 17389367
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956532
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dima TПроизводительность тут теряется на бесполезных итерациях. Указатели это не просто другой синтаксис, по сравнению с другими ЯП, это совсем другие возможности, но сначала надо суть понять, чтобы эти возможности задействовать. Поэтому читай книжку.
Спасибо. Я сейчас читаю Кернигана и Ритчи, параллельно вот пытаюсь практиковаться.
Dima TМой пример выше поизучай 17628531
Можешь еще парсер строки CSV посмотреть, тоже близкая тема 17389367
Большое спасибо. Ваш пример, как я понял, иллюстрирует разбиение на лексемы без использования strtok.
Я, собственно, с этого и начал (естественно, моя функция из первого поста нуждается в кардинальной переработке), но как-то обсуждение перетекло на вариант с strtok...
Буду разбираться дальше, еще раз большое спасибо вам и остальным.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956547
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey VahromkinТело моей функции состоит из 11 строк.
После спокойного ознакомления с написанным вами и остальными, думается, уложусь и в озвученные вами 5-7.
4 лишние строки делают функцию "чудовищной"?
Твой код не пройдёт "code-review" с точки зрения обычного "C"-шного кода.
Мотиваций для introduce new function я не вижу никакой. Про избыточные вычисления
и временнУю сложность алгоритма Дмитрий уже писал. Я просто присоединяюсь.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956557
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey Vahromkin,
непонятно в чём у вас проблема. Вообще говоря, у K&R есть разбор вашей задачи. Вы хотите сделать всё "нахрапом" и побыстрее и учесть все детали, так не бывает. Язык Си требует тщательного изучения.
1. Комментарии это безусловно хорошо и полезно, но участниками этого Сообщества являются не школьники 5 класса, а достаточно грамотные люди. Лично мне (хотя я знаю тут явно менее других товарищей) не нравится читать такой код где прокомментирована каждая строчка. Думаю остальные также обратили на это внимание и солидарны по этому вопросу. Комментируйте только основные и неоднозначные моменты.
2. Почему вы используете calloc ? Принципиальна инициализация в 0 ?
3. Неудачное именование параметров функции и других объектов программы
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956804
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
maytonТвой код не пройдёт "code-review" с точки зрения обычного "C"-шного кода.
Мотиваций для introduce new function я не вижу никакой. Про избыточные вычисления
и временнУю сложность алгоритма Дмитрий уже писал. Я просто присоединяюсь.
Это мой первый код на Си - и вы хотите, чтобы он был образцовым? В таком случае у меня бы не было необходимости сюда писать...
Я внимательно читаю все, что мне пишут, стараюсь делать выводы и исправлять ошибки.
За участие и помощь я вам и остальным очень благодарен.
SashaMercuryAndrey Vahromkin,
непонятно в чём у вас проблема. Вообще говоря, у K&R есть разбор вашей задачи. Вы хотите сделать всё "нахрапом" и побыстрее и учесть все детали, так не бывает. Язык Си требует тщательного изучения.
Я, конечно, могу объяснить, зачем мне все это нужно, но только я и сам прекрасно понимаю, что предстоит еще очень много узнать, поэтому никуда не спешу, а разбираюсь в основах.
SashaMercury1. Комментарии это безусловно хорошо и полезно, но участниками этого Сообщества являются не школьники 5 класса, а достаточно грамотные люди. Лично мне (хотя я знаю тут явно менее других товарищей) не нравится читать такой код где прокомментирована каждая строчка. Думаю остальные также обратили на это внимание и солидарны по этому вопросу. Комментируйте только основные и неоднозначные моменты.
Учту, спасибо.
SashaMercury2. Почему вы используете calloc ? Принципиальна инициализация в 0 ?
Вы выше спрашивали, в чем у меня проблема...С моей точки зрения мир сейчас выглядит так:
1. В языке Си для выполнения любой одной конкретной элементарной задачи существует несколько решающих эту задачу функций, причем 90% этих функций использовать нежелательно, а остальные 10% содержат те или иные ошибки и использовать их тоже не стоит.
2. Писать собственные реализации вышеозначенных функций также не рекомендуется, поскольку есть стандартные функции, а то, что удастся написать, будет заведомо хуже.
3. Если компиляция программы на паскале либо запуск perl-скрипта прошли без ошибок и предупреждений, а программа выдает ожидаемые результаты - скорее всего, программа работает верно.
Если компиляция программы на Си прошла без ошибок и программа выдает верные результаты - это абсолютно ни о чем не говорит.
4. Решение классической задачи "прострелить себе ногу" на Си вовсе не "вы простреливаете себе ногу", а что-то вроде "Вы думаете, что прострелили себе ногу, но в итоге выясняется, что вы не выстрелили, не себе, и не в ногу".

Так почему же я использую calloc? Да просто пока по неопытности я из двух зол выбираю оба.

Вот какие-то такие у меня проблемы. Извините моего внутреннего Петросяна.

SashaMercury3. Неудачное именование параметров функции и других объектов программы
[молча развожу руками] На это мне абсолютно нечего сказать...
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956811
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Саш а ты заметил что ты стал сурово гнобить и обижать новичков?
Do you remember как ты сам был зелёным нубасиком.
А щас - "забурел" и даёшь джунам советы как жить
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956851
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey VahromkinЯ, конечно, могу объяснить, зачем мне все это нужно, но только я и сам прекрасно понимаю, что предстоит еще очень много узнать, поэтому никуда не спешу, а разбираюсь в основах.
Это неинтересно. Граблей будет еще много по дороге будет, главное не расслабляйся.

2 SashaMercury
mayton прав. Нечего сказать по существу - промолчи. Тут есть гуру, которые любят погнобить спрашивающих, но в их словах есть крупицы полезных знаний. В твоих - нет. Не бери с них пример.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956944
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T

mayton прав. Нечего сказать по существу - промолчи. Тут есть гуру, которые любят погнобить спрашивающих, но в их словах есть крупицы полезных знаний. В твоих - нет. Не бери с них пример.


Я прокомментировал код автора топика. Подсказал ему что K&R есть разобранный пример.
Сделал три вполне адекватных комментария по ему вопросу. Вы говорите чётко и ясно что мои советы бесполезны. Потому прошу вас по возможности прокомментировать каждый из трёх замечаний, и объяснить почему в каждом конкретном нет крупицы полезных знаний :) И да, "гнобить" никто никого не имеет право. В Сообществе это недопустимо.

PS
Марк, я прекрасно всё помню, у меня даже записано в блокноте, если я вдруг забуду. И это прокомментировал
SS Лично мне (хотя я знаю тут явно менее других товарищей). Вы меня второй раз обвиняете в грубости к новичкам, хотя я очень вежливо, всё объяснил. Марк, убеждаю вас ещё раз, никаких помыслов в грубости у меня не было, единственное что может смущать это сухой язык, но я привык так говорить с незнакомыми людьми.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38956975
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SashaMercury1. Комментарии это безусловно хорошо и полезно, но участниками этого Сообщества являются не школьники 5 класса, а достаточно грамотные люди. Лично мне (хотя я знаю тут явно менее других товарищей) не нравится читать такой код где прокомментирована каждая строчка. Думаю остальные также обратили на это внимание и солидарны по этому вопросу. Комментируйте только основные и неоднозначные моменты.
Для автора они пока все основные и непонятные. Он честно в этом сознался:
Andrey VahromkinБуду пояснять, что именно я делаю, так будет виднее, понял ли я суть или нет.

SashaMercury2. Почему вы используете calloc ? Принципиальна инициализация в 0 ?
Нехорошо вопросом на вопрос отвечать. Именно про это писал. Считаешь что это лишнее - предложи свой вариант, а не отправляй на поиски альтернатив.
По-хорошему, в данном случае динамическое выделение памяти вообще не нужно. Это отдельная тема, и изучать ее надо отдельно.

SashaMercury3. Неудачное именование параметров функции и других объектов программы
Лично у меня тут претензий нет.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38957029
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TSashaMercury1. Комментарии это безусловно хорошо и полезно, но участниками этого Сообщества являются не школьники 5 класса, а достаточно грамотные люди. Лично мне (хотя я знаю тут явно менее других товарищей) не нравится читать такой код где прокомментирована каждая строчка. Думаю остальные также обратили на это внимание и солидарны по этому вопросу. Комментируйте только основные и неоднозначные моменты.
Для автора они пока все основные и непонятные. Он честно в этом сознался:
Andrey VahromkinБуду пояснять, что именно я делаю, так будет виднее, понял ли я суть или нет.

SashaMercury2. Почему вы используете calloc ? Принципиальна инициализация в 0 ?
Нехорошо вопросом на вопрос отвечать. Именно про это писал. Считаешь что это лишнее - предложи свой вариант, а не отправляй на поиски альтернатив.
По-хорошему, в данном случае динамическое выделение памяти вообще не нужно. Это отдельная тема, и изучать ее надо отдельно.

SashaMercury3. Неудачное именование параметров функции и других объектов программы
Лично у меня тут претензий нет.

1. Таким образом мы дойдём до комментариев
Код: plaintext
1.
int a;//переменная целого типа ...



2. Так сначала изучите функции аллоцирования, а потом используйте. Язык Си это не лопата, бери кто угодно и копай. Может быть он специально использовал calloc, я не знаю, потому и спросил. В итоге оказалось что эта функция тут совершенно не нужна.
3. extractword и worddelim хорошие имена ?
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38957263
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SashaMercury1. Таким образом мы дойдём до комментариев
Код: plaintext
1.
int a;//переменная целого типа ...



А другой стороны - почему бы не сэкономить свое и чужое время, максимально подробно поясняя свои действия в ходе обучения?
SashaMercury2. Так сначала изучите функции аллоцирования, а потом используйте. Язык Си это не лопата, бери кто угодно и копай. Может быть он специально использовал calloc, я не знаю, потому и спросил. В итоге оказалось что эта функция тут совершенно не нужна.
Хорошо, я поясню ход своих мыслей.
Функции malloc и calloc
Функция malloc() возвращает указатель на первый байт области памяти размером size, которая была выделена из динамически распределяемой области памяти. Если для удовлетворения запроса в динамически распределяемой области памяти нет достаточного объема памяти, возвращается нулевой указатель.

Функция calloc() выделяет память, размер которой равен значению выражения num * size, т.е. память, достаточную для размещения массива, содержащего num объектов размером size. Возвращает указатель на первый байт выделенной области памяти. Все биты распределенной памяти инициализируются нулями. Если для удовлетворения запроса нет достаточного объема памяти, возвращается нулевой указатель.

Как я полагаю, исходя из вышепроцитированного, в рассматриваемом примере нет особой разницы - использовать malloc или calloc.
Первая будет быстрее, вторая позволит закрыть глаза на возможное отсутствие '\0' и мусора в размещаемой в памяти строки - закрывать глаза, наверное, не есть хорошо, но все же может оказаться полезным.
По поводу "быстрее" - лично я сомневаюсь, что malloc тут даст какой-то существенный прирост в производительности, с другой стороны - возможно, в Си иные критерии существенности.
Было бы неплохо, если бы теперь вы пояснили, почему с вашей точки зрения calloc тут неоправдан, и что бы вы использовали вместо него.
SashaMercury3. extractword и worddelim хорошие имена ?
extract ion word - "извлечение слова"
word delim eters - "разделители слов"
Можно также функцию назвать " get_word ", а переменную - " separators ", но я сомневаюсь, что текст программы после этого станет гораздо понятнее. Предложите свои варианты, ради интереса.

Господа, я ещё раз переписал свои extractword'ы, в обоих вариантах - с strtok и без.
1. Вариант с strtok.
Короче он не стал, т.к. я постарался учесть замечания относительно каверз str(n)cpy а также добавил различные коды возврата для контроля за проиходящим внутри функции (0 - нет ошибок, 1 - нет слова с нужным номером, 2 и 3 - ошибки при внутреннем копировании строк)
Вместо массива s[STR_BUFFER] в качестве упражнения снова использую strdup/free ( 17628569 от Anatoly Moskovsky) - как я понял, единого мнения о лучшем способе создания копии нет.
Относительно strlcpy - пишу под freebsd, функция доступна в системе, вопросами переносимости кода на другие платформы пока не озабочивалсялся, но исходный код данной функции доступен и при необходимости может быть включен в тело программы.
Код: plaintext
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.
int extractword4(char *word, const unsigned int n, const char *str, const char *worddelim)
{
  int i = 2;
  char *s, *p;
  int result = 0;

  *word = '\0';
  s = strdup(str);

  if (s != NULL)
  {
    p = strtok(s, worddelim);
    while ( i <= n && p != NULL )
    {
      p = strtok(NULL, worddelim);
      i++;
    }
    if ( p != NULL) { if ( strlcpy(word, p, STR_BUFFER) >= STR_BUFFER ) result = 2; }
    else result = 1;
    free(s);
  }
  else result = 3;

  return result;
}


2. Вариант без strtok как советовал в ( 17628531 Dima T)
Короче чем с strtok, но что-то мне в нем не нравится, сейчас думаю, можно ли упростить.
Можно реализовать и без функций str..., тогда потребуется усложнять условия в циклах для отсева всех оговоренных разделителей, либо писать еще одну функцию, которая будет предварительно выполнять замену символов, входящих в набор разделителей каким-то одним символом
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
int extractword(char *word, const unsigned int n, const char *str, const char *worddelim)
{
  int count = 1;

  *word = '\0';
  while ( *str != 0 && strchr(worddelim, *str) != NULL ) str++; // вычистим разделители в начале строки
  while ( count != n )
  {
    if ( *str == '\0' ) return 1; // конец строки, а слово n не встретилось 
    while ( *str != 0 && strchr(worddelim, *str) == NULL ) str++;
    while ( *str != 0 && strchr(worddelim, *str) != NULL ) str++;
    count ++;
  }
  while ( *str != 0 && strchr(worddelim, *str) == NULL ) { *word = *str; word++; str++; }
  *word = '\0';

  return 0;
}
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38957341
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вахромкин. strchr внутри себя содержит еще один цикл. Подумай есть ли смысл троекратно
запускать его внутри твоих циклов?
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38957387
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
mayton,

Ну это не лучший вариант, конечно. Попробую вечерком переписать вообще без str...
Но у меня возникает вопрос - в Си вообще пользуются функциями из стандартных библитек? ;)
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38957392
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Выделение памяти операция тяжелая, поэтому там где можно обойтись без нее - лучше без нее. Поэтому второй вариант будет быстрее.
Во-вторых память экономить никогда не мешало.

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

По поводу нескольких разделителей и strchr() для проверки - это нормально. Можно strspn() задействовать для поиска начала следующего слова.

Дальше вопрос по архитектуре: задача какая решается? получать одно-два слова из каждой строки или разобрать строку на слова? Если второе, то архитектура корявая, т.к. каждый раз начинаешь с первого слова. Поэтому эффективнее всего возвращать указатель на символ сразу за найденным словом и следующий проход начитать с этого места (у меня так было). Например надо получить 3,5,10-е слова, твой код прочитает 18 слов (3+5+10), мой 10.

Раз уж кодами ошибок пользуешься - задавай их дефайнами, так читабельнее
Код: plaintext
1.
2.
3.
4.
5.
6.
#define EW_OK   0
#define EW_NONE 1
...
if(...) return EW_NONE;
...
return EW_OK;
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38957393
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonstrchr внутри себя содержит еще один цикл. Подумай есть ли смысл троекратно запускать его внутри твоих циклов?
Это у него последовательно проверяется каждый символ на предмет является ли он разделителем. ИМХУ вроде ничего лишнего. Или у тебя есть идея как это сделать меньшим количеством операций?
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38957405
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey Vahromkinу меня возникает вопрос - в Си вообще пользуются функциями из
стандартных библитек? ;)
Пользуются, конечно. Но поскольку программирование на языке С обычно ориентировано на
быстродействие результата, то стараются точно знать во что обойдётся их применение.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38957460
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey VahromkinПопробую вечерком переписать вообще без str...
Это лишнее. strchr() быстро работает. От того что ты ее "своими словами" перепишешь - код быстрее не станет. Также будешь перебирать массив разделителей.

Другое дело strdup() - динамическое выделение памяти и копирование всей строки. Это не быстро. Если надо будет повторить много раз - получишь тормоз.

В твоем последнем extractword() нет ничего лишнего. Разве что архитектуру пересмотреть (выше писал 17633636 )

Можно немного поуменьшать количество строк/букв кода, станет покрасивее, но не быстрее.
Например цикл for() вместо while() сделать
Код: plaintext
1.
2.
3.
for(int count = 0; count < n; count++) {
  ...
}
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38957475
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dima TВыделение памяти операция тяжелая, поэтому там где можно обойтись без нее - лучше без нее. Поэтому второй вариант будет быстрее. Во-вторых память экономить никогда не мешало.
Принимается, от этого и буду отталкиваться.
Dima TВ обоих вариантах накосячено с контролем выхода за пределы word, точнее во втором вообще нет контроля (в моем примере была проверка end), а в первом размер жестко задан STR_BUFFER, завтра захочешь поменять STR_BUFFER и он изменится для всей твоей проги. Размер буфера надо в параметрах передавать.
Проверку по end я действительно упустил из виду, а насчёт передачи размера буфера в параметрах я уже думал, но забыл написать, что вижу необходимость реализации этого :)
Dima TДальше вопрос по архитектуре: задача какая решается? получать одно-два слова из каждой строки или разобрать строку на слова?

Ну вообще на повестке дня - в дальней перспективе - замена нескольких perl-хелперов для прокси-сервера squid на более шустрые и компактные аналоги. На вход хелперы получают от 2 до 6 параметров. Полученные данные в хелперах участвуют в запросах к базе postgresql. В зависимости от результатов squid'у возвращают либо ОК либо ERR.
Сейчас начинаю упираться в скорость работы скриптов и потребление памяти. Попробовал переписать на freepascal как на знакомом с института, но был неприятно удивлен - perl-скрипты работают втрое быстрее паскалевского кода и памяти жрут меньше.

test.dat - 10000 строчек вида "Source_IP Destination_URL"
Засекал по 4 раза время отработки perl-скрипта и паскалевского исполняемого файла, ниже результаты
perl
time cat test.dat | ./bypass_auth.pl

4.053u 0.482s 0:42.00 10.7% 5+2838k 0+0io 0pf+0w
4.175u 0.579s 0:43.93 10.7% 4+2671k 0+0io 0pf+0w
4.270u 0.408s 0:42.95 10.8% 5+2767k 0+0io 0pf+0w
3.952u 0.518s 0:41.53 10.7% 5+2771k 0+0io 0pf+0w

pascal
time cat test.dat | ./sqBypass_Auth -u squid -p squid -b squid

15.327u 18.999s 2:03.62 27.7% 993+1768k 0+0io 0pf+0w
14.819u 20.901s 2:04.81 28.6% 1009+1797k 0+0io 0pf+0w
15.147u 21.269s 2:07.03 28.6% 1004+1788k 0+0io 0pf+0w
15.148u 21.762s 2:08.37 28.7% 984+1752k 0+0io 0pf+0w

Решил попробовать на Си реализовать. Первое с чем столкнулся - отсутствие split - соответственно, упёрся в способы разбора строк на составные части.
Далее предстоит искать какую-то замену перловому модулю URI для разбора url, получаемых от squid. Ну и способы доступа к postgresql.
Dima TЕсли второе, то архитектура корявая, т.к. каждый раз начинаешь с первого слова. Поэтому эффективнее всего возвращать указатель на символ сразу за найденным словом и следующий проход начитать с этого места (у меня так было). Например надо получить 3,5,10-е слова, твой код прочитает 18 слов (3+5+10), мой 10.
Учту, попробую это реализовать
Dima TРаз уж кодами ошибок пользуешься - задавай их дефайнами, так читабельнее

Да, спасибо, хорошая идея.

Dima TAndrey VahromkinПопробую вечерком переписать вообще без str...
Это лишнее. strchr() быстро работает. От того что ты ее "своими словами" перепишешь - код быстрее не станет. Также будешь перебирать массив разделителей.
Ну в общем да. Либо предварительно "причёсывать" строку дополнительной функцией, заменяющей разные разделители на какой-то один и удаляющей повторяющиеся лишние разделители
Dima TВ твоем последнем extractword() нет ничего лишнего. Разве что архитектуру пересмотреть (выше писал 17633636 )
Можно немного поуменьшать количество строк/букв кода, станет покрасивее, но не быстрее.
Например цикл for() вместо while() сделать
Код: plaintext
1.
2.
3.
for(int count = 0; count < n; count++) {
  ...
}


Спасибо, подумаю ещё сегодня вечерком :)
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38957538
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторSS1. Таким образом мы дойдём до комментариев
Код: plaintext
1.
int a;//переменная целого типа ...



А другой стороны - почему бы не сэкономить свое и чужое время, максимально подробно поясняя свои действия в ходе обучения?


Не надо заниматься ерундой. Если вас тут кто-то защищает, не думайте что вы тут правы во всём. Ваши комментарии неудачно расположены, и их слишком много даже для процесса обучения. Кто бы вас не защищал(от адекватных замечаний), это так.

авторКак я полагаю, исходя из вышепроцитированного, в рассматриваемом примере нет особой разницы - использовать malloc или calloc.
Первая будет быстрее, вторая позволит закрыть глаза на возможное отсутствие '\0' и мусора в размещаемой в памяти строки - закрывать глаза, наверное, не есть хорошо, но все же может оказаться полезным.По поводу "быстрее" - лично я сомневаюсь, что malloc тут даст какой-то существенный прирост в производительности, с другой стороны - возможно, в Си иные критерии существенности.
Было бы неплохо, если бы теперь вы пояснили, почему с вашей точки зрения calloc тут неоправдан, и что бы вы использовали вместо него.

если бы вы стандарт цитировали, тогда то что вы полагаете из "выше процитировано" имело бы место(это не какое-то "гнобление" или чего вы там напридумывали, а совет автору топика читать стандарт и ссылаться на него). И даже если то что вы процитировали верный перевод, то выделенное красным не соответствует действительности и неверно. функция calloc имеет побочный эффект(в контексте обычного аллоцирования ) при выделении памяти, и раз вы её используете, значит этот эффект вам нужен. Я бы подумал что это массив счётчиков, например.

авторextraction word - "извлечение слова"
word delimeters - "разделители слов"
get_word
delimeters or separators

вы сами справились. слова get set классика.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38957560
egorych
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SashaMercuryавторextraction word - "извлечение слова"
word delimeters - "разделители слов"
get_word
delimeters or separators

вы сами справились. слова get set классика.ну, то есть претензий к n и str нет у нас, а вот к единственным, хоть как то полезно названным объектам программы - есть )))

А я бы, кстати, extractword оставил бы, оно больше подходит по смыслу к происходящему, чем get, а вот worddelim заменил бы на delimeters. word назвал бы, возможно, dst/destination, а str - src/source. Ну и n - такое прекрасное имя, но я бы его в m переименовал бы, обязательно ))))
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38957592
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey VahromkinНу вообще на повестке дня - в дальней перспективе - замена нескольких perl-хелперов для прокси-сервера squid на более шустрые и компактные аналоги. На вход хелперы получают от 2 до 6 параметров. Полученные данные в хелперах участвуют в запросах к базе postgresql. В зависимости от результатов squid'у возвращают либо ОК либо ERR.
Сейчас начинаю упираться в скорость работы скриптов и потребление памяти. Попробовал переписать на freepascal как на знакомом с института, но был неприятно удивлен - perl-скрипты работают втрое быстрее паскалевского кода и памяти жрут меньше.

test.dat - 10000 строчек вида "Source_IP Destination_URL" ...
Полсекунды на разбор 10000 простых строчек это много для любого языка. Насколько я знаю разбор строк в перле достаточно быстро происходит.

Я бы для начала убедился в ту ли сторону копаешь. Сделай замеры времени:
1. тупо поставить return ОК и получить скорость вызова обработчика.
2. Оставить разбор, убрать запросы к БД и в конце return ОК
В итоге получишь из чего состоят эти полсекунды, т.е. время на вызовы обработчика, время разбора и время на обращения к БД.

Дальше смотри что получится: возможно надо изучать не Си, а как тюнинговать postgresql.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38957932
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dima TПолсекунды на разбор 10000 простых строчек это много для любого языка. Насколько я знаю разбор строк в перле достаточно быстро происходит.
Я бы для начала убедился в ту ли сторону копаешь. Сделай замеры времени:
Это уже оффтоп, но что-то я тут возможности отправлять личные сообщения найти не могу - простите :(

Разбор строк, формирование запроса и собственно запрос к БД происходят практически мгновенно, у меня проблема в железе - на сервере памяти 2Гб, плюс там ещё зоопарк всякий живёт. А эти постоянные подключения/отключения и съедают львиную долю времени исполнения. Вот и думал попробовать ещё и на С, он все же побыстрее должен быть, ну и - заодно освоить новый язык хотя бы на уровне "пишу, заглядывая в справочник".
Тесты
1. Только split и OK

# time test.sh
0.075u 0.016s 0:00.09 88.8% 5+2986k 0+0io 0pf+0w
0.076u 0.015s 0:00.09 88.8% 6+3258k 0+0io 0pf+0w
0.076u 0.015s 0:00.09 88.8% 22+3004k 0+0io 0pf+0w

2. split, построение запроса и ОК без обращения к БД

# time test.sh
0.736u 0.086s 0:00.82 98.7% 5+2815k 0+0io 0pf+0w
0.773u 0.047s 0:00.81 100.0% 5+2788k 0+0io 0pf+0w
0.754u 0.063s 0:00.81 100.0% 5+2761k 0+0io 0pf+0w

3. split, построение и выполнение запроса с постоянным подключением к БД

# time test.sh
1.569u 0.118s 0:06.50 25.6% 5+2770k 0+0io 0pf+0w
1.584u 0.110s 0:06.52 25.9% 5+2955k 0+0io 0pf+0w
1.576u 0.120s 0:06.52 25.9% 5+3084k 0+0io 0pf+0w

4. split, построение и выполнение запроса с подключением к БД по запросу

# time test.sh
3.684u 0.554s 0:40.29 10.4% 5+2865k 0+0io 0pf+0w
3.731u 0.518s 0:40.39 10.4% 5+2807k 0+0io 0pf+0w
3.760u 0.473s 0:40.31 10.4% 5+2613k 0+0io 0pf+0w

# less test.sh
#!/bin/sh
cat test1.dat | ./bypass_auth.pl

test.sh (END)
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38957957
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ойй, куда-то у меня строка из текста сообщения выпала, ерунда получилась...

Разбор строк, формирование запроса и собственно запрос к БД происходят практически мгновенно, у меня проблема в железе - на сервере памяти 2Гб, плюс там ещё зоопарк всякий живёт. Поэтому в скрипте подключение к БД происходит только после поступления строки на вход, а пока данных нет - скрипт к базе не подключен, и не занимает доступные соединения вхолостую. Вот эти постоянные подключения/отключения и съедают львиную долю времени исполнения. Вот и думал попробовать ещё и на С, он все же побыстрее должен быть, ну и - заодно освоить новый язык хотя бы на уровне "пишу, заглядывая в справочник".
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38957961
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey VahromkinПоэтому в скрипте подключение к БД происходит только после
поступления строки на вход, а пока данных нет - скрипт к базе не подключен, и не занимает
доступные соединения вхолостую.
Connection pool? Не, не слышали о таком...
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38957964
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dimitry SibiryakovConnection pool? Не, не слышали о таком...
Ну нельзя же знать всё на свете...
Вот услышал, читаю теперь, что это такое...
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38957985
wst
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я правильно понимаю, что в данном случае произвольный доступ к подстрокам не нужен? И формат разбираемых строк фиксированный?
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38958009
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
wstЯ правильно понимаю, что в данном случае произвольный доступ к подстрокам не нужен? И формат разбираемых строк фиксированный?
Не совсем понял вопрос.
Разные хелперы получают на вход строки различной конструкции.
Например

'ip url'
'login ip url'
'url ip/fqdn ident method'
'"username":"realmname"'

Иногда части строк могут отсутствовать
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38958016
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey VahromkinDima TПолсекунды на разбор 10000 простых строчек это много для любого языка. Насколько я знаю разбор строк в перле достаточно быстро происходит.
Я бы для начала убедился в ту ли сторону копаешь. Сделай замеры времени:
Это уже оффтоп, но что-то я тут возможности отправлять личные сообщения найти не могу - простите :(

Тут демократичные модераторы, если оффтоп по существу - прощают :)

Andrey VahromkinРазбор строк, формирование запроса и собственно запрос к БД происходят практически мгновенно,
И чего ты тут хочешь улучшить? Магическое "написано на Си" не заставит процессор быстрее работать.

Твои замеры: 15 мс на вызов, 40-50 мс на разбор строк, 50-60 мс на выполнение запроса и 400 мс на установение связи с БД.

Теперь то что ты оптимизируешь: разбор 40-50 мс, допустим станет 0. выигрыш 10%. Но они не станут 0, уменьшатся максимум до 20-30 мс (если вообще уменьшатся), т.е. выиграешь 3-5%. Оно поможет?

На установке соединения с БД ты теряешь 80% !!! времени. Т.е. потенциал ускорить работу в 5 !!! раз. Просто допиши скрипт чтобы он поддерживал соединение и при необходимости умел восстанавливать.

Это решение твоей проблемы.

а это
Andrey Vahromkinу меня проблема в железе ... заодно освоить новый язык ...
твои домыслы и хотелки. Но если есть желание освоить - осваивай. Только чудес от использования Си не будет.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38958021
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Andrey VahromkinВот эти постоянные подключения/отключения и съедают львиную долю времени исполнения.
Си тут ни при чем. Возможно там просто умышленно тормоз вставлен, чтобы подбор пароля усложнить. Держи соединение, оно ресурсы почти не тратит.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38958030
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вахромкин. В большинстве задач оптимизации нужно смотреть в корень. А именно
в события ожидания. Готов спорить что у тебя это network events, ну на крайний случай
I/O. Переписывание pl скрипта на "C" ничего особенного не даст. Судя из твоих бенчмарков
между 1м и 2м тестом разница времени - 10х кратная. Это увеличение отклика появилось
после того как к split ты добавил подключение к БД.

Вот с него нужно и начать оптимизировать. Про pool уже сказали. Плюсик. Далее - где задержка.
Сетевые события? Посмотреть сеть? БД стоит локально? Подключить loopback, pipes. БД далеко?
Сократить маршрут. Есть возможность включить гигабит? Есть возможность снизить затраты на транспорт
информации? Снижай.

Далее. БД. После использования SQL-операций время снова удвоилось? Почему? Что за БД. Смотри
explain plan твоего запроса. Найди DBA ? Спроси у него чо как? Как ускорить? Может индекс построить
да там дофигища шаманста это я тебе как быв. DBA говорю. Море направлений.

Вот в таком вот аспекте.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38958035
wst
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Смысл вопроса про фиксированный формат в том, что все эти extractword-ы можно заменить одним проходом strtok, при котором заполнялись бы соответствующие поля структуры с более гуманными названиями. Если данные резать за один проход, назначая им при этом нормальные идентификаторы, то:
Результат 1. вместо extractword9 (username, BUFFER_SIZE, ....); x(username); в коде будет что-то вроде x(s->username) - проще через полгода вспомнить про что вообще речь.
Результат 2. заполнение структуры отдельно от использования заполненной - меньше надо держать в голове при реализации что того что другого. Да и к новому формату входных данных если что проще приспособиться.
Дальше уже просто приятные мелочи:
Результат 3. меньше дерганий за выделение-освобождение памяти - меньше возможностей отстрелить ногу-другую.
Результат 4, мелкий бонус - есть все шансы что так еще и будет быстрее работать.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38958164
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dima T, mayton
Да, похоже, мне нужно с вопросами переезжать в ветки с perl и postgresql :)
Что ж, сейчас пока разбираюсь, что такое pgbouncer/pgpool, и что лучше использовать...
Далее буду изучать, как с этим работает perl.
С тем не менее не брошу, всё-таки буду параллельно учиться на нем программировать.
wstСмысл вопроса про фиксированный формат в том, что все эти extractword-ы можно заменить одним проходом strtok, при котором заполнялись бы соответствующие поля структуры с более гуманными названиями.
Эх, а ведь и правда, и наверное, можно даже сразу разбирать строку по мере считывания ее из stdin... чудно, что это даже в голову раньше не приходило...

Господа! Огромное всем спасибо за помощь и участие!
Было приятно пообщаться и научиться (надеюсь) чему-то новому!
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38958194
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сообщи если надо перенести топик в профильный подфорум.
...
Рейтинг: 0 / 0
Вопросы начинающего - функции для работы со строковыми лексемами
    #38958225
Andrey Vahromkin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
maytonСообщи если надо перенести топик в профильный подфорум.
Да не надо, наверное, пока, во всяком случае.
У меня вопросы сейчас самые общие "что это такое и как оно работает". Сначала почитаю, попробую поставить, посмотреть, а там видно будет.
Еще раз спасибо!
...
Рейтинг: 0 / 0
73 сообщений из 73, показаны все 3 страниц
Форумы / C++ [игнор отключен] [закрыт для гостей] / Вопросы начинающего - функции для работы со строковыми лексемами
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]