0

Нужно найти строку в массиве байт. Т е из файла читается его содержимое в массив байт, затем в этом массиве ищется строка. Обычный find() или strstr() не помогут, т к файл бинарный -> т е могут встретиться символы переноса строки, нуль-байты и т д. Узнал про memmem, но для меня вариант оказался нерабочий - возвращает SIGSEGV:

#include <stdio.h>
#include <sys/stat.h>
#include <fstream>
#include <string.h>
using namespace std;

int main() { struct stat buf; stat("binary", &buf); const unsigned int fsize = buf.st_size; ifstream bins; bins.open("binary", ios::in|ios::binary); char cbuf = new char[fsize]; char ch; unsigned int k = 0; while(bins.get(ch)) { cbuf[k] = ch; k++; } bins.close(); const void pos = memmem(cbuf, fsize, "/system", 7); const int ipos = (int )pos; delete[] cbuf; printf("%d", *ipos); return 0; }

 ~/work $ g++ -g main.cpp
 ~/work $ ./a.out
Segmentation fault
 ~/work $ gdb ./a.out
gdb > r
Starting program: /home/me/work/a.out

Program received signal SIGSEGV, Segmentation fault.
0x0000005555555dd0 in main () at main.cpp:24
24          printf("%d", *ipos);

А мне нужно найти строку в массиве байт таким образом, чтобы получить себе позицию начала строки в массиве. Т е, если первый символ искомого слова является 439м байтом, то должно вернуть число 439.

  • 2
    Посмотрите в сторону std::search. Примерно так. вариант оказался нерабочий - возвращает SIGSEGV Немудрено, ведь после освобождения буфера delete[] cbuf; указатель ipos указывает на фрагмент освобождённое памяти. Его разыменование вызывает неопределённое поведение. Также нарушено правило строгих псевдонимов (*ipos), и требования по выравниванию ((int *)pos). – wololo Jun 26 '22 at 23:15
  • спасибо за причину ошибку SIGSEGV, теперь все работает) UPD: мне выводит число, большее размеру буфера... – RandomDice 779 Jun 27 '22 at 06:12
  • мне выводит число, большее размеру буфера. Если вы всего лишь перенесли освобождение буфера в конец программы, то тоже ожидаемо. pos хранит указатель на начало последовательности символов "/system" внутри cbuf. Вы интерпретировали sizeof(int) (обычно 4) байт этой последовательности как значение типа int. Т.е. ваша программа выводит значение байтов "/sys", как int. Вывелось 1937339183? – wololo Jun 27 '22 at 07:34
  • UPD: решил проблему – RandomDice 779 Jun 27 '22 at 09:04

2 Answers2

1

Вычитайте указатели на char * чтобы вычислить смещение.

const char *pos = static_cast<const char *>(memmem(cbuf, fsize, "/system", 7));
if (pos == nullptr) {
    printf("Not found\n");
} else {
    const ptrdiff_t ipos = pos - cbuf;
    printf("%td", ipos);
}
delete[] cbuf;
  • После освобождения буфера delete[] cbuf; указатели pos и cbuf становится невалидным. Попытки чтения и манипуляций над прочитанными значениями вызывают неопределённое поведение. И неожиданные вещи происходят. – wololo Jun 26 '22 at 22:51
  • @wololo, спасибо. Поправил. – Stanislav Volodarskiy Jun 26 '22 at 23:02
0
const char *pos = static_cast<const char*>(memmem(cbuf, fsize, "/system", 7));
const ptrdiff_t ipos = pos - cbuf;
if (ipos < 0 || ipos > fsize) {
printf("Can't find!\n");
} else {
printf("%d\n", ipos);
}
  • 1
    пожалуйста, постарайтесь оставлять чуть более развёрнутые ответы. дополнить ответ можно, нажав [edit] – aleksandr barakin Jun 27 '22 at 09:43
  • 2
    Функция memmem в случае успеха возвращает указатель на элемент массива cbuf, но в случае неудачи возвращает нулевой указатель. Нельзя из нулевого указателя вычитать указатель на объект. Это вызывает неопределённое поведение (см.: expr.add/5, арифметика указателей). Чем вам не угодил способ предложенный @StanislavVolodarskiy? – wololo Jun 27 '22 at 11:30
  • 3
    %d не совместим с ptrdiff_t. Используйте %td. – Stanislav Volodarskiy Jun 28 '22 at 07:21