2013-04-24 4 views
0

Я прочитал строки с пробелами в них, используя следующий оператор scanf().C язык программирования (scanf)

scanf("%[^\n]", &stringVariableName); 

Что означает строка управления [^\n]?

Есть ли способ читать строки с таким пробелом?

+0

Я рекомендую использовать fgets. – BLUEPIXY

+0

Не забудьте прочитать новую строку, которую вы оставляете в потоке. Кроме того, вы, вероятно, хотите указать максимальную длину, чтобы избежать переполнения буфера. – effeffe

+0

Bluepixy является правильным. scanf - большой риск для безопасности. – ncmathsadist

ответ

5

Это значит «прочитать что-нибудь, пока вы не найдете„\ п“»

Это нормально, но было бы лучше, чтобы сделать это «что-нибудь прочитать, пока вы не найдете„\ п“, или читать больше символов, чем мой буфер поддержки»

char stringVariableName[256] = {} 
if (scanf("%255[^\n]", stringVariableName) == 1) 
    ... 

Edit: убрана & от аргумента, и проверить результат зсапЕ.

+2

+1 для правильного использования размера переменной в спецификации формата. –

+0

@JonathanLeffler Прискорбно, что ширина поля, по-видимому, является единственным фокусом. Есть еще две проблемы с этим кодом. Интересно, найдет ли кто-нибудь еще их ... – Sebivor

+0

@undefinedbehaviour: Адрес массива; и проверить возвращаемое значение из 'scanf()'? Да, вам нужно пойти с тем, что там ... –

4

Указатель формата "%[^\n]" дает указание scanf() читать, но не включает символ новой строки. Из связанного ссылочной страницы:

 
    matches a non-empty sequence of character from set of characters. 

If the first character of the set is ^, then all characters not 
in the set are matched. If the set begins with ] or ^] then the ] 
character is also included into the set. 

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

char buffer[1024]; 
if (fgets(buffer, 1024, stdin)) 
{ 
    /* Remove newline. */ 
    char* nl = strrchr(buffer, '\n'); 
    if (nl) *nl = '\0'; 
} 

Можно указать максимальное количество символов для чтения через scanf():

scanf("%1023[^\n]", buffer); 

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

+0

'scanf' выполняет регулярные выражения? Я так не знал этого. – cHao

+0

@ Чао, это не совсем регулярное выражение. – hmjd

+0

Формат '% [...]' поверхностно напоминает часть синтаксиса regexp, но это не регулярное выражение. – zwol

0

Чтение с человеком страниц для scanf() ...

[Соответствует непустой последовательности символов из определенного набора принятых символов; следующий указатель должен быть указателем на символ, и должно быть достаточно места для всех символов в строке, а также завершающего нулевого байта. Обычный пропущенный пробел подавляется. Строка должна состоять из символов в (или не в) конкретном наборе; набор определяется символами между открытым кронштейном [символ и закрывающей скобкой] символ. Набор исключает эти символы, если первый символ после открытой скобки является circumflex (^). Чтобы включить скот в комплект, сделайте его первым символом после открытой скобки или circumflex; любая другая позиция закончит набор. Символ дефиса - также особенный; при размещении между двумя другими символами он добавляет все входящие символы в набор. К прилагается дефис, сделайте его последним символом перед окончательным закрытием скобки . Например, [^] 0-9-] означает набор «все, кроме , закройте скобки, от нуля до девяти и дефис». Строка заканчивается на внешностью символа, не входящего в комплект (или с набором circumflex, in), или когда заканчивается ширина поля.

В двух словах, [^ \ п] означает, что читать все из строки, которая не является \n и хранить, что в указателе согласования в списке аргументов.

0

Другие люди объяснили, что значит %[^\n].

не хороший способ читать строки. Это так же опасно, как и небезопасное небезопасное gets, и по той же причине: он понятия не имеет, насколько велик буфер на stringVariableName.

Лучший способ прочитать одну полную строку из файла - getline, но не у всех библиотек C есть это. Если вы этого не сделаете, вы должны использовать fgets, который знает, насколько велик буфер, и помните, что вы не можете получить полную строку (если строка слишком длинная для буфера).

+0

'get' * может * знать, насколько большой буфер ... – Sebivor

+0

@undefinedbehaviour Я могу представить себе компилятор, который переписывает' char buf [N]; ... получает (buf); 'как' fgets (buf, N, stdin); 'но насколько я знаю, никакой компилятор в производстве не делает этого. Это то, о чем вы думаете? В противном случае, пожалуйста, объясните. – zwol

+0

Как «realloc» знает, сколько байтов копировать из старого в новый? – Sebivor

2

Технически это невозможно определить.

Соответствует непустой последовательности символов из набора ожидаемых символов (сканирование).

Если ни один модификатор л Длина не присутствует, то соответствующий аргумент должен быть указателем на начальный элемент символьного массива достаточно большого принять последовательность и завершающий нулевой символ, который будет добавлен автоматически.

Предположив декларацию stringVariableName выглядит char stringVariableName[x];, то &stringVariableName является char (*)[x];, не char *. Тип неправильный. Поведение не определено. Это может Работа по совпадению, но все, что полагается на совпадение, не Работа по моему определению.

Единственный способ сформировать char * с помощью &stringVariableName, если stringVariableName является символ! Это означает, что массив символов достаточно велик, чтобы принять завершающий нулевой символ. В случае, когда пользователь вводит один или несколько символов перед нажатием enter, scanf будет писать за пределами массива символов и вызывать неопределенное поведение. В случае, когда пользователь просто нажимает кнопку ввода, директива %[...] потерпит неудачу и даже '\0' не будет записана в ваш массив символов .


Теперь, с этим все сказано и сделано, я предполагаю, что вы имели в виду следующее: scanf("%[^\n]", stringVariableName); (примечание опущенной амперсанд)

Вы действительно должны проверять возвращаемое значение !!

A %[ Директива %[ вызывает scanf для извлечения последовательности символов, состоящих из тех, которые указаны между квадратами квадратных скобок []. A ^ в начале набора указывает, что нужный набор содержит все символы, кроме тех, которые находятся между скобками. Следовательно, %[^\n] сообщает scanf читать как можно больше символов не '\n' и хранить их в массиве, на который указывает соответствующий char *.

'\n' будет оставлен непрочитанным. Это может вызвать проблемы. Пустое поле приведет к ошибке совпадения. В этой ситуации возможно, что никакие данные не будут скопированы в ваш массив (даже не заканчивающийся символ '\0'). По этой причине (и другим), вам действительно нужно проверить возвращаемое значение!

В каком руководстве содержится информация о возвращаемых значениях scanf? The scanf manual.