Я пытаюсь получить некоторые данные от пользователя и отправить их в другую функцию в gcc. Код примерно такой.
printf("Enter your Name: ");
if (!(fgets(Name, sizeof Name, stdin) != NULL)) {
fprintf(stderr, "Error reading Name.\n");
exit(1);
}
Тем не менее, я обнаружил, что \n
в конце он имеет символ новой строки . Так что, если я вхожу, John
это заканчивается отправкой John\n
. Как мне удалить это \n
и отправить правильную строку.
if (!fgets(Name, sizeof Name, stdin))
(по крайней мере, не используйте два отрицания,! и! =)if (fgets(Name, sizeof Name, stdin)) {
.if (fgets(Name, sizeof Name, stdin) == NULL ) {
!
:Ответы:
Немного безобразный способ:
Немного странный способ:
Обратите внимание, что
strtok
функция не работает должным образом, если пользователь вводит пустую строку (т.е. нажимает только Enter). Это оставляет\n
персонажа нетронутым.Конечно, есть и другие.
источник
strtok()
будет поточно-безопасной (она будет использовать локальное хранилище потоков для состояния 'inter-call'). Тем не менее, в целом все же лучше использовать нестандартный (но достаточно распространенный)strtok_r()
вариант.strtok
подход (и он работает с пустыми входами). На самом деле хорошим способом реализацииstrtok
является использованиеstrcspn
иstrspn
.*strchrnul(Name, '\n') = '\0';
.strchr(Name, '\n') == NULL
, кроме «слишком длинного ввода для буфера, есть ошибка флага», существуют и другие возможности: последний текст вstdin
не заканчивался'\n'
символом или был прочитан редкий внедренный нулевой символ.Возможно, самое простое решение использует одну из моих любимых малоизвестных функций
strcspn()
:Если вы хотите, чтобы он также обрабатывал
'\r'
(скажем, если поток двоичный):Функция считает количество символов до тех пор, пока не достигнет a
'\r'
или a'\n'
(другими словами, она найдет первый'\r'
или'\n'
). Если он ничего не ударил, он останавливается на'\0'
(возвращая длину строки).Обратите внимание, что это работает нормально, даже если нет новой строки, потому что
strcspn
останавливается на'\0'
. В этом случае вся строка просто заменяется'\0'
на'\0'
.источник
buffer
чем начинается с'\0'
, то , что приводит к печальным последствиям дляbuffer[strlen(buffer) - 1] = '\0';
подхода.strcspn()
. Одна из наиболее полезных функций в библиотеке, IMO. Я решил написать и опубликовать кучу распространенных C-хаков, подобных этому сегодня;strtok_r
реализация с использованиемstrcspn
иstrspn
был одним из первых: codepad.org/2lBkZk0w ( Внимание: я не могу гарантировать , что это без ошибок, она была написана наспех и , вероятно, некоторые из них). Я пока не знаю, где я их опубликую, но я намерен сделать это в духе знаменитых «хихиканьях».fgets()
. Это ,strcspn()
кажется, единственный правильный один вкладыш.strlen
быстрее - хотя и не так просто.fgets()
ввода . Который всегда является также первой новой строкой.источник
fgets(buf, size, ....)
->strlen(buf) == 0
. 1)fgets()
читается как первыйchar
а'\0'
. 2)size == 1
3)fgets()
возвращаетNULL
тогдаbuf
содержимое может быть что угодно. (Хотя код OP проверяет NULL). Предложить:size_t ln = strlen(name); if (ln > 0 && name[ln-1] == '\n') name[--ln] = '\0';
ln
будет -1, за исключением того, что фактsize_t
без знака, таким образом, запись в случайную память. Я думаю, что вы хотите использоватьssize_t
и проверьтеln
> 0.strlen
) может быть реализован намного эффективнее, чем простой поиск по типу символов. По этой причине я бы посчитал это решение лучше, чем основанноеstrchr
илиstrcspn
основанное.Ниже приведен быстрый подход к удалению потенциала
'\n'
из строки, сохраненной с помощьюfgets()
.Используется
strlen()
с 2-мя тестами.Теперь используйте
buffer
и поlen
мере необходимости.Этот метод имеет побочное преимущество
len
значения для последующего кода. Это может быть легко быстрее, чемstrchr(Name, '\n')
. Реф YMMV, но оба метода работают.buffer
, из оригиналаfgets()
не будет содержаться"\n"
при некоторых обстоятельствах:A) слишком длинная строка,
buffer
поэтому сохраняется толькоchar
предшествующее . Непрочитанные символы остаются в потоке. Б) Последняя строка в файле не заканчивается на .'\n'
buffer
'\n'
Если во входных данных есть где-то встроенные нулевые символы
'\0'
, длина, указанная пользователемstrlen()
, не будет включать'\n'
местоположение.Некоторые другие ответы на вопросы:
strtok(buffer, "\n");
не удается удалить,'\n'
когдаbuffer
есть"\n"
. Из этого ответа - исправлены после этого ответа, чтобы предупредить об этом ограничении.Следующий сбой в редких случаях , когда первое
char
чтение наfgets()
это'\0'
. Это происходит, когда ввод начинается со встроенного'\0'
. Тогдаbuffer[len -1]
становитсяbuffer[SIZE_MAX]
доступ к памяти определенно за пределами законного диапазонаbuffer
. Что-то хакер может попробовать или найти в глупом чтении текстовых файлов UTF16. Это было состояние ответа, когда этот ответ был написан. Позже не-OP отредактировал его, включив в него код, подобный проверке этого ответа""
.sprintf(buffer,"%s",buffer);
не определено поведение: Ref . Кроме того, он не сохраняет начальные, разделительные или конечные пробелы. Сейчас удалено .[Изменить из-за хорошего последующего ответа ] С 1 вкладышем нет проблем,
buffer[strcspn(buffer, "\n")] = 0;
кроме производительности по сравнению сstrlen()
подходом. Производительность при обрезке обычно не является проблемой, учитывая, что код выполняет ввод-вывод - черная дыра процессорного времени. Если следующий код нуждается в длине строки или имеет высокую производительность, используйте этотstrlen()
подход. Иначеstrcspn()
это прекрасная альтернатива.источник
strlen(buffer)
когда размер буфера динамически распределяется с помощьюmalloc
?buffer = malloc(allocation_size); length = strlen(buffer);
плохо - данные в памяти, на которые указываетbuffer
неизвестно.buffer = malloc(allocation_size_4_or_more); strcpy(buffer, "abc"); length = strlen(buffer);
все в порядкеПрямое удаление \ n из вывода fgets, если в каждой строке есть \ n
В противном случае:
источник
strnlen
вместоstrlen
.n
символа не повышает магическую безопасность, в этом случае это фактически делает код более опасным. Точно так жеstrncpy
, с ужасно небезопасной функцией. Пост, на который вы ссылаетесь, - плохой совет.""
). Также неstrlen()
возвращается .size_t
int
Для одиночной обрезки \ n
для многократной обрезки \ n
источник
if
когда вы можете просто написать одно условие, используя&&
? Этотwhile
цикл имеет странную структуру; это может быть простоwhile (length > 0 && string[length-1] == '\n') { --length; string[length] = '\0'; }
.size_t length = strlen(string); if (length > 0 && string[length-1] == '\n') { string[length-1] = '\0'; }
. Это также лучше отражает второе определение (просто используяif
вместоwhile
).Мой путь новичка ;-) Пожалуйста, дайте мне знать, если это правильно. Кажется, работает для всех моих случаев:
источник
Шаги по удалению символа новой строки, возможно, наиболее очевидным способом:
NAME
, используяstrlen()
заголовокstring.h
. Обратите внимание, чтоstrlen()
не считается окончание\0
.\0
символ (пустая строка). В этом случаеsl
будет,0
поскольку,strlen()
как я сказал выше, не учитывается\0
и останавливается при первом появлении этого:'\n'
. Если это так, замените\n
на\0
. Обратите внимание, что индекс начинается с0
того, что нам нужно сделатьNAME[sl - 1]
:Обратите внимание, что если вы только нажали Enter при
fgets()
запросе строки (содержимое строки состояло только из символа новой строки), строкаNAME
после будет пустой строкой.if
выражении, используя логический оператор&&
:Если вы предпочитаете функцию для использования этой техники, обрабатывая
fgets
выходные строки в целом, не перепечатывая каждый раз, вотfgets_newline_kill
:В приведенном вами примере это будет:
Обратите внимание, что этот метод не работает, если во входную строку встроены
\0
s. В этом случаеstrlen()
будет возвращаться только количество символов до первого\0
. Но это не совсем обычный подход, так как большинство функций чтения строк обычно останавливаются на первом\0
и принимают строку до этого нулевого символа.Помимо вопроса сам по себе. Старайтесь избегать двойных отрицаний , которые делают ваш код unclearer:
if (!(fgets(Name, sizeof Name, stdin) != NULL) {}
. Вы можете просто сделатьif (fgets(Name, sizeof Name, stdin) == NULL) {}
.источник
\n
с\0
в конце строки является способом «удаления» новой строки. Но замена\n
символов внутри строки в корне меняет строку. Нередко встречаются строки с преднамеренным множеством символов новой строки, и это эффективно отрубает концы этих строк. Чтобы удалить такие новые строки, содержимое массива необходимо сместить влево, чтобы перезаписать\n
.fgets()
?fgets()
. Но я не понимаю вашего возражения: вы единственный, кто предлагает код для работы с несколькими символами новой строки.strlen
и т. д. Обоснование того, что он не является дубликатом: 1. Пояснение кода по шагам. 2. Предоставляется как функционально-контекстное решение. 3. Подсказка, чтобы избежать выражений двойного отрицания.Tim Čas один вкладыш удивителен для строк, полученных при вызове fgets, потому что вы знаете, что в конце они содержат одну новую строку.
Если вы находитесь в другом контексте и хотите обрабатывать строки, которые могут содержать более одной новой строки, возможно, вы ищете strrspn. Это не POSIX, то есть вы не найдете его на всех Unices. Я написал один для своих нужд.
Для тех, кто ищет Perl-аналог chomp в C, я думаю, что это так (chomp удаляет только завершающий перевод строки).
Функция strrcspn:
источник
'\n'
(или, если строка""
).strrcspn
течение, когда нет\n
.goto end;
вместоreturn len;
?goto
вашем коде есть два вида s: бесполезные,goto
которые можно заменить наreturn
утверждение, и обратные,goto
которые считаются злыми. Использованиеstrchr
помогает реализоватьstrrspn
иstrrcspn
в более простой форме:size_t strrspn(const char *s, const char *accept) { size_t len = strlen(s); while (len > 0 && strchr(accept, s[len - 1])) { len--; } return len; }
иsize_t strrcspn(const char *s, const char *reject) { size_t len = strlen(s); while (len > 0 && !strchr(reject, s[len - 1])) { len--; } return len; }
Если вы используете
getline
опцию - не пренебрегая ее проблемами безопасности и если вы хотите заключить указатели в скобки - вы можете избежать строковых функций, поскольку ониgetline
возвращают количество символов. Что-то вроде нижеПримечание : не следует пренебрегать [ проблемами безопасности ] с
getline
.источник
Приведенная ниже функция является частью библиотеки обработки строк, которую я поддерживаю на Github. Он удаляет и нежелательные символы из строки, именно то, что вы хотите
Пример использования может быть
Вы можете проверить другие доступные функции или даже внести свой вклад в проект :) https://github.com/fnoyanisi/zString
источник
*
в*src++;
и сделатьbad
,token
иd
const char *
. И почему бы не использоватьstrchr
вместоzChrSearch
?*src
не может быть'\0'
в вашейzStrrmv
функции.strchr
Вы должны попробовать. Этот код в основном перебирает строку, пока не найдет \ n. Когда он будет найден, \ n будет заменен нулевым символом-терминатором
Обратите внимание, что вы сравниваете символы, а не строки в этой строке, поэтому нет необходимости использовать strcmp ():
так как вы будете использовать одинарные кавычки, а не двойные кавычки. Вот ссылка на одиночные и двойные кавычки, если вы хотите узнать больше
источник
for(int i = 0; i < strlen(Name); i++ )
будет вызыватьstrlen(Name)
много раз (смена циклаName[]
), поэтому с длинойN
этоO(N*N)
решение. Только один вызовstrlen(Name)
, если таковой имеется, необходим для обеспечения решения O (N) `. Непонятно, почемуint i
используется вместоsize_t i
. Рассмотримfor(size_t i = 0; i < Name[i]; i++ )
for (size_t i = 0; Name[i]; i++) { if (Name[i] == '\n') { Name[i] = '\0'; break; } }
Попробуй это:
источник
len = strlen(str)
может переполниться:strlen
возвращаетсяsize_t
, нетint
. Что за странныеif (len>0) if (...)
условия? Вы не знаете о&&
? Если вы собираетесь удалить несколько завершающих экземпляров CR / LF, зачем ограничивать себя 5? Почему бы не удалить их все? Почему функция имеетint
возвращаемый тип, когда она всегда возвращает0
? Почему бы просто не вернутьсяvoid
?