Вот реальный пример, над которым я сейчас работаю, от систем обработки / управления сигналами:
Предположим, что у вас есть структура, которая представляет данные, которые вы собираете:
struct Sample {
time_t time;
double value1;
double value2;
double value3;
};
Теперь предположим, что вы введете их в вектор:
std::vector<Sample> samples;
... fill the vector ...
Теперь предположим, что вы хотите вычислить некоторую функцию (скажем, среднее значение) одной из переменных в диапазоне выборок, а вы хотите, чтобы этот средний расчет включал функцию. Указатель-к-член упрощает:
double Mean(std::vector<Sample>::const_iterator begin,
std::vector<Sample>::const_iterator end,
double Sample::* var)
{
float mean = 0;
int samples = 0;
for(; begin != end; begin++) {
const Sample& s = *begin;
mean += s.*var;
samples++;
}
mean /= samples;
return mean;
}
...
double mean = Mean(samples.begin(), samples.end(), &Sample::value2);
Примечание Редактировано 2016/08/05 для более сжатого подхода к шаблону-функции
И, конечно, вы можете использовать шаблон это вычислить среднее значение для любого форварда-итератора и любого типа значения, который поддерживает добавление с самим собой и деление на size_t:
template<typename Titer, typename S>
S mean(Titer begin, const Titer& end, S std::iterator_traits<Titer>::value_type::* var) {
using T = typename std::iterator_traits<Titer>::value_type;
S sum = 0;
size_t samples = 0;
for( ; begin != end ; ++begin ) {
const T& s = *begin;
sum += s.*var;
samples++;
}
return sum / samples;
}
struct Sample {
double x;
}
std::vector<Sample> samples { {1.0}, {2.0}, {3.0} };
double m = mean(samples.begin(), samples.end(), &Sample::x);
EDIT - приведенный выше код имеет последствия для производительности
Вы следует отметить, как я вскоре обнаружил, что приведенный выше код имеет некоторые серьезные последствия для производительности. Резюме состоит в том, что если вы вычисляете итоговую статистику по временному ряду или вычисляете FFT и т. Д., То вы должны хранить значения для каждой переменной в памяти. В противном случае итерация по ряду приведет к пропуску кеша для каждого полученного значения.
Рассмотрим производительность этого кода:
struct Sample {
float w, x, y, z;
};
std::vector<Sample> series = ...;
float sum = 0;
int samples = 0;
for(auto it = series.begin(); it != series.end(); it++) {
sum += *it.x;
samples++;
}
float mean = sum / samples;
На многих архитектурах один экземпляр Sample
будет заполнять строку кэша. Таким образом, на каждой итерации цикла один образец будет извлечен из памяти в кеш. 4 байта из строки кэша будут использоваться, а остальные будут удалены, а следующая итерация приведет к еще одному пропуску кэша, доступу к памяти и т. Д.
Гораздо лучше сделать это:
struct Samples {
std::vector<float> w, x, y, z;
};
Samples series = ...;
float sum = 0;
float samples = 0;
for(auto it = series.x.begin(); it != series.x.end(); it++) {
sum += *it;
samples++;
}
float mean = sum / samples;
Теперь, когда первое значение x загружается из памяти, следующие три будут также загружены в кеш (предположительно подходящее выравнивание), то есть вам не нужны значения, загруженные для следующих трех итераций.
Вышеупомянутый алгоритм может быть несколько улучшен за счет использования SIMD-инструкций, например, для архитектур SSE2. Тем не менее, они работают намного лучше, если значения все смежны в памяти, и вы можете использовать одну инструкцию для загрузки четырех образцов вместе (подробнее в последующих версиях SSE).
YMMV - проектируйте свои структуры данных в соответствии с вашими алгоритм.
Вы можете сделать это с помощью strtol
, например:
char *str = "ab234cid*(s349*(20kd", *p = str;
while (*p) { // While there are more characters to process...
if ( isdigit(*p) || ( (*p=='-'||*p=='+') && isdigit(*(p+1)) ) {
// Found a number
long val = strtol(p, &p, 10); // Read number
printf("%ld\n", val); // and print it.
} else {
// Otherwise, move on to the next character.
p++;
}
}
Ссылка на ideone .
Сделать конечный автомат, который работает по одному основному принципу: текущий символ - номер.
Возможны оптимизации.
Или вы можете сделать простую функцию следующим образом:
// Provided 'c' is only a numeric character
int parseInt (char c) {
return c - '0';
}
Возможное решение с использованием sscanf()
и наборов сканирования:
const char* s = "ab234cid*(s349*(20kd";
int i1, i2, i3;
if (3 == sscanf(s,
"%*[^0123456789]%d%*[^0123456789]%d%*[^0123456789]%d",
&i1,
&i2,
&i3))
{
printf("%d %d %d\n", i1, i2, i3);
}
, где %*[^0123456789]
означает игнорировать ввод до тех пор, пока не будет найдена цифра. См. Демонстрацию в http://ideone.com/2hB4UW .
Или, если число номеров неизвестно, вы можете использовать спецификатор %n
для записи последней позиции, прочитанной в буфер:
const char* s = "ab234cid*(s349*(20kd";
int total_n = 0;
int n;
int i;
while (1 == sscanf(s + total_n, "%*[^0123456789]%d%n", &i, &n))
{
total_n += n;
printf("%d\n", i);
}
здесь после простого решения с использованием sscanf
:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char str[256]="ab234cid*(s349*(20kd";
char tmp[256];
int main()
{
int x;
tmp[0]='\0';
while (sscanf(str,"%[^0123456789]%s",tmp,str)>1||sscanf(str,"%d%s",&x,str))
{
if (tmp[0]=='\0')
{
printf("%d\r\n",x);
}
tmp[0]='\0';
}
}
Если числа разделены пробелом в строке, вы можете использовать sscanf (). Так как это не так с вашим примером, вы должны сделать это сами:
char tmp[256];
for(i=0;str[i];i++)
{
j=0;
while(str[i]>='0' && str[i]<='9')
{
tmp[j]=str[i];
i++;
j++;
}
tmp[j]=0;
printf("%ld", strtol(tmp, &tmp, 10));
// Or store in an integer array
}