Вопросы на струнах до

Я плохо знаком с C, и я очень перепутан со струнами до. Следующее является моими вопросами.

Нахождение последнего знака от строки

Как я могу узнать последний знак от строки? Я шел с чем-то как,

char *str = "hello";
printf("%c", str[strlen(str) - 1]);
return 0;

Действительно ли это - способ пойти? Я так или иначе думаю, что, это не корректный путь потому что strlen должен выполнить итерации по символам для получения длины. Таким образом, эта операция будет иметь a O(n) сложность.

Преобразование char кому: char*

Я имею строку и должен добавить символ к нему. Как я могу сделать это? strcat принимает только char*. Я попробовал следующее,

char delimiter = ',';
char text[6];
strcpy(text, "hello");
strcat(text, delimiter);

Используя strcat с переменными, который имеет локальный объем

Рассмотрите следующий код,

void foo(char *output)
{
   char *delimiter = ',';
   strcpy(output, "hello");
   strcat(output, delimiter);
}

В вышеупомянутом коде,delimiter локальная переменная, которая уничтожается после foo возвращенный. Это в порядке для добавления его к переменной output?

Как strcat оконечный знак пустого указателя дескрипторов?

Если я конкатенирую, два пустых указателя завершили строки, будет strcat добавить два пустых оконечных знака к результирующей строке?

Существует ли хорошая статья уровня новичка, которая объясняет, как строки работают в C и как я могу выполнить обычные обработки строк?

Любая справка была бы большой!

6
задан Tim Post 23 February 2011 в 19:04
поделиться

7 ответов

  1. Последний символ: ваш подход правильный. Если вам нужно будет часто делать это для больших строк, ваша структура данных, содержащая строки, должна хранить вместе с ними длины. В противном случае не имеет значения, что это O (n).

  2. Добавление персонажа: у вас несколько ошибок. Во-первых, ваш буфер слишком мал, чтобы вместить еще один символ. Что касается вызова strcat, вы можете либо поместить символ в строку (массив с двумя записями, вторая - 0), либо вы можете просто вручную использовать длину, чтобы написать символ до конца.

  3. Ваше беспокойство по поводу двух терминаторов-нуль безосновательно. Хотя он занимает память, смежную со строкой, и необходим, нулевой байт в конце НЕ является «частью строки» в смысле длины и т. Д. Это просто маркер конца. strcat перезапишет старый nul и поместит новый в самый конец после объединенной строки. Опять же, вам нужно убедиться, что ваш буфер достаточно велик, прежде чем вызывать strcat!

7
ответ дан 8 December 2019 в 12:18
поделиться
  1. O (n) - лучшее, что вы можете сделать, из-за того, как работают строки C.
  2. char delimiter [] = ","; . Это делает разделителем символьный массив, содержащий запятую и NUL. Кроме того, текст должен иметь длину 7. hello - 5, затем у вас есть запятая и NUL.
  3. Если вы правильно определили разделитель, это нормально (как есть, вы назначаете символ для указателя, что неверно). В дальнейшем содержимое вывода не будет зависеть от разделителя.
  4. Он перезапишет первый NUL.

Вы на правильном пути. Я настоятельно рекомендую вам прочитать K&R C 2nd Edition. Это поможет вам со строками, указателями и многим другим. И не забывайте справочные страницы и документацию. Они довольно четко ответят на вопросы, подобные тому, что задан на strcat . Два хороших сайта - это Open Group и cplusplus.com.

5
ответ дан 8 December 2019 в 12:18
поделиться

«Строка C» на самом деле представляет собой простой массив из char s, с str [0] , содержащим первый символ, str [1] второй и так далее. После последнего символа массив содержит еще один элемент , содержащий ноль. Этот ноль по соглашению означает конец строки. Например, эти две строки эквивалентны:

char str[] = "foo"; //str is 4 bytes
char str[] = {'f', 'o', 'o', 0};

А теперь к вашим вопросам:

