2

Хотел бы задать такой вопрос, как можно вычислить длину строки, без использования функции вычисления длины строки strlen()?

navi1893
  • 1,882
  • 6
    sctrlen - это C, в C++ принято использовать string – sercxjo Jun 08 '12 at 08:54
  • 1
    и, соответственно, string::length. http://www.cplusplus.com/reference/string/string/length/ – andrybak Feb 12 '15 at 13:41
  • 2
    Раз уж откопали этот ретровопрос, то можно посмотреть, что реализация strlen() может быть и не столь тривиальна, как во всех местных ответах. – avp Feb 12 '15 at 13:57
  • @navi1893, Если вам дан исчерпывающий ответ, отметьте его как верный (нажмите на галку рядом с выбранным ответом). – Sleeping Owl Feb 12 '15 at 17:32

9 Answers9

13

Можно. Длиной строки по сути является номер позиции символа '\0':

size_t my_strlen(const char *s) {
    const char* cur = s;
    for (; *cur; ++cur);
    return cur - s;
}
dzhioev
  • 11,683
  • 25
  • 38
  • а как вывести результат? Просто вот return запутывает меня =/ – navi1893 Jun 09 '12 at 13:15
  • 9
    Теперь стало все с вами ясно: =)
      return запутывает меня
    
    – AseN Jun 09 '12 at 15:06
  • 1
    @navi1893, my_strlen() это функция. Нужно взять учебник по С/С++, почитать что такое функции и как их вызывать. – insolor Jun 09 '12 at 18:16
  • 4
    s и cur нужно местами поменять в конце. Ещё можно, чтобы за границу строки не выходить: for ( ; *cur; ++cur ); return cur - s; Код для цикла тот же получается – jfs Feb 12 '15 at 22:44
  • 3
    @jfs, спасибо, поправил. Грустно, что такое провисело 3 года, да еще и кучу голосов получило. – dzhioev Jan 30 '16 at 00:27
  • @jfs, там выхода за границу не было. – Qwertiy Sep 29 '16 at 17:23
  • @Qwertiy Представьте *cur=='\0', тогда после *cur++; как в изначальном варианте в return, cur будет указывать за границу строки. Сравните с for (;*cur;++cur), где ++cur не выполняется, если *cur=='\0' и поэтому cur продолжает на конец строки указывать (на ноль). – jfs Sep 29 '16 at 17:54
  • @jfs, да, но оно имеет право туда указывать. – Qwertiy Sep 29 '16 at 18:04
  • @Qwertiy "не было" и "имеет право" это немного разные утверждения. – jfs Sep 29 '16 at 18:30
  • @jfs, выхода за границу строки не было, т. к. указатель не разыменовывается. Он получает значение, указывающее на следующий за концом строки элемент - стандарт разрешает использовать такой указатель (ровно на 1 элемент), если нет разыменования, поэтому указывать туда и использоваться он имеет право. Тут нет противоречия, это две разные мысли. – Qwertiy Sep 29 '16 at 18:40
  • @Qwertiy: да, выхода за границу в смысле разыменования не было. Фразу "чтобы за границу строки не выходить" я неточно применил. Хотел сказать, "чтобы cur за границу не указывал". Хотя, в этом случае, ничего плохого в лишнем сur++ нет, так как именно поддержка полу-открытых интервалов в циклах могла быть мотивацией для включения "one past the last element of the array object" правила в стандарт. (учитывая что код содержал баг c арифметикой указателей, я пытался упростить ситуацию настолько, насколько это возможно—даже если компилятор один и тот же код генерировал бы в итоге) – jfs Sep 29 '16 at 19:42
4

Можно путем итерирования указателя (с начало строки и до терминирующего символа \0) и подсчета числа этих самых итераций - то же, что делает strlen(). Но только зачем это?

vladimir_ki
  • 1,923
  • поставлено учителем такое, ненормальное, условие – navi1893 Jun 08 '12 at 08:55
  • 4
    Вполне нормальное условие, думаю он хочет чтобы вы сами поняли как работает strlen. – AlexDenisov Jun 08 '12 at 08:57
  • Ясно. Видимо, следующим заданием будет обращение строки "своими руками". – vladimir_ki Jun 08 '12 at 08:58
  • Прикол будет, если длина строки будет выше чем пара десятков символов. Скажем, миллион символов. Вот за это я и не люблю С-строки. – PaulD Jun 09 '12 at 11:28
  • Строка в миллион символов? Это ж в какой ситуации такое возможно? – AlexDenisov Jun 09 '12 at 11:34
  • 3

    думаю он хочет чтобы вы сами поняли как работает

    поддерживаю, учитель - умничка

    – northerner Jun 09 '12 at 15:45
  • @AlexDenisov Вполне нормальная ситуация. Насколько я помню ( может где то ошибся ) в файле 1МБ 1048576 символа. Возьмите любой текстовый файл с сотню МБ и получите эту самую ситуацию. В последнее время я с ними частенько работаю ) – Kamo Petrosyan Nov 04 '15 at 12:53
