Foreversoft.ru

IT Справочник
1 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Strlen си реализация

C реализация strlen() в одной строке кода

вчера я был на собеседовании и меня попросили реализовать strlen() в C без использования каких-либо стандартных функций, все вручную. Как абсолютный любитель, я реализовал примитивную версию с while loop. Глядя на это, мой интервьюер сказал, что он может быть реализован только в одной строке кода. В тот момент я не смог создать этот код, используя этот термин. После интервью я обратился к коллегам, и самые опытные из них дали мне это произведение, которое действительно сработало отлично:

итак, возникает вопрос, возможно ли это без использования рекурсии, и если да, то как? Условия:

  • без какого-либо ассемблера
  • без каких-либо функций C существовали в библиотеках
  • без просто написания нескольких строк кода в одном

пожалуйста, обратите внимание, что это не вопрос оптимизации или реального использования, просто возможность сделать задачу.

9 ответов

подобно ответу @DanielKamilKozar, но с for-loop, вы можете сделать это без тела for-loop, и len инициализируется должным образом в функции:

лучшее, что я мог придумать, это это, но это не стандарт strlen поскольку сама функция имеет другой прототип. Кроме того, предполагается, что *len равен нулю на старте.

мне любопытно, как стандартный strlen может быть реализовано в «одной строке кода», потому что для этого потребуется return , что является «одной строкой кода», судя по тому, что вы опубликовали.

тем не менее, я согласен с комментариями о том, что это невероятно глупое интервью вопрос.

Если это не должно быть функцией, этот однострочный, вероятно, самый простой и короткий способ вычислить длину любого массива с нулевым завершением (не включая объявления переменных и печати):

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

Это, кажется, работает нормально.

это, вероятно, самый эффективный способ реализации strlen. Большинство компиляторов используют этот реализованный так или иначе.

Это может быть немного сложнее понять, особенно если вы не изучили указатели.

Как насчет пустого цикла for. Как

вопреки тому, что говорят другие, это невозможно если соблюдаются некоторые разумные ограничения. Ограничения:

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

любая функция с подписью strlen должен иметь оператор возврата. Оператор return состоит из return ключевое слово и выражение. Язык C не имеет выражений, которые выполняют циклы. Для этого требуется оператор, но эта позиция зарезервирована для оператора return.

если ослабить эти ограничения (скажем, изменить подпись или не считать операторы возврата и / или объявления и / или тела составных операторов, пока они «просты», как отдельные» строки»), задача становится возможной и скорее простой, как видно из многих примеров здесь и во всем интернете.o

по сравнению со str[i] приведенный выше код, который увеличивает указатель, будет работать лучше, потому что индексирование str[i] будет оцениваться как: *(str + i), что является операцией сложения, выполняемой с каждым циклом, в то время как операция приращения быстрее.

кроме того, по сравнению с strlen(const char *str, size_t *len) нет необходимости в дополнительном параметре, который предоставил бы вызывающий.

наконец, он находится на одной строке в соответствии с исходным запросом.

вы можете заменить ‘ ‘ на ноль, но я предпочитаю, как это

Функции обработки строк в Cи

В программе строки могут определяться следующим образом:

  • как строковые константы;
  • как массивы символов;
  • через указатель на символьный тип;
  • как массивы строк.

Кроме того, должно быть предусмотрено выделение памяти для хранения строки.

Любая последовательность символов, заключенная в двойные кавычки «» , рассматривается как строковая константа .

Для корректного вывода любая строка должна заканчиваться нуль-символом ‘’ , целочисленное значение которого равно 0. При объявлении строковой константы нуль-символ добавляется к ней автоматически. Так, последовательность символов, представляющая собой строковую константу, будет размещена в оперативной памяти компьютера, включая нулевой байт.

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

Для помещения в строковую константу некоторых служебных символов используются символьные комбинации. Так, если необходимо включить в строку символ двойной кавычки, ему должен предшествовать символ «обратный слеш»: ‘»‘ .

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