Поиск последнего символа в строке

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

Преобразование char в char *

Как было сказано ранее, «строка» - это просто массив из char s с добавленным нулевым терминатором в конце. Итак, если вам нужна строка из одного символа, вы объявляете массив из двух char s - вашего символа и последнего нуля, например:

char str[2];
str[0] = ',';
str[1] = 0;

Или просто:

char str[2] = {',', 0};

Используя strcat с переменные с локальной областью видимости

strcat () просто копируют содержимое исходного массива в целевой массив со смещением нулевого символа в целевом массиве. Так что неважно, что происходит с источником после операции. Но вам НЕОБХОДИМО беспокоиться, если целевой массив достаточно велик для хранения данных - иначе strcat () перезапишет все данные, находящиеся в памяти сразу после массива! Необходимый размер: strlen (str1) + strlen (str2) + 1 .

Как strcat обрабатывает завершающий нулевой символ?

Ожидается, что последний ноль завершит обе входные строки и добавляется к выходной строке.

3
ответ дан 8 December 2019 в 12:18
поделиться

Поиск последнего символа в строке

Я предлагаю мысленный эксперимент: если бы вообще было возможно найти последний символ строки лучше, чем за O (n), тогда вы не могли бы также реализовать strlen за время лучше, чем O (n)?

Преобразование char в char *

Вы можете временно сохранить char в массиве - char , и он распадется на a pointer-to- char :

char delimiterBuf[2] = "";
delimiterBuf[0] = delimiter;
...
strcat(text, delimiterBuf);

Однако, если вы используете просто символьные литералы, вы можете просто использовать вместо них строковые литералы.

Использование strcat с переменными, имеющими локальную область видимости

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

Как strcat обрабатывает нулевой завершающий символ?

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

(И если вам интересно, что, если входные строки имеют несколько конечных Уже NUL байтов, я предлагаю еще один мысленный эксперимент: как strcat узнает сколько конечных NUL-байтов в строке?)

Кстати, поскольку вы отметили это «передовым опытом», я также рекомендую вам позаботиться о том, чтобы не писать дальше конца целевых буферов. Обычно это означает отказ от strcat и strcpy (если вы еще не проверили, что входные строки не будут выходить за пределы места назначения) и использование более безопасных версий (например, strncat . Обратите внимание, что strncpy имеет свои подводные камни, поэтому это плохая замена. Существуют также более безопасные нестандартные версии, такие как strlcpy / strlcat и strcpy_s / strcat_s .)

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

1
ответ дан 8 December 2019 в 12:18
поделиться

Как узнать последний символ из строки?

Ваша техника с str[strlen(str) - 1] подходит. Как было указано, вам следует избегать повторных, ненужных вызовов strlen и сохранять результаты.

Мне почему-то кажется, что это не совсем правильный способ, потому что strlen должен перебирать символы, чтобы получить длину. Поэтому эта операция будет иметь O(n) сложность.

Повторяющиеся вызовы strlen могут быть бичом программ на языке Си. Однако следует избегать преждевременной оптимизации. Если профилировщик действительно демонстрирует "горячую точку", где strlen обходится дорого, то вы можете сделать что-то вроде этого для случая с буквенными строками:

const char test[] = "foo";
sizeof test // 4

Конечно, если вы создадите 'test' на стеке, это повлечет за собой небольшие накладные расходы (увеличение/уменьшение указателя стека), но никакой линейной операции по времени не будет.

Буквальные строки обычно не бывают такими гигантскими. В других случаях, например, при чтении большой строки из файла, вы можете заранее сохранить длину строки, чтобы избежать повторного вычисления длины строки. Это также может быть полезно, так как заранее подскажет вам, сколько памяти нужно выделить для буфера символов.

У меня есть строка, и мне нужно добавить к ней символ char к ней. Как я могу это сделать? strcat принимает только char*.

Если у вас есть char и вы не можете сделать из него строку (char* c = "a"), то я полагаю, что вы можете использовать strncat (нужна проверка):

