Количество элементов в массиве char

Какую функцию можно использовать, чтобы узнать, сколько элементов содержится в массиве char?

sizeof() дает количество доступных «пробелов», поэтому у меня это не работает.

, 👍2

Обсуждение

Можете ли вы привести пример, пожалуйста? например. char foo[100] = "bar"; - это то, что вы имеете в виду? Вы хотите ответ: 3?, @Nick Gammon

Да все верно, @Federico Corazza


3 ответа


Лучший ответ:

11

Вам нужен strlen.

char foo [100] = "bar";
Serial.println (strlen (foo));   // --> печатает 3
,

Если ответ сработал для вас, нажмите кнопку «принять» (она выглядит как галочка). Таким образом, другие люди узнают, что решение сработало., @Nick Gammon

Мне пришлось подождать пару минут, чтобы сделать это, @Federico Corazza

Обратите внимание, что это будет *только* работать, если данные в вашем char[] содержат строку ascii и должным образом заканчиваются нулем. Кроме того, если у вас есть длинная строка в char[], и вы перезаписываете ее более короткой строкой без добавления завершающего нуля, вы получите размер старой строки., @Connor Wolf

Совершенно верно. Мой ответ был на вопрос, как представлено. Упомянутые вами вещи следует учитывать для строк C с нулевым завершением., @Nick Gammon


3

Я знаю, что у вас есть ответ от @NickGammon, но я просто хотел бы добавить немного более подробной информации о том, как все это работает.

sizeof() не является функцией в обычном смысле этого слова. Это оператор, который дает вам количество байтов памяти, выделенных для того, что вы ему передаете. Если вы передаете ему массив, он возвращает количество байтов, доступных для этого массива. Если вы передаете ему указатель на массив, он возвращает размер этого указателя, а не размер массива. Если вы передаете ему целочисленную переменную, она возвращает количество байтов, используемых этой целочисленной переменной (2 в 8-битной системе, такой как AVR, 4 в 32-битной системе, такой как Due).

Итак, несколько примеров:

char array[50] = "hello";
// sizeof(массив) = 50.
char *array_p = array;
// sizeof(array_p) = 2 или 4 в зависимости от архитектуры.
char single = 'a';
// sizeof(single) = 1.
char string[] = "hello";
// sizeof(string) = 6 (5 символов плюс \0) - он выделяет память во время компиляции, чтобы уместить строку

Теперь strlen(). Чем именно это отличается от sizeof()? Проще говоря, strlen() подсчитывает количество символов в массиве символов до тех пор, пока не достигнет символа \0, который является "NULL" завершающим символом строки C. Возьмем приведенные выше примеры, но вместо этого используем strlen:

char array[50] = "hello";
// strlen(массив) = 5.
char *array_p = array;
// strlen(array_p) = 5.
char single = 'a';
// strlen(single) = ОШИБКА! strlen() не работает с отдельными символами.
char string[] = "hello";
// strlen(строка) = 5.

Вы заметили, что он всегда возвращает количество символов в строке до завершающего символа \0, но не включая его.

В своей простейшей форме функция strlen() может выглядеть так:

int strlen(const char *data) {
    int c = 0;
    const char *p = data;
    while (*p) {
        c++;
        p++;
    }
    return c;
}

В основном он начинается с первого символа в строке (*p = data), проверяет, является ли это \0 или нет (while (*p )), увеличивает количество символов (c++) и переходит к следующему символу в строке (p++).

Если вы хотите выполнить итерацию по строке в своей программе, вы можете сначала вызвать strlen(), чтобы получить количество символов в строке, а затем использовать это значение в цикле. Это немного расточительно, так как strlen() сначала выполняет итерацию по строке, поэтому в итоге вы выполняете итерацию дважды. Гораздо эффективнее узнать, как лучше всего перемещаться по каждому символу в строке, пока не будет найден завершающий символ, например, как функция strlen() использует указатель для двигаться по памяти. Вы также можете видеть, насколько важно убедиться, что символ \0 существует в конце строки, иначе как такие функции, как strlen(), узнают, когда остановиться ? Они не могут знать длину строки (sizeof() вернет размер переданного указателя, а не размер массива), поэтому им нужен какой-то ручной маркер. , а в C принято использовать \0.

Обратите внимание, что функции Arduino print() на самом деле делают это очень неэффективно. Если вы сделаете что-то вроде:

char message[] = "Hello";
Serial.println(message);

На самом деле он будет выполнять довольно много работы, в которой действительно нет необходимости. Шаг за шагом это:

  1. вызывает println(сообщение)
  2. который вызывает запись(сообщение)
  3. который получает длину строки с помощью strlen(message)
  4. и вызывает write(message, length)
  5. который затем выполняет цикл от 0 до длины 1, отправляя каждый символ сообщения в write() по очереди.
  6. наконец печатает \r\n для новой строки.

Таким образом, на самом деле он заканчивается вложенностью около 4 функций и выполняет итерацию всей строки дважды. Классический пример того, как тратить время на обработку. Повторяя строку один раз в поисках символа \0 в функции write(message) (шаг 2), она будет работать как минимум в два раза быстрее. Старый добрый Ардуино...

,

Что касается «В простейшей форме функция strlen() может выглядеть так», в более короткой (возможно, более простой?) форме она может выглядеть так: int strlen(const char *data) { const char *p = данные; пока (*р++); вернуть p-данные-1; }, @James Waldby - jwpat7

@ jwpat7 Я сказал «самый простой», а не «самый короткий и компактный». Эта форма, хотя и меньше и эффективнее, гораздо труднее понять ОП (который, очевидно, * не * программист)., @Majenko

Согласен :) Также легче допустить ошибку. И если \0 является последним доступным байтом в сегменте, *p++ будет ошибкой. Но int strlen(const char *data) { const char *p = data; пока (*р)++р; вернуть p-данные; } позволяет избежать этой проблемы., @James Waldby - jwpat7

На самом деле, *p++ не будет ошибаться, даже если \0 будет последним доступным байтом в сегменте; часть *p будет обращаться к последнему байту; часть ++ установит p на недопустимый адрес; но поскольку этот неверный адрес не упоминается, на типичной машине не возникает никаких ошибок., @James Waldby - jwpat7

*Это макрос времени компиляции...* Это не **макрос**, это **оператор** (например, "+" и "-" являются операторами). Они более низкого уровня, чем макросы, которые выполняются во время препроцессора. См. [оператор sizeof](http://en.cppreference.com/w/cpp/language/sizeof). Также [Операторы в C++](https://www.tutorialspoint.com/cplusplus/cpp_operators.htm), @Nick Gammon

В самом деле. Три года назад я думал иначе., @Majenko


-4
использовать sizeof

символ ннн[10];
for(int i=0; i< sizeof(nnn)/sizeof(char); i++){

}


,

Вы правильно прочитали вопрос?, @gre_gor

ОП сказал, что «sizeof» «у меня не работает», а затем вы предлагаете использовать sizeof., @Nick Gammon

не могу ответить на вопрос при использовании одного и того же неизвестного, @Guy . D