При определении массива символов необходимо сообщить компилятору требуемый размер памяти.

Компилятор также может самостоятельно определить размер массива символов, если инициализация массива задана при объявлении строковой константой:

В этом случае имена m2 и m3 являются указателями на первые элементы массивов:

  • m2 эквивалентно &m2[0]
  • m2[0] эквивалентно ‘Г’
  • m2[1] эквивалентно ‘o’
  • m3 эквивалентно &m3[0]
  • m3[2] эквивалентно ‘x’
Читать еще:  Спецификаторы в си printf

При объявлении массива символов и инициализации его строковой константой можно явно указать размер массива, но указанный размер массива должен быть больше, чем размер инициализирующей строковой константы:

Для задания строки можно использовать указатель на символьный тип .

В этом случае объявление массива переменной m4 может быть присвоен адрес массива:

Здесь m3 является константой-указателем. Нельзя изменить m3 , так как это означало бы изменение положения (адреса) массива в памяти, в отличие от m4 .

Для указателя можно использовать операцию увеличения (перемещения на следующий символ):

Массивы символьных строк

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

В этом случае poet является массивом, состоящим из четырех указателей на символьные строки. Каждая строка символов представляет собой символьный массив, поэтому имеется четыре указателя на массивы. Указатель poet[0] ссылается на первую строку:
*poet[0] эквивалентно ‘П’,
*poet[l] эквивалентно ‘-‘.

Инициализация выполняется по правилам, определенным для массивов.
Тексты в кавычках эквивалентны инициализации каждой строки в массиве. Запятая разделяет соседние
последовательности.
Кроме того, можно явно задавать размер строк символов, используя описание, подобное такому:

Разница заключается в том, что такая форма задает «прямоугольный» массив, в котором все строки имеют одинаковую длину.

Свободный массив

Операции со строками

Большинство операций языка Си, имеющих дело со строками, работает с указателями. Для размещения в оперативной памяти строки символов необходимо:

  • выделить блок оперативной памяти под массив;
  • проинициализировать строку.

Для выделения памяти под хранение строки могут использоваться функции динамического выделения памяти. При этом необходимо учитывать требуемый размер строки:

Для ввода строки использована функция scanf() , причем введенная строка не может превышать 9 символов. Последний символ будет содержать ‘’ .

Функции ввода строк

Для ввода строки может использоваться функция scanf() . Однако функция scanf() предназначена скорее для получения слова, а не строки. Если применять формат «%s» для ввода, строка вводится до (но не включая) следующего пустого символа, которым может быть пробел, табуляция или перевод строки.

Для ввода строки, включая пробелы, используется функция

В качестве аргумента функции передается указатель на строку, в которую осуществляется ввод. Функция просит пользователя ввести строку, которую она помещает в массив, пока пользователь не нажмет Enter.

Функции вывода строк

Для вывода строк можно воспользоваться рассмотренной ранее функцией

или в сокращенном формате

Для вывода строк также может использоваться функция

которая печатает строку s и переводит курсор на новую строку (в отличие от printf() ). Функция puts() также может использоваться для вывода строковых констант, заключенных в кавычки.

Функция ввода символов

Для ввода символов может использоваться функция

которая возвращает значение символа, введенного с клавиатуры. Указанная функция использовалась в рассмотренных ранее примерах для задержки окна консоли после выполнения программы до нажатия клавиши.

Функция вывода символов

Для вывода символов может использоваться функция

которая возвращает значение выводимого символа и выводит на экран символ, переданный в качестве аргумента.

Пример Посчитать количество введенных символов во введенной строке.

Результат выполнения

Основные функции стандартной библиотеки string.h

Основные функции стандартной библиотеки string.h приведены в таблице.