char ch = 'a';
strncat(str, &ch, 1);

В приведенном выше коде разделитель - это локальная переменная, которая уничтожается после того, как будет вычислена. переменная, которая уничтожается после foo возвращается. Можно ли добавить ее к переменную?

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

Если я конкатенирую две нулевые завершенных строк, будет ли strcat добавит два нулевых завершающих символа к результирующей строке?

Нет, strcat просто перезапишет нулевой терминатор в конечной строке и запишет его мимо, а затем добавит новый нулевой терминатор, когда закончит.

1
ответ дан 8 December 2019 в 12:18
поделиться

Как мне найти вывести последний символ из строки?

Ваш подход почти правильный. Единственный способ найти конец строки C - это перебрать символы в поисках нуля.

Но в вашем ответе есть ошибка (в общем случае). Если strlen (str) равен нулю, вы получаете доступ к символу до начала строки.

У меня есть строка, и мне нужно добавить к ней символ. Как я могу это сделать?

Ваш подход неверен. Строка C - это просто массив символов C, последний из которых '\ 0' .Итак, теоретически вы можете добавить такой символ:

char delimiter = ',';
char text[7];
strcpy(text, "hello");
int textSize = strlen(text);
text[textSize] = delimiter;
text[textSize + 1] = '\0';

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

... delimiter - это локальная переменная, которая уничтожается после возврата foo. Можно ли добавлять его в вывод переменной?

Да, нормально. strcat копирует символы. Но ваш образец кода не проверяет, достаточно ли объем вывода для всего, что вы в него вкладываете.

Если я объединяю две строки с завершающим нулем, добавит ли strcat два завершающих символа к результирующей строке?

Нет.

1
ответ дан 8 December 2019 в 12:18
поделиться

Мне почему-то кажется, что это неправильный способ, потому что strlen должен перебирать символы, чтобы получить длину. Таким образом, эта операция будет иметь сложность O (n).

Вы правы, прочитав Джоэла Спольски о , почему С-струны - отстой . Есть несколько способов обойти это. Способы включают в себя либо не использовать строки C (например, использовать строки Pascal и создать свою собственную библиотеку для их обработки), либо не использовать C (используйте, скажем, C ++, у которого есть строковый класс - который медленный по разным причинам, но вы также можете написать ваш собственный, чтобы легче обрабатывать строки Паскаля, чем, например, в C)

Относительно добавления символа в строку C; Строка C - это просто массив символов с нулевым терминатором, пока вы сохраняете терминатор, это строка, никакой магии нет.

char* straddch( char* str, char ch )
{
    char* end = &str[strlen(str)] ;
    *end = ch ;
    end++ ;
    *end = 0 ;
    return str ;
}

Так же, как strcat (), вы должны знать , что массив, в котором создается str , достаточно длинный, чтобы вместить более длинную строку, компилятор вам не поможет. Это одновременно неэлегантно и небезопасно.

Если я объединяю два нулевых завершенные строки, strcat будет добавлять два нулевых завершающих символа в результирующая строка?

Нет, только одна, но все, что следует за ней, может оказаться нулем или тем, что случилось в памяти. Рассмотрим следующий эквивалент:

char* my_strcat( char* s1, const char* s2 )
{
    strcpy( &str[strlen(str)], s2 ) ;
}

первый символ s2 заменяет терминатор в s1.

В приведенном выше коде разделителем является локальный переменная, которая уничтожается после foo вернулся. Можно ли добавить его в переменная output?

В вашем примере разделитель не является строкой, и инициализация указателя с помощью символа не имеет смысла.Однако, если бы это была строка, код был бы в порядке, strcat () копирует данные из второй строки, поэтому время жизни второго аргумента не имеет значения. Конечно, вы можете в своем примере использовать char (не char *) и функцию straddch (), предложенную выше.

1
ответ дан 8 December 2019 в 12:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: