Estoy tratando de obtener algunos datos del usuario y enviarlos a otra función en gcc. El código es algo como esto.
printf("Enter your Name: ");
if (!(fgets(Name, sizeof Name, stdin) != NULL)) {
fprintf(stderr, "Error reading Name.\n");
exit(1);
}
Sin embargo, me parece que tiene un \n
carácter de nueva línea al final. Entonces, si entro John
, termina enviando John\n
. ¿Cómo elimino eso \n
y envío una cadena adecuada?
if (!fgets(Name, sizeof Name, stdin))
(¡al menos no use dos negaciones,! y! =)if (fgets(Name, sizeof Name, stdin)) {
.if (fgets(Name, sizeof Name, stdin) == NULL ) {
!
:Respuestas:
La forma un poco fea:
La forma un poco extraña:
Tenga en cuenta que la
strtok
función no funciona como se esperaba si el usuario ingresa una cadena vacía (es decir, solo presiona Enter). Deja el\n
personaje intacto.También hay otros, por supuesto.
fuente
strtok()
será segura para subprocesos (usará almacenamiento local de subprocesos para el estado 'entre llamadas'). Dicho esto, todavía es generalmente mejor usar lastrtok_r()
variante no estándar (pero lo suficientemente común) .strtok
enfoque (y funciona con entradas vacías). De hecho, una buena manera de implementarstrtok
es usarstrcspn
ystrspn
.*strchrnul(Name, '\n') = '\0';
.strchr(Name, '\n') == NULL
, además de "entrada demasiado larga para el búfer, error de marca", existen otras posibilidades: el último textostdin
no terminó con un'\n'
carácter nulo incrustado raro o se leyó.Quizás la solución más simple utiliza una de mis funciones favoritas poco conocidas
strcspn()
:Si desea que también maneje
'\r'
(por ejemplo, si la secuencia es binaria):La función cuenta el número de caracteres hasta que toca a
'\r'
o a'\n'
(en otras palabras, encuentra el primero'\r'
o'\n'
). Si no golpea nada, se detiene en'\0'
(devolviendo la longitud de la cadena).Tenga en cuenta que esto funciona bien incluso si no hay una nueva línea, porque se
strcspn
detiene en a'\0'
. En ese caso, toda la línea simplemente se reemplaza'\0'
con'\0'
.fuente
buffer
que comienza con'\0'
, algo que causa dolor por elbuffer[strlen(buffer) - 1] = '\0';
enfoque.strcspn()
. Una de las funciones más útiles en la biblioteca, IMO. He decidido escribir y publicar un montón de hacks C comunes como este hoy; unastrtok_r
implementación usandostrcspn
ystrspn
fue una de las primeras: codepad.org/2lBkZk0w ( Advertencia: no puedo garantizar que no tenga errores; se escribió apresuradamente y probablemente tenga algunos). Sin embargo, todavía no sé dónde los publicaré, pero tengo la intención de hacerlo en el espíritu de los famosos "trucos de tonterías".fgets()
strcspn()
strlen
fgets()
entrada . Que siempre es también la primera línea nueva.fuente
fgets(buf, size, ....)
->strlen(buf) == 0
. 1) sefgets()
lee como el primerchar
a'\0'
. 2)size == 1
3)fgets()
devuelve,NULL
entonces elbuf
contenido puede ser cualquier cosa (Sin embargo, el código de OP prueba NULL) Sugerir:size_t ln = strlen(name); if (ln > 0 && name[ln-1] == '\n') name[--ln] = '\0';
ln
sería -1, salvo por el hecho desize_t
que no está firmado, escribiendo así en la memoria aleatoria. Creo que quieres usarssize_t
y comprobarln
es> 0.strlen
) puede implementarse de manera mucho más eficiente que una simple búsqueda char-by-char. Por esta razón, consideraría esta solución mejor que unastrchr
ostrcspn
basada.A continuación se muestra un enfoque rápido para eliminar un potencial
'\n'
de una cadena guardada porfgets()
.Utiliza
strlen()
, con 2 pruebas.Ahora use
buffer
ylen
según sea necesario.Este método tiene el beneficio secundario de un
len
valor para el código posterior. Puede ser fácilmente más rápido questrchr(Name, '\n')
. Ref. YMMV, pero ambos métodos funcionan.buffer
, Desde el original,fgets()
no contendrá en"\n"
bajo algunas circunstancias:A) La línea era demasiado largo para
buffer
lo que sólochar
precede a la'\n'
se guarda enbuffer
. Los caracteres no leídos permanecen en la secuencia.B) La última línea del archivo no terminó con a
'\n'
.Si la entrada tiene caracteres nulos incrustados
'\0'
en alguna parte, la longitud informada porstrlen()
no incluirá la'\n'
ubicación.Algunos problemas de otras respuestas:
strtok(buffer, "\n");
no puede eliminar el'\n'
cuandobuffer
es"\n"
. De esta respuesta : modificada después de esta respuesta para advertir sobre esta limitación.Lo siguiente falla en raras ocasiones cuando la primera
char
lecturafgets()
es'\0'
. Esto sucede cuando la entrada comienza con un incrustado'\0'
. Luego sebuffer[len -1]
convierte enbuffer[SIZE_MAX]
acceder a la memoria ciertamente fuera del rango legítimo debuffer
. Algo que un hacker puede probar o encontrar al leer tontamente archivos de texto UTF16. Este era el estado de una respuesta cuando se escribió esta respuesta. Más tarde, un no OP lo editó para incluir código como la comprobación de esta respuesta""
.sprintf(buffer,"%s",buffer);
es comportamiento indefinido: Ref . Además, no guarda ningún espacio en blanco inicial, de separación o final. Ahora eliminado .[Editar debido a una buena respuesta posterior ] No hay problemas con el trazador de líneas 1
buffer[strcspn(buffer, "\n")] = 0;
aparte del rendimiento en comparación con elstrlen()
enfoque. El rendimiento en el recorte generalmente no es un problema dado que el código está haciendo E / S, un agujero negro del tiempo de CPU. Si el siguiente código necesita la longitud de la cadena o es altamente consciente del rendimiento, utilice estestrlen()
enfoque. De lo contrario,strcspn()
es una buena alternativa.fuente
strlen(buffer)
cuando el tamaño del búfer se asigna dinámicamente usandomalloc
?buffer = malloc(allocation_size); length = strlen(buffer);
es malo:buffer
se desconocen los datos en la memoria señalados por .buffer = malloc(allocation_size_4_or_more); strcpy(buffer, "abc"); length = strlen(buffer);
está bienDirecto para eliminar el '\ n' de la salida de fgets si cada línea tiene '\ n'
De otra manera:
fuente
strnlen
lugar destrlen
.n
no aumenta mágicamente la seguridad, en este caso, de hecho, haría que el código sea más peligroso. De manera similar constrncpy
, una función terriblemente insegura. La publicación que vinculaste es un mal consejo.""
). Tambiénstrlen()
devuelvesize_t
noint
.Para el recorte simple '\ n',
para múltiples '\ n' recortes,
fuente
if
cuando simplemente puedes escribir una condición usando&&
? Esewhile
bucle tiene una estructura extraña; simplemente podría serwhile (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'; }
. Esto también refleja mejor la segunda definición (solo usando enif
lugar dewhile
).My Newbie way ;-) Avísame si es correcto. Parece estar funcionando para todos mis casos:
fuente
Los pasos para eliminar el carácter de nueva línea de la forma quizás más obvia:
NAME
usandostrlen()
, encabezadostring.h
. Tenga en cuenta questrlen()
no cuenta la terminación\0
.\0
carácter (cadena vacía). En este casosl
sería0
porque,strlen()
como dije anteriormente, no cuenta\0
y se detiene en el primer caso:'\n'
. Si este es el caso, reemplácelo\n
con a\0
. Tenga en cuenta que los recuentos de índices comienzan en,0
así que tendremos que hacerNAME[sl - 1]
:Tenga en cuenta que si solo presionó Entrar en la
fgets()
solicitud de cadena (el contenido de la cadena solo consistía en un carácter de nueva línea), la cadenaNAME
será una cadena vacía a partir de entonces.if
declaración utilizando el operador lógico&&
:Si prefiere una función para usar esta técnica manejando
fgets
cadenas de salida en general sin volver a escribir cada vez, aquí estáfgets_newline_kill
:En su ejemplo proporcionado, sería:
Tenga en cuenta que este método no funciona si la cadena de entrada tiene
\0
s integrados . Si ese fuera el casostrlen()
, solo devolvería la cantidad de caracteres hasta el primero\0
. Pero este no es un enfoque bastante común, ya que la mayoría de las funciones de lectura de cadenas generalmente se detienen al principio\0
y toman la cadena hasta ese carácter nulo.Aparte de la pregunta por sí solo. Trate de evitar las negaciones dobles que hacen que su unclearer código:
if (!(fgets(Name, sizeof Name, stdin) != NULL) {}
. Simplemente puedes hacerif (fgets(Name, sizeof Name, stdin) == NULL) {}
.fuente
\n
por\0
a al final de una cadena es una forma de "eliminar" la nueva línea. Pero reemplazar\n
caracteres dentro de una cadena cambia fundamentalmente la cadena. No es raro tener cadenas con múltiples caracteres intencionales de nueva línea, y esto cortaría efectivamente los extremos de esas cadenas. Para eliminar estas nuevas líneas, el contenido de la matriz debe desplazarse hacia la izquierda para sobrescribir el\n
.fgets()
?fgets()
. Pero no entiendo su objeción: usted es el único que propone el código para manejar múltiples líneas nuevas.strlen
etc. Justificación para no ser un duplicado: 1. Explicación del código por pasos. 2. Proporcionado como función y solución basada en el contexto. 3. Sugerencia para evitar expresiones de doble negación.Tim Čas one liner es increíble para las cadenas obtenidas por una llamada a fgets, porque sabes que contienen una nueva línea al final.
Si se encuentra en un contexto diferente y desea manejar cadenas que pueden contener más de una nueva línea, es posible que esté buscando strrspn. No es POSIX, lo que significa que no lo encontrará en todos los Unices. Escribí uno para mis propias necesidades.
Para aquellos que buscan un equivalente de Perl chomp en C, creo que esto es todo (chomp solo elimina la nueva línea final).
La función strrcspn:
fuente
'\n'
(o si la cadena es""
).strrcspn
para cuando no hay\n
.goto end;
lugar dereturn len;
?goto
electrónicos en su código: uno inútilgoto
que puede reemplazarse por unareturn
declaración y uno al revésgoto
que se considera malvado. El usostrchr
ayuda a implementarstrrspn
ystrrcspn
de una manera más simple: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; }
ysize_t strrcspn(const char *s, const char *reject) { size_t len = strlen(s); while (len > 0 && !strchr(reject, s[len - 1])) { len--; } return len; }
Si usar
getline
es una opción, sin descuidar sus problemas de seguridad y si desea colocar punteros, puede evitar las funciones de cadena ya quegetline
devuelve el número de caracteres. Algo como abajoNota : Sin embargo, los [ problemas de seguridad ] con
getline
no deben descuidarse.fuente
La siguiente función es parte de la biblioteca de procesamiento de cadenas que mantengo en Github. Elimina los caracteres no deseados de una cadena, exactamente lo que quieres
Un ejemplo de uso podría ser
Es posible que desee comprobar otras funciones disponibles, o incluso contribuir al proyecto :) https://github.com/fnoyanisi/zString
fuente
*
in*src++;
y makebad
,token
yd
const char *
. Además, ¿por qué no usar enstrchr
lugar dezChrSearch
?*src
no puede estar'\0'
en tuzStrrmv
función.strchr
Usted debe darle una oportunidad. Este código básicamente recorre la cadena hasta que encuentra el '\ n'. Cuando se encuentre, '\ n' será reemplazado por el terminador de caracteres nulos '\ 0'
Tenga en cuenta que está comparando caracteres y no cadenas en esta línea, entonces no hay necesidad de usar strcmp ():
ya que usará comillas simples y no comillas dobles. Aquí hay un enlace sobre comillas simples vs dobles si quieres saber más
fuente
for(int i = 0; i < strlen(Name); i++ )
llamarástrlen(Name)
muchas veces (cambios de bucleName[]
), por lo que con una longitudN
, esta es unaO(N*N)
solución. Solostrlen(Name)
se necesita 1 llamada a , si la hay, para proporcionar una solución O (N) `. Noint i
está claro por qué se usa en lugar desize_t i
. Considerefor(size_t i = 0; i < Name[i]; i++ )
for (size_t i = 0; Name[i]; i++) { if (Name[i] == '\n') { Name[i] = '\0'; break; } }
Prueba este:
fuente
len = strlen(str)
puede desbordarse:strlen
retornossize_t
, noint
. ¿Qué pasa con los extrañosif (len>0) if (...)
condicionales? ¿No lo sabes&&
? Si va a eliminar varias instancias finales de CR / LF, ¿por qué limitarse a 5? ¿Por qué no eliminarlos a todos? ¿Por qué la función tiene unint
tipo de retorno cuando siempre regresa0
? ¿Por qué no solo volvervoid
?