ФункцияОписание
присоединяет s2 к s1, возвращает s1
присоединяет не более n символов s2 к s1, завершает строку символом ‘’, возвращает s1
копирует строку s2 в строку s1, включая ‘’, возвращает s1
копирует не более n символов строки s2 в строку s1, возвращает s1;
сравнивает s1 и s2, возвращает значение 0, если строки эквивалентны
сравнивает не более n символов строк s1 и s2, возвращает значение 0, если начальные n символов строк эквивалентны
возвращает количество символов в строке s
заполняет строку s символами, код которых равен значению c, возвращает указатель на строку s
заменяет первые n символов строки s символами, код которых равен c, возвращает указатель на строку s

Пример использования функций

Результат выполнения

Урок №79. Строки C-style

Обновл. 31 Дек 2019 |

В уроке №57 мы определили термин «строка» как набор последовательных символов (например, Hello, world! ). Строки — это основной способ работы с текстом в C++, а std::string упрощает это взаимодействие.

Современный C++ поддерживает два разных типа строк:

std::string (как часть стандартной библиотеки);

строки C-style (изначально унаследованные от языка C).

std::string реализован с помощью строк C-style.

Строки C-style

Строка C-style — это простой массив символов, который использует нуль-терминатор. Нуль-терминатор — это специальный символ (код ASCII — 0), используемый для обозначения конца строки. Строка C-style ещё называется «нуль-терминированной строкой».

Для её определения нужно просто объявить массив типа char и инициализировать его литералом (например, string -ом):

Хотя string имеет только 6 букв, C++ автоматически добавляет нуль-терминатор в конец строки (нам не нужно добавлять его вручную). Следовательно, длина массива mystring на самом деле равна 7!

В качестве примера рассмотрим следующую программу, которая выводит длину строки, а затем коды ASCII всех символов литерала string :

Результат выполнения программы выше:

string has 7 characters.
115 116 114 105 110 103 0

Нуль в конце является кодом ASCII нуль-терминатора, который был добавлен в конец строки.

При таком объявлении строк рекомендуется использовать квадратные скобки [], чтобы позволить компилятору определить длину массива самому. Таким образом, если вы измените строку позже, вам не придётся вручную изменять значение длины массива.

Важно отметить, что строки C-style следуют всем тем же правилам, что и массивы. Это означает, что вы можете инициализировать строку при создании, но после этого не сможете присваивать ей значения с помощью оператора присваивания:

Это то же самое, как если бы мы сделали следующее:

Поскольку строки C-style являются массивами, то вы можете использовать оператор [] для изменения отдельных символов в строке:

Результат выполнения программы выше:

При выводе строки C-style std::cout выводит символы до тех пор, пока не встретит нуль-терминатор. Если бы вы случайно перезаписали нуль-терминатор в конце строке (например, присвоив что-либо для mystring[6] ), то вы не только бы получили все символы строки, но std::cout также вывел бы всё, что находится в соседних слотах памяти до тех пор, пока не попадётся 0!

Обратите внимание, это нормально, если длина массива больше строки, которую он хранит:

В этом случае строка Max будет выведена, а std::cout остановится на нуль-терминаторе. Остальные символы в массиве будут проигнорированы.

Строки C-style и std::cin

Есть много случаев, когда мы не знаем заранее, насколько длинной будет наша строка. Например, рассмотрим проблему написания программы, где мы просим пользователя ввести своё имя. Насколько длинным оно будет? Это неизвестно до тех пор, пока пользователь его не введёт!

В таком случае мы можем объявить массив размером больше, чем нам нужно:

В программе выше мы объявили массив из 255 символов, предполагая, что пользователь не введёт имя длиннее 255 символов. Хоть это и распространённая практика, но она не очень эффективна, так как пользователю ничего не мешает ввести имя более 255 символов (случайно или намеренно).

Намного лучше сделать следующим образом:

Вызов cin.getline() будет принимать до 254 символов в массив name (оставляя место для нуль-терминатора!). Любые лишние символы будут проигнорированы. Таким образом, мы можем гарантировать, что массив не будет переполнен!

Управление строками C-style

C++ предоставляет множество функций для управления строками C-style, которые подключаются с помощью заголовочного файла cstring. Вот несколько самых полезных функций:

Функция strcpy_s() позволяет копировать содержимое одной строки в другую. Чаще всего это используется для присваивания значений строке:

Тем не менее, использование strcpy_s() может легко вызвать переполнение массива, если не быть осторожным! В следующей программе, длина массива dest меньше длины копируемой строки, поэтому в результате мы получим переполнение массива:

Ещё одной полезной функцией управления строками является функция strlen(), которая возвращает длину строки C-style (без учёта нуль-терминатора):

Результат выполнения программы выше:

My name is Max
Max has 3 letters.
Max has 15 characters in the array.

Обратите внимание на разницу между strlen() и sizeof(). strlen() выводит количество символов до нуль-терминатора, тогда как оператор sizeof() возвращает размер целого массива, независимо от того, что в нём находится.

Вот ещё полезные функции для управления строками C-style:

strcat() — добавляет одну строку к другой (опасно);

strncat() — добавляет одну строку к другой (с проверкой размера места назначения);

strcmp() — сравнивает две строки (возвращает 0, если они равны);

strncmp() — сравнивает две строки до определённого количества символов (возвращает 0, если они равны).

Длина строки — функция strlen( )

Длина строки — функция strlen( )

В предыдущей главе мы практически без объяснений использовали операцию sizeof, которая дает нам размер объектов в байтах Функция strlen( ) позволяет определять длину строки числом символов. Поскольку для размещения одного символа в памяти отводится 1 байт, можно было бы предположить, что в результате применения любой из этих двух операций к одной строке будет получен одинаковый результат. Оказывается, это не так. Давайте немного изменим нашу предыдущую программу (добавим к ней несколько строк), и тогда мы поймем, в чем дело.

#define PRAISE » Вот это да, какое великолепное имя!»

printf(» Как вас зовут? «);

printf(» Привет, %s. %s » , name, PRAISE);

printf(» Ваше имя состоит из %d букв и занимает %d ячеек памяти. «,

strlen (name), sizeof name);

printf(» Хвалебная фраза состоит из %d букв», strlen (PRAISE));

printf(» и занимает %d ячеек памяти. «, sizeof PRAISE);

Заметим, что случайно мы воспользовались двумя методами для обработки длинных операторов printf(). В первом случае мы, записав один оператор печати в двух строках программы. Мы сделали это, поскольку разрешается разбивать строку между аргументами, но не посередине строки. В другом случае использовались два оператора printf() для печати одной строки; мы указали символ «новая строка» ( ) только во втором из них. Представленный ниже результат работы данной программы поможет понять подобную ситуацию:

Привет, Перки. Вот это да, какое великолепное имя!

Ваше имя состоит из 5 букв и занимает 50 ячеек памяти.

Хвалебная фраза состоит из 35 букв и занимает 36 ячеек памяти.

Давайте посмотрим, в чем дело. Массив name занимает 50 ячеек памяти, и именно об этом сообщает операция sizeof. Но для хранения имени Перки требуются только первые пять ячеек, и как раз об этом нас информирует функция strlen( ). В шестой ячейке массива name содержится нуль-символ, и его появление служит сигналом для функции strlen( ) прекратить подсчет символов

РИС.4.4. Распознавание функцией strlen( ) конца строки

При переходе к обработке константы PRAISE обнаруживается, что функция strlen( ) опять дает нам точное число символов (включая пробелы и знаки пунктуации) в строке. Результат операции sizeof оказывается на единицу большим, поскольку при этом учитывается и «невидимый» нуль-символ, помещенный в конец строки. Мы не указываем компилятору, какой объем памяти он должен отвести для размещения всей фразы, он сам подсчитывает число символов между кавычками.

