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 \ncarácter de nueva línea al final. Entonces, si entro John, termina enviando John\n. ¿Cómo elimino eso \ny 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
strtokfunción no funciona como se esperaba si el usuario ingresa una cadena vacía (es decir, solo presiona Enter). Deja el\npersonaje 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) .strtokenfoque (y funciona con entradas vacías). De hecho, una buena manera de implementarstrtokes usarstrcspnystrspn.*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 textostdinno 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
strcspndetiene en a'\0'. En ese caso, toda la línea simplemente se reemplaza'\0'con'\0'.fuente
bufferque 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_rimplementación usandostrcspnystrspnfue 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()strlenfgets()entrada . Que siempre es también la primera línea nueva.fuente
fgets(buf, size, ....)->strlen(buf) == 0. 1) sefgets()lee como el primerchara'\0'. 2)size == 13)fgets()devuelve,NULLentonces elbufcontenido 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';lnsería -1, salvo por el hecho desize_tque no está firmado, escribiendo así en la memoria aleatoria. Creo que quieres usarssize_ty comprobarlnes> 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 unastrchrostrcspnbasada.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
bufferylensegún sea necesario.Este método tiene el beneficio secundario de un
lenvalor 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
bufferlo que sólocharprecede 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'cuandobufferes"\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
charlecturafgets()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:bufferse 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
strnlenlugar destrlen.nno 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_tnoint.Para el recorte simple '\ n',
para múltiples '\ n' recortes,
fuente
ifcuando simplemente puedes escribir una condición usando&&? Esewhilebucle 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 eniflugar 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:
NAMEusandostrlen(), encabezadostring.h. Tenga en cuenta questrlen()no cuenta la terminación\0.\0carácter (cadena vacía). En este casoslsería0porque,strlen()como dije anteriormente, no cuenta\0y se detiene en el primer caso:'\n'. Si este es el caso, reemplácelo\ncon a\0. Tenga en cuenta que los recuentos de índices comienzan en,0así 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 cadenaNAMEserá una cadena vacía a partir de entonces.ifdeclaración utilizando el operador lógico&&:Si prefiere una función para usar esta técnica manejando
fgetscadenas 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
\0s 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\0y 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
\npor\0a al final de una cadena es una forma de "eliminar" la nueva línea. Pero reemplazar\ncaracteres 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.strlenetc. 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"").strrcspnpara cuando no hay\n.goto end;lugar dereturn len;?gotoelectrónicos en su código: uno inútilgotoque puede reemplazarse por unareturndeclaración y uno al revésgotoque se considera malvado. El usostrchrayuda a implementarstrrspnystrrcspnde 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
getlinees una opción, sin descuidar sus problemas de seguridad y si desea colocar punteros, puede evitar las funciones de cadena ya quegetlinedevuelve el número de caracteres. Algo como abajoNota : Sin embargo, los [ problemas de seguridad ] con
getlineno 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,tokenydconst char *. Además, ¿por qué no usar enstrchrlugar dezChrSearch?*srcno puede estar'\0'en tuzStrrmvfunción.strchrUsted 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 iestá 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:strlenretornossize_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 uninttipo de retorno cuando siempre regresa0? ¿Por qué no solo volvervoid?