Каковы особенности определения строки в C?

Я должен ответить на вопрос домашнего задания для одного из моих классов. В частности, я должен сказать, считаются ли определенные массивы в C строками или нет. На основе этой статьи (https://www.geeksforgeeks.org/strings-in-c-2/) Я знаю, что строки представляют собой массив символов с завершающим нулем в конце.

Мое основное зависание — это часть вопроса, который спрашивает о массиве, который выглядит так:

char c1[] = { 'C', 'S', '\0', '3', '2', '4', '\0' };

Очевидно, это массив символов с завершающим нулем в конце. Однако считается ли она по-прежнему строкой, поскольку она также имеет нулевой завершающий символ в середине? Как это повлияет на строку?

РЕДАКТИРОВАТЬ: на основе комментариев я предоставил фактическую формулировку вопроса:

«Какие из следующих массивов можно считать «строками» в целях использования их в качестве аргументов для функций strcpy(), strncpy(), strcmp(), strncmp() и подобных строковых функций (указать все применимые)?»

РЕДАКТИРОВАТЬ: я написал об этом своему профессору по электронной почте, так как вопрос казался неоднозначно сформулированным (как указали несколько человек). Если кому-то интересно, он сказал мне: «Да, это строка. Суть в том, что есть нулевой символ. Но, конечно, это повлияет на любые операции со строками; строка заканчивается нулевым символом».


person quango    schedule 21.02.2020    source источник
comment
Является ли вопрос c1 строкой? или c1 содержит строку??   -  person EOF    schedule 22.02.2020
comment
@EOF вопрос: какой из следующих массивов можно считать строками для целей использования их в качестве аргументов для функций strcpy(), strncpy(), strcmp(), strncmp() и подобных строковых функций (укажите все применимые)? Однако это единственный массив, который меня смущает.   -  person quango    schedule 22.02.2020
comment
Можно сказать, что это строка "CS" с добавлением нескольких байтов мусора (в этом случае последний символ NUL не имеет значения). Но это не строка в целом. -- Тем не менее, передача этого на strcpy и т. д. не взорвет ваш компьютер, потому что эти функции будут видеть только часть "CS".   -  person Hagen von Eitzen    schedule 22.02.2020
comment
c1 можно абсолютно использовать в качестве аргумента для strcmp(). Можно ли использовать его в качестве аргумента для изменяемых строковых функций, зависит от дополнительных факторов, которые не указаны.   -  person EOF    schedule 22.02.2020
comment
Вопрос недостаточно конкретен, чтобы любой ответ был правильным. Какой аргумент имеет значение для функций, изменяющих целевую строку, например str[n]cpy().   -  person Andrew Henle    schedule 22.02.2020
comment
Содержимое c1 является изменяемым, поэтому я не понимаю, почему он не может быть допустимым аргументом назначения для strcpy или подобного, если только он не был достаточно большим для размещения исходной строки. Это не сделало бы ее не строкой, а просто не подходящей для данной цели.   -  person John Bollinger    schedule 22.02.2020
comment
В целом согласен, что вопрос сформулирован неоднозначно. Выражение c1 удовлетворило бы основным требованиям к строковым аргументам для всех строковых функций стандартной библиотеки (узких), включая все специально названные, но поведение может не соответствовать ожидаемому или желаемому вызывающей стороне (даже игнорируя неопределенное поведение, которое может быть вызвано) .   -  person John Bollinger    schedule 22.02.2020
comment
Обратите внимание, что type не обязательно должен быть char. Подойдет любой тип символа.   -  person chux - Reinstate Monica    schedule 22.02.2020
comment
Я не думаю, что вопрос двусмысленный вообще. c1 — это массив, содержащий строку CS. Конец истории. Он также содержит некоторые оставшиеся мусорные байты после конца, как и многие строки.   -  person Lee Daniel Crocker    schedule 22.02.2020


Ответы (3)


c1 в основном [1] эквивалентен &c1[0], который содержит одну строку, "CS".

Там скрывается вторая строка, "324", начинающаяся с &c1[3], но пока вы обращаетесь к c1 как c1, строка "CS" представляет собой все функции strcpy() и др. увидел бы.


[1]: c1 — массив, &c1[0] — указатель.

person DevSolar    schedule 21.02.2020
comment
Итак, правильно ли использовать c1 в качестве целевой строки в команде strcpy()? Вопрос неоднозначный - в лучшем случае. - person Andrew Henle; 22.02.2020
comment
Конечно, вы можете использовать c1 в качестве любого аргумента для strcpy(). Это совершенно обычная струна во всех смыслах. Обычные строки часто содержат остаточный мусор после их терминаторов. Тот факт, что этот мусор жестко запрограммирован в программе, создает впечатление, что автор намеревается использовать c1 не строковыми способами, но это не входило в вопрос. - person Lee Daniel Crocker; 22.02.2020
comment
c1 эквивалентно &c1[0] вводит в заблуждение. c1 - это массив. &c1[0] — это указатель. - person chux - Reinstate Monica; 22.02.2020

Если вы хотите узнать особенности определения строки в C, перейдите к источнику.

Из стандарта C90:

7 Библиотека

7.1 Введение

7.1.1 Определения терминов
строка — это непрерывная последовательность символов, заканчивающаяся первым нулевым символом включительно. «Указатель на» строку — это указатель на ее начальный (самый низкий адрес) символ. «Длина» строки — это количество символов, предшествующих нулевому символу, а ее «значение» — это последовательность значений содержащихся символов по порядку.

(В более поздних стандартах не было соответствующих изменений.)

Таким образом, c1 содержит две последовательные строки, CS и 324, но сама не является строкой.

Если мы передаем массив функции, он распадается на указатель на его первый элемент, таким образом, +c1 указывает на строку (первую), что достаточно для любой функции, ожидающей указатель на строку. Он не указывает на строку CS\0324, но этого, вероятно, достаточно для двусмысленного вопроса вашего инструктора.

person Deduplicator    schedule 21.02.2020
comment
Я бы сказал, что даже по этому определению c1 явно является строкой CS. Период. Тот факт, что он может содержать ненулевые байты после терминатора, не имеет значения - многие строки будут такими в течение их жизни. - person Lee Daniel Crocker; 22.02.2020
comment
+c1 указывает на строку, потому что c1 начинается со строки. Однако это никоим образом не делает c1 строкой. - person Deduplicator; 22.02.2020
comment
Это адрес раздела памяти, который содержит символы, оканчивающиеся нулевым байтом. Если бы функция printf() нормально работала с %s, она дала бы совершенно правильное число, переданное в strlen(), сработало бы, если бы оно было передано в strcpy() и т. д. Для меня это звучит как строка. - person Lee Daniel Crocker; 22.02.2020
comment
Да, но это две последовательные строки. Тем не менее, это может засчитываться как вопрос инструктора, который слишком небрежен. - person Deduplicator; 22.02.2020
comment
Вопросы определения, а не факта, часто сложны, потому что инструкторы или книги могут выбирать разные. Но я думаю, что любое определение строки в C, которое делает ответ на этот вопрос отрицательным, является плохим и бесполезным определением. - person Lee Daniel Crocker; 22.02.2020
comment
Хмпф. Выбор определения постфактум в соответствии с ответом, который вы хотите получить, делает определения бессмысленными. В любом случае, вопрос инструктора достаточно двусмысленный, чтобы можно было ответить и да, и нет, в зависимости от того, как вы щуритесь при взгляде. - person Deduplicator; 22.02.2020
comment
Я согласен с опубликованным вами определением, которое описывает последовательность байтов в памяти и которому последовательность байтов по адресу c1 удовлетворяет на 100%. Но это определение ничего не говорит об идентификаторе c1, и вопрос не дает понять, говорим ли мы об идентификаторе или его содержимом. Но поскольку C не имеет строкового типа для идентификаторов, я думаю, что имеет смысл определить строку с точки зрения содержимого памяти, как это делает ваше определение. - person Lee Daniel Crocker; 22.02.2020
comment
c1, массив 7 символов`. Он содержит строку - даже 2 строки. - person chux - Reinstate Monica; 22.02.2020

Добавляя к ответу @DevSolar то, что я обнаружил после игры с данной строкой, если бы это было так:

char c1[] = { 'C', 'S', '\\0', '3', '2', '4', '\\0' };

Если вы выведете эту строку, вы получите CS03240, а размер этой строки равен 7. Насколько я понимаю, \\0 используется для обозначения нулевого символа (т.е. \0). Если вы сделаете:

printf("\0");

Вы ничего не видите в выходном журнале, но если вы это сделаете:

printf("\\0");

Вы видите \0, что ожидаемо, потому что для вывода специальных символов, таких как обратная косая черта или кавычки, вам нужно использовать вместе с ними \.

Что-то, что меня озадачивает, это вывод CS03240 и его размер 7. Общепринято понимать, что размер строки - это количество символов в ней плюс один (для нулевого символа). Кроме того, размер равен 7 даже для строки char c1[] = { 'C', 'S', '\0', '3', '2', '4', '\0' };.

Так что, может быть, продолжение этого вопроса, что здесь происходит?

person rasengan__    schedule 22.02.2020
comment
'\\0' не является нулевым символом. Это многосимвольная константа. Его значение, определенное реализацией, безусловно, выходит за пределы диапазона char. c1[] не является строкой, поскольку в ней отсутствует нулевой символ. вывод этой строки, скорее всего, приведет к неопределенному поведению. - person chux - Reinstate Monica; 22.02.2020
comment
Я не совсем понял вас, хотя искал многосимвольные константы. Если c1[] не является строкой, потому что в конце у нее нет нулевого символа, то почему размер в исходном случае равен 7, как указано в OP? - person rasengan__; 22.02.2020
comment
char c1[] = { 'C', 'S', '\0', '3', '2', '4', '\0' }; имеет размер 7, потому что он инициализирован 7 значениями. Его размер не имеет ничего общего с строками. char c1[] = { 1, 2, 3, 4, 5, 6, 7 }; по-прежнему будет иметь размер 7. - person chux - Reinstate Monica; 22.02.2020
comment
Что касается того, содержит ли массив c1 жало? Это отдельная тема. См. также - person chux - Reinstate Monica; 22.02.2020