Еще одно замечание в предыдущей главе была использована операция sizeof со скобками, а в этой — без них. Решение, использовать ли скобки или нет, зависит от того, что вы хотите знать объем памяти, отводимый под элементы конкретного типа, или объем памяти, занимаемый определенным объектом В первом случае вы писали бы sizeof(char) или sizeof(float), а во втором — sizeof name или sizeof 6.28.

Похожие главы из других книг:

6.13.3 Версия, длина заголовка и длина датаграммы

6.13.3 Версия, длина заголовка и длина датаграммы В настоящее время используется четвертая версия IP (версия «Следующее поколение» имеет номер 6).Длина заголовка измеряется в 32-разрядных словах. Если не нужны дополнительные варианты, можно ограничиться длиной заголовка в 5

Длина дуги

Длина дуги С помощью команды DIMARC создается размер длины дуги, указывающий расстояние вдоль дуги или дугового сегмента полилинии (рис. 11.14). Чтобы отличать эти размеры от линейных и угловых, для размеров длины дуги по умолчанию отображается символ дуги. Команда вызывается

Длина дуги

Длина дуги С помощью команды DIMARC создается размер длины дуги, указывающий расстояние вдоль дуги или дугового сегмента полилинии (рис. 11.14). Чтобы отличать эти размеры от линейных и угловых, для размеров длины дуги по умолчанию отображается символ дуги. Команда

Особенности кодирования литеральных символов и пар расстояние/длина

Особенности кодирования литеральных символов и пар расстояние/длина В предыдущих разделах ничего не было сказано о небольшом нюансе реализации алгоритма: как в процессе считывания сжатых данных отличить литеральный символ от кода расстояние/длина? В конце концов, не

Строки

Строки CharPrev Функция CharPrev возвращает указатель на предшествующий символ в строке. Функция заменяет функцию AnsiPrev . LPTSTR CharPrev ( LPCTSTR lpszStart , // указатель на первый символ LPCTSTR lpszCurrent // указатель на текущий символ ); Параметры lpszStart — указатель на начало строки. lpszCurrent — указатель

Длина дуги

Длина дуги С помощью команды DIMARC создается размер длины дуги , указывающий расстояние вдоль дуги или дугового сегмента полилинии (рис. 11.19). Чтобы отличать эти размеры от линейных и угловых, для размеров длины дуги по умолчанию отображается символ дуги. Команда

Пример 9-15. Длина переменной

Пример 9-15. Длина переменной #!/bin/bash# length.shE_NO_ARGS=65if [ $# -eq 0 ] # Для работы скрипта необходим хотя бы один входной параметр.then echo «Вызовите сценарий с одним или более параметром командной строки.» exit $E_NO_ARGSfivar01=abcdEFGH28ijecho «var01 = $«echo «Length of var01 = $<#var01>«echo «Количество входных

Длина дуги

Длина дуги С помощью команды DIMARC создается размер длины дуги, указывающий расстояние вдоль дуги или дугового сегмента полилинии (рис. 10.10). Чтобы эти размеры отличались от линейных и угловых, для размеров длины дуги по умолчанию показан символ дуги. Команда вызывается из

2.5 Строки

2.5 Строки Строка есть последовательность символов, заключенная в двойные кавычки: «. ». Строка имеет тип «массив символов» и класс памяти static (см. #4 ниже), она инициализируется зданными символами. Все строки, даже если они записаны одинково, различны. Компилятор

Какова длина второго имени?

Какова длина второго имени? Как бы стеки не заставили нас забыть, что кроме излюбленных специалистами по информатике примеров имеются структуры данных, тесно связанные с объектами реальной жизни. Вот забавный пример, взятый из почты форума Риски (Risks) (группа новостей Usenet

Строки

Строки Класс STRING описывает символьные строки. Он имеет специальный статус, поскольку нотация допускает манифестные строковые константы, обозначающие экземпляры STRING.Строковая константа записывается в двойных кавычках, например,»ABcd Ef

Ссылка на основную публикацию
Adblock
detector