strlen не возвращает правильную длину

В настоящее время я использую метод strlen для вычисления длины этой строки:

56 69 56 4F 74 65 63 68 32 00 2C 00 00 27 6F 23 84 0E 32 50 41 59 2E 53 59 53 2E 44 44 46 30 31 A5 11 BF 0C 0E 61 0C 4F 07 A0 00 00 00 04 10 10 87 01 01

основная проблема в том, что он всегда останавливается при встрече с 00 , я думаю, что это путает его с '\0' ! поэтому мне интересно, есть ли замена этому методу или есть ли что-нибудь, что вы можете предложить, чтобы решить эту проблему.

PS: Я не уверен, что вопрос дублируется. Я искал ту же проблему, но не нашел удовлетворительного ответа!

Отредактировано:

мой код:

unsigned char Response[269]={0x00};
unsigned char Response_PPSE[269];


for(i=0;i<=strlen(Response);i++)
sprintf(Response_PPSE+(2*i),"%02X",Response[i]);

strlen вычисляет длину только этих байтов: 56 69 56 4F 74 65 63 68 32 00


person Sara Sara    schedule 08.04.2015    source источник
comment
как представлена ​​ваша строка? Помните, что 0 и '0' — это не одно и то же.   -  person Sourav Ghosh    schedule 08.04.2015
comment
Не могли бы вы показать нам свой код?   -  person Thomas Ayoub    schedule 08.04.2015
comment
Это строка цифр (например, "56 69 56 4F 74 ...") или это массив char со значениями 0?   -  person crashmstr    schedule 08.04.2015
comment
Я думаю, это путает его с '\0' ! Нет путаницы. Это одно и то же, символ ASCII 0.   -  person Paul Roub    schedule 08.04.2015
comment
Если вы не хотите останавливаться на первом 0 (это то, что делает strlen() и что длина строки означает в C), как вы ожидаете узнать, когда вы достигли конец строки?   -  person Paul Roub    schedule 08.04.2015
comment
Как вы создали строку?   -  person BLUEPIXY    schedule 08.04.2015
comment
Какая длина у вас получается? Я получаю 152, что правильно (я посчитал). я сделал char a[] = "56 69 5........"; printf("%d",strlen(a));   -  person Arun A S    schedule 08.04.2015
comment
пожалуйста, проверьте обновление @Thomas   -  person Sara Sara    schedule 08.04.2015
comment
Итак, strlen() ведет себя именно так, как ожидалось. Вы так и не сказали, как хотите определять конец строки.   -  person Paul Roub    schedule 08.04.2015
comment
@BLUEPIXY на самом деле я не создаю строку, она генерируется!   -  person Sara Sara    schedule 08.04.2015
comment
Обратите внимание, что массивы и строки C очень примитивны по сравнению с большинством других языков. Поэтому, особенно если вы привыкли к какому-то другому языку, забудьте то, что вы знаете, и узнайте, что эти вещи означают в C (или переключитесь на C++, в котором есть массивы, строки и контейнеры более высокого уровня, если это возможно).   -  person hyde    schedule 08.04.2015
comment
Как вы сгенерировали строку? unsigned char Response[269]={0x00}; : все элементы равны нулю.   -  person BLUEPIXY    schedule 08.04.2015
comment
@BLUEPIXY со смарт-карты через бесконтактные интерфейсы с использованием платежного терминала   -  person Sara Sara    schedule 08.04.2015
comment
Вы должны сохранить размер прочитанных данных.   -  person BLUEPIXY    schedule 08.04.2015
comment
Хотя этот вопрос наивен, я не могу понять, почему люди проголосовали против. Это серьезный вопрос от нового пользователя.   -  person Stephen Canon    schedule 08.04.2015
comment
Ну извините, никто не родился экспертом! @СтивенКанон   -  person Sara Sara    schedule 08.04.2015


Ответы (5)


Другие ответы, которые я видел до сих пор, танцуют вокруг настоящей проблемы. Вам нужно понимать, с какой строкой вы имеете дело.

Согласно историческому соглашению, C представляет строки как массивы оканчивающихся нулевым символом. Это та строка, которую ожидает strlen. Но ваша «строка» содержит нулевые байты. Так что это не строка с завершающим нулем, и strlen не будет делать то, что вы хотите.

Что еще более важно, strlen чрезвычайно опасен и никогда не должен использоваться в современном коде. С помощью strlen легко создать уязвимость в системе безопасности, и велика вероятность того, что если ваша программа использует strlen для проверки ответов, полученных по сети, ваша программа может быть использована для отказа в обслуживании или даже для удаленного выполнения кода.

Более безопасная альтернатива – strnlen, если вы укажете правильное ограничение на размер. Трудно сказать более точно о правильном решении, потому что в вашем примере правильный ответ всегда равен 269, поэтому на самом деле нет строки переменной длины для измерения.

person Ed4    schedule 08.04.2015
comment
Что еще более важно, strlen чрезвычайно опасен ... -- я не согласен. strlen совершенно безопасен, если вы можете гарантировать, что аргумент указывает на допустимую строку с завершающим нулем. Это могут быть даже входные данные, если ввод был получен способом, гарантирующим нулевое завершение (например, fgets). - person Keith Thompson; 08.04.2015

unsigned char Response[269]={0x00};

Это инициализирует Response последовательностью из 269 идентичных значений, каждое из которых равно нулю. Обратите внимание, что 0x00, 0 и '\0' — это одно и то же.

strlen(Response)

На самом деле это недопустимо, хотя некоторые компиляторы могут это разрешать. strlen требует аргумента типа char*; Response — это массив unsigned char, который преобразуется в указатель типа unsigned char*. Типы несовместимы, неявное преобразование отсутствует. Вы должны были получить предупреждение во время компиляции (если да, включите предупреждение в свой вопрос).

Если мы изменим определение Response на:

char Response[269] = {0x00};

тогда вызов strlen становится действительным и возвращает 0. strlen ищет первый '\0' нулевой символ, и вы заполнили Response нулевыми символами.

В верхней части вашего вопроса вы говорите, что у вас есть строка:

56 69 56 4F 74 65 63 68 32 00 2C 00 00 27 6F 23 84 0E 32 50 41 59 2E 53 59 53 2E 44 44 46 30 31 A5 11 BF 0C 0E 61 0C 4F 07 A0 00 00 00 04 10 10 87 01 01

Это не имеет ничего общего с кодом, который вы нам показали. Это также неоднозначно; это строка шестнадцатеричных цифр и пробелов: "56 69 56 ..." или что-то вроде "\x56\x69\x56..."? Если последовательность 56 69 предназначена для представления содержимого вашего массива, обновите свой вопрос, чтобы показать фактический код, который его создает.

Ну наконец то:

for(i=0;i<=strlen(Response);i++)
sprintf(Response_PPSE+(2*i),"%02X",Response[i]);

Вызов strlen на каждой итерации цикла может быть весьма неэффективным. strlen должен каждый раз сканировать всю строку, чтобы определить ее длину. Как только вы устраните другие проблемы, вы должны вызвать strlen один раз перед циклом и использовать сохраненное значение.

Однако вы, вероятно, не хотите использовать strlen в первую очередь. strlen применяется к строкам. «Строка» — это последовательность символов, заканчивающаяся нулевым символом (0, '\0', 0x00). Похоже, у вас есть последовательность символов без знака, в которой 0x00 является допустимым значением, а не терминатором. Вместо того, чтобы использовать strlen для вычисления длины массива, вам нужно отслеживать длину каким-то другим способом.

person Keith Thompson    schedule 08.04.2015
comment
Спасибо за ваш ответ ! Я обязательно сделаю, как вы сказали, и я буду держать вас в курсе о результате :) - person Sara Sara; 08.04.2015
comment
Ну, я изменил unsigned char на char, но проблема осталась. И строка, упомянутая выше, я просто написал так, чтобы показать вам, где она заканчивается! - person Sara Sara; 08.04.2015
comment
@SaraSara: знание того, где он останавливается, не поможет, если мы не знаем, как оно на самом деле выглядит. 56 69 56 4F 74 ... не является представлением строки. Пожалуйста, обновите свой вопрос, чтобы показать нам фактический код, который создает строку. Если ваш массив содержит байты со значениями 0x56, 0x69, 0x56 и т. д., то, конечно, strlen останавливается при встрече с первым 0x00; 0x00 и '\0' это одно и то же. - person Keith Thompson; 08.04.2015
comment
Строка создается с карты через бесконтактный интерфейс Электронного платежного терминала! - person Sara Sara; 08.04.2015
comment
@SaraSara: см. последний абзац моего обновленного ответа. - person Keith Thompson; 08.04.2015
comment
спасибо за ваши ответы! Я буду искать, как вы сказали, другие средства - person Sara Sara; 08.04.2015
comment
Возможно, downvoter захочет объяснить, что не так с этим ответом. - person Keith Thompson; 08.04.2015

00 и '\0' это одно и то же.

Похоже, вы можете получить массив данных, если хотите получить длину массива, а не длину строки. strlen будет сканировать массив до первого нулевого терминатора. Для произвольного массива нет эквивалента, поэтому вам нужно следить за ним самостоятельно.

person Sean    schedule 08.04.2015

Вы имеете в виду длину массива, а не длину ответа, поэтому вам нужен sizeof(Response), а не strlen(Response) - предположительно вы знаете, что ответ имеет длину 269 байтов, потому что это то, что определяет протокол карты.

Вам также нужно, чтобы Response_PPSE имел длину 2 * 269 + 1 байт, потому что в противном случае ваши операторы printf будут выполняться за пределами конца массива. И вам нужно установить Response_PPSE[2*269]=0, чтобы сделать его действительной строкой с завершающим нулем.

person Tom Womack    schedule 09.04.2015

В приложении, которое я сделал, я создал собственный метод «strlen», используя следующий подход, чтобы правильно подсчитать длину, даже если у меня есть нулевые байты в середине моих данных:

-Нам нужно использовать кроме char *, содержащего данные, также размер malloc'а. -Я передаю в метод следующие параметры: первый параметр char *str, второй размер malloc.

-Метод работает наоборот, из адреса MAX памяти (адрес памяти str + второй параметр ) до первого размера памяти, цикл while уменьшает максимальный адрес памяти до тех пор, пока не будет достигнут первый адрес памяти, но этот цикл while прервется, если будет достигнут первый символ, отличный от NULL/0.

-Наконец мы возвращаем разницу между последним MAX адресом памяти и первым адресом памяти char *, +1.

Это мой код:

size_t utils_strlen(const char * str, int max) {
    const char * maxs;
    maxs = str + max;

    while(str<maxs) {
      if(*maxs!=0) break;
      maxs--;
    }

    return(maxs-str)+1;
}
person Diamantis Kyriakakis    schedule 20.07.2017