Как я могу ускорить процедуру?
Самый подозрительный аспект вашей программы - это strcat()
. При каждом вызове ему нужно отсканировать всю строку назначения с начала, чтобы найти место для добавления исходной строки. В результате, если строки вашего файла имеют длину, ограниченную константой (даже большой), то производительность вашего подхода масштабируется с квадратом длины файла.
Анализ асимптотической сложности не обязательно отражает всю историю. Часть ввода-вывода вашего кода масштабируется линейно с длиной файла, а поскольку I/O намного дороже, чем манипуляция с памятью в памяти, это будет доминировать над вашей производительностью для файлов с небольшим количеством файлов. Если вы находитесь в этом режиме, вы, вероятно, не будете делать намного лучше, чем вы уже делаете. В этом случае, однако, вы могли бы еще сделать немного лучше, читая весь файл сразу через fread()
, а затем сканировать его с истекшим данных через strstr()
:
size_t nread = fread(vString, 1, fdstat.st_size, fp);
// Handle nread != fdstat.st_size ...
// terminate the buffer as a string
vString[nread] = '\0';
// truncate the string after the end-of-data:
char *eod = strstr(vString, "\n ");
if (eod) {
// terminator found - truncate the string after the newline
eod[1] = '\0';
} // else no terminator found
Это масштабируется линейно, поэтому он обращается ваша проблема асимптотической сложности тоже, но если интересующие данные часто будут намного короче, чем файл, тогда это оставит вас в тех случаях, когда вы делаете намного более дорогостоящие операции ввода-вывода, чем вам нужно. В этом случае одним из вариантов было бы читать куски, как предположил @laissez_faire. Другим было бы настроить ваш оригинальный алгоритм для отслеживания конца vString
, чтобы использовать strcpy()
вместо strcat()
, чтобы добавить каждую новую строку. Ключевая часть этой версии будет выглядеть примерно так:
char *linePtr = NULL;
size_t nread = 0;
size_t len = 0;
*vString = '\0'; // In case the first line is end-of-data
for (char *end = vString; ; end += nread) {
// Check every line
nread = getline(&linePtr, &len, fp);
if (nread < 0) {
// handle eof or error ...
}
// When data ends, the line begins with space (" ")
if (*linePtr == ' ') {
break;
}
strcpy(end, *linePtr);
}
free(linePtr);
Кроме того, обратите внимание, что
вам не нужно изначально нулевой заполнения памяти, выделенной для *vString
, так как вы просто переписывая эти нули с данными реального интереса (а затем игнорируя остальную часть буфера).
Вы не должны указывать возвращаемое значение malloc()
-семейных функций, включая calloc()
.
'calloc' =' malloc' + 'memset (..., 0, ...)' за один шаг. –
И 'malloc (0)' не возвращает действительный адрес для 'size_t', передайте переменную из стека, как указано в [getline] (http://man7.org/linux/man-pages/man3 /getline.3.html): 'size_t len = 0;' ... 'getline (& line, & len, stream)' –
Thx! Я исправил его .. но это не ускорило мой код;) –