3
int size_s(char *s)
{
    int i;
    for (i = 0; s[i] != '\0'; i++);
    return i;
}

когда-то я писал примерно так.

Nicolas Chabanovsky
  • 51,426
  • 87
  • 267
  • 507
sudo97
  • 1,823
  • @Илья Михневич, а если в строке есть нулевые символы, но после них есть что-то ещё? "\0" - не всегда показатель конца строки... – neo Feb 12 '15 at 13:30
  • 2
    @Kristya, Вы заблуждаетесь. – avp Feb 12 '15 at 13:47
  • 2
    @Kristya: Строка C по определению заканчивается на \0. Точнее, она заканчивается перед ним, \0 не принадлежит самой строке. (Отсюда следует, что C-строка не может содержать \0). В других языках, даже в C++ — не так, строки могут содержать любые символы. (Для случая C++ я имею в виду идиоматический std::string.) – VladD Feb 12 '15 at 17:22
  • 1
    лучше использовать size_t, чтобы избежать переполнения в общем случае, например, в распространённых lp64 и llp64 моделях, где int 32-битный, а указатели и size_t 64-битные. – jfs Feb 12 '15 at 23:03
  • Строка в C таки-да заканчивается на \0, а вот строка в C++ — не обязательно. – VladD Nov 04 '15 at 13:04
0

На 32-битных процессорах так получается быстрее:

size_t strlen( const char *s )
{
  const char *p = s;

  for (;;)
  {
    uint32 c = *((uint32*)p);

    if ( (c - 0x01010101u) & 0x80808080u )
    {
      if ((c & 0x000000ffu) == 0) return p-s+0;
      if ((c & 0x0000ff00u) == 0) return p-s+1;
      if ((c & 0x00ff0000u) == 0) return p-s+2;
      if ((c & 0xff000000u) == 0) return p-s+3;
    }
    p += 4;
  }
}

Тут предполагается, что входная строка выровнена до 32-битной границы (конечно, будет работать и без выравнивания, но тогда весь смысл теряется).

  • Комментарий про strict aliasing, и необязательно четырёхбайтный uint32_t, и возможное нарушение требований по выравниванию. – wololo Jan 13 '18 at 09:33
  • Я сюда этот код размсестил не для того, чтобы его бездумно копипастили, а с целью показать, что строку можно анализировать не только посимвольно, но и блоками по 4 символа (или по 8, если шина данных 64-битная), и это будет намного быстрее. – Костя Jan 19 '18 at 13:22
-1

Файлик main.c

#include <stdio.h>

int main(int argc, char argv[]){ int i = 1; for(;i<argc;i++){ char pStr = argv[i]; int length = 0; while(*pStr++ != '\0'){ length++; } printf("%d\n", length); } }

Собираем

gcc main.c

Запускаем

./a.out some_string

Будет подсчитана длина всех строк, переданных в качестве параметров (some_string)

Итерация начинается с единицы, т.к. первый параметр всегда имя программы.

Собственно strlen так работает =)

AlexDenisov
  • 6,442
  • 1
  • 21
  • 29
  • а что за argc и argv тут??? – navi1893 Jun 08 '12 at 09:20
  • перменные, которые позволяют обрабатывать параметры переданные в приложение извне – AlexDenisov Jun 08 '12 at 10:01
  • 1
    Хм, наверно вендоводы наминусовали =) – AlexDenisov Jun 08 '12 at 10:11
  • 2
    @1101_debian правильно и заминусовали, зачем у тебя дополнительная операция сложения в цикле. –  Jun 09 '12 at 09:36
  • 2
    Вы это о length++? Ну простите, хотел понятней написать, а не мегаоптимальней... – AlexDenisov Jun 09 '12 at 10:28
-1

Способ без циклов и указателей , бесплатно (изначально делал для числовых массивов , но и для строк тоже подойдет , нужно только отнять терминирующий ноль )

#define SIZE_OF_ARRAY(_array) (sizeof(_array) / sizeof(_array[0])-1)
-1

Вот таким не хитрым способом можно:

size_t strlen(const char *s) {
    const char *p;
    for (p = s; *p; ++p);
    return p - s;
}
-1

Ну а как же могли забыть это? Хоть и платформенно-специфичное, конечно :)

xor eax, eax
mov ecx, -1
mov edi, some_string
mov ebx, edi
cld
push ds
pop es
repne scasb
mov eax, edi
sub eax, ebx
dec eax
PinkTux
  • 9,056
-3
#include <iostream>
#include <string>
using namespace std;

int number(string chislosimvolov, int i);

int  main()
{
string chisla;
int i;
cout << "\nEnter stroky:";
cin >> chisla;
cout << "Number of symbols in it is: "<< number(chisla, int (chisla.size()));
 }

int number(string chislosimvolov, int i)
{
    int t;
    if (i== -1) t = 0;  
    else
    t = number(chislo,i-1)
;
return t;
}