La suppression de fuite caractère de saut de ligne à partir de fgets() entrée
Je suis en train d'essayer d'obtenir certaines données de l'utilisateur et de l'envoyer à une autre fonction dans gcc. Le code est quelque chose comme cela.
printf("Enter your Name: ");
if (!(fgets(Name, sizeof Name, stdin) != NULL)) {
fprintf(stderr, "Error reading Name.\n");
exit(1);
}
Cependant, je trouve qu'il a un saut de ligne \n
personnage à la fin. Donc, si je entrer John
il finit par l'envoi d' John\n
. Comment puis-je supprimer que \n
et envoyer une chaîne de caractères.
if (!fgets(Name, sizeof Name, stdin))
(à tout le moins, ne pas utiliser de deux négations, ! et !=)- Pate "de ne pas utiliser deux négations" --> hmmm, si nous creuser profondément "ne pas" et "négation" sont à la fois des négations. ;-). Peut-Être Que "L'Utilisation
if (fgets(Name, sizeof Name, stdin)) {
. - Je suis sûr que vous avez voulu dire
if (fgets(Name, sizeof Name, stdin) == NULL ) {
- True: satanés
!
:
Vous devez vous connecter pour publier un commentaire.
Légèrement laid façon:
Légèrement étrange façon:
Noter que le
strtok
ne fonctionne pas comme prévu si l'utilisateur entre une chaîne vide (c'est à dire presses seule Entrée). Il quitte le\n
caractère intact.Il y a les autres aussi, bien sûr.
strtok()
thread-safe (il va utiliser le thread local de stockage pour les "inter-appel' etat). Cela dit, il est toujours préférable d'utiliser la non-standard (mais assez commun)strtok_r()
variante.strtok
approche (et il fonctionne à vide entrées). En fait, une bonne façon de mettre en œuvrestrtok
est d'utiliserstrcspn
etstrspn
.*strchrnul(Name, '\n') = '\0';
.strchr(Name, '\n') == NULL
, puis de côté "de l'entrée trop longtemps de la mémoire tampon, le drapeau d'erreur", d'autres possibilités existent: Dernier texte dansstdin
n'a pas pris fin avec un'\n'
ou de l'un des rares intégré caractère null a été lu.Peut-être la solution la plus simple utilise l'un de mes préférés, peu connu, fonctions,
strcspn()
:Si vous souhaitez également gérer
'\r'
(par exemple, si le flux binaire):La fonction compte le nombre de caractères jusqu'à ce qu'il frappe une
'\r'
ou un'\n'
(en d'autres termes, il trouve la première'\r'
ou'\n'
). Si il n'a pas touché quoi que ce soit, il s'arrête à la'\0'
(retour de la longueur de la chaîne).Notez que cela fonctionne bien, même si il n'y a pas de saut de ligne, parce que
strcspn
s'arrête à un'\0'
. Dans ce cas, la totalité de la ligne est tout simplement en remplacement de'\0'
avec'\0'
.buffer
que commence avec'\0'
, quelque chose qui provoque la douleur pour labuffer[strlen(buffer) - 1] = '\0';
approche.strcspn()
. L'un des plus utiles les fonctions de la bibliothèque, de l'OMI. J'ai décidé d'écrire et de publier un tas de commun C hacks comme celui d'aujourd'hui; unstrtok_r
mise en œuvre à l'aide destrcspn
etstrspn
a été l'un des premiers: codepad.org/2lBkZk0w (Avertissement: je ne peux pas garantir que c'est sans bugs; il a été écrit à la hâte et a probablement un peu). Je ne sais pas où je vais publier 'em encore, bien que, mais j'ai l'intention de le faire dans l'esprit de la célèbre "peu tourner les hacks".fgets()
. Cettestrcspn()
semble être le que corriger one-liner.strlen
est plus rapide mais pas aussi simple.\r
. Certains systèmes, même utilisé\n\r
(par opposition à\r\n
).'\n'
."\n"
dans le cas habituel, mais"\r\n"
si le flux binaire (et si l'on veut traiter toutes les 3 types communs de fins de ligne: CR, LF, et CRLF).fgets
cette distinction est sans importance, mais elle est importante, si quelqu'un veut l'utiliser dans un cas général.fgets()
d'entrée. Ce qui est aussi toujours le premier retour à la ligne.fgets
cette distinction est sans importance, mais elle est importante, si quelqu'un veut utiliser ce dans le cas général. Une recherche sur Google en arrière quand, pour si il y avait un C/C++ équivalent encore pour Perlchomp
, m'a conduit ici. Quiconque cherche pour que, qui le trouve et n'est pas reconnaître la distinction, peuvent se retrouver avec des problèmes.fgets(buf, size, ....)
-->strlen(buf) == 0
. 1)fgets()
se lit comme la premièrechar
un'\0'
. 2)size == 1
3)fgets()
retourneNULL
puisbuf
contenu pourrait être n'importe quoi. (OP code ne testent la valeur NULL si) Suggèrent:size_t ln = strlen(name); if (ln > 0 && name[ln-1] == '\n') name[--ln] = '\0';
ln
serait -1, sauf pour le faitsize_t
est pas signé, donc l'écriture de la mémoire vive. Je pense que vous voulez utiliserssize_t
et vérifierln
est >0.name[0]
pourrait avoir la valeur de'\0'. Yet
ssize_t ln = strlen(nom) - 1; si(ln > 0) ... " peut ne pas fonctionner soit commessize_t
est non-C standard et peut être en mesure de représenterstrlen("") - 1
comme un nombre positif. Assez simplement le codesize_t ln = strlen(name); if (ln > 0 && name[ln-1] == '\n') ...
strlen
) peut être mis en œuvre de manière beaucoup plus efficace qu'un simple char par char de recherche. Raison pour laquelle je voudrais examiner cette solution meilleure qu'unestrchr
oustrcspn
basé.Ci-dessous est une approche rapide pour supprimer un potentiel
'\n'
à partir d'une chaîne enregistrée parfgets()
.Il utilise
strlen()
, avec 2 tests.Maintenant utiliser
buffer
etlen
en tant que de besoin.Cette méthode a l'avantage secondaire de
len
de la valeur pour le code suivant. Il peut facilement être plus rapide questrchr(Name, '\n')
. Ref YMMV, mais les deux méthodes de travail.buffer
, à partir de l'originalfgets()
ne contiendra pas à"\n"
sous certaines conditions:A) La ligne est trop longue pour
buffer
donc seulementchar
précédant la'\n'
est enregistré dansbuffer
. Les caractères non lus restent dans le cours d'eau.B) à La dernière ligne dans le fichier n'a pas pris fin avec un
'\n'
.Si l'entrée a incorporé des caractères null
'\0'
en quelque part, la longueur rapporté parstrlen()
ne comprennent pas les'\n'
emplacement.Certains autres réponses " questions:
strtok(buffer, "\n");
ne parvient pas à supprimer le'\n'
quandbuffer
est"\n"
. À partir de ce réponse - modifié après cette réponse pour l'avertir de cette limitation.La suivante échoue à de rares occasions, lors de la première
char
lire parfgets()
est'\0'
. Cela se produit lorsque l'entrée commence avec un intégré à'\0'
. Puisbuffer[len -1]
devientbuffer[SIZE_MAX]
accès à la mémoire sûr, en dehors de la légitime gamme debuffer
. Quelque chose d'un pirate peut essayer ou trouvé dans bêtement lecture UTF16 des fichiers texte. Tel était l'état d'un réponse lorsque cette réponse a été écrit. Plus tard, un non-OP modifié pour inclure le code comme ceci répondre à vérifier pour""
.sprintf(buffer,"%s",buffer);
est un comportement indéfini: Ref. De plus, il n'enregistre pas les conduisant, en séparant les espaces de début ou de fin. Maintenant supprimé.[Modifier en raison de la bonne plus tard réponse] Il n'y a pas de problèmes avec les 1 liner
buffer[strcspn(buffer, "\n")] = 0;
autre que les performances par rapport à lastrlen()
approche. Performance dans le parage n'est généralement pas un problème, vu le code est en train de faire des I/O - un trou noir de temps CPU. Doit code suivant besoin la longueur de la chaîne ou de est très la performance consciente, utilisez cestrlen()
approche. Le reste de lastrcspn()
est une belle alternative.strlen(buffer)
lorsque la taille de la mémoire tampon est alloué dynamiquement à l'aide demalloc
?buffer
est inconnue.buffer = malloc(allocation_size_4_or_more); strcpy(buffer, "abc"); length = strlen(buffer);
est OKDirect pour enlever le '\n' dans le fgets sortie si toutes les lignes a '\n'
Autrement:
strnlen
au lieu destrlen
.n
n'est pas la baguette magique pour augmenter la sécurité, dans ce cas, il est en effet de rendre le code plus dangereux. De la même façon avecstrncpy
, un très dangereux à la fonction. Le poste que vous-même liée à de mauvais conseils.""
). Aussistrlen()
retournesize_t
pasint
.Pour unique '\n' trmming,
pour plusieurs '\n' parage,
if
lorsque vous pouvez simplement écrire une condition à l'aide de&&
? Quewhile
boucle a une structure étrange; il pourrait simplement êtrewhile (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'; }
. Cela reflète aussi la deuxième définition plus (juste en utilisantif
au lieu dewhile
).Tim Čas un liner est incroyable pour les chaînes obtenues par un appel à fgets, parce que vous savez qu'ils contiennent un seul saut de ligne à la fin.
Si vous êtes dans un autre contexte et souhaitez manipuler des chaînes de caractères qui peut contenir plus d'un saut de ligne, vous pourriez être à la recherche pour strrspn. Il n'est pas POSIX, ce qui signifie que vous ne trouverez pas sur tous les Unix. Je l'ai écrit pour mes propres besoins.
Pour ceux qui recherchent un Perl chomp équivalent en C, je pense que c'est elle (chomp supprime seulement la fuite de saut de ligne).
La strrcspn fonction:
'\n'
(ou si la chaîne est""
).strrcspn
quand il n'y a pas de\n
.goto end;
au lieu dereturn len;
?goto
s dans votre code: inutilegoto
qui peut être remplacé par unreturn
et d'un état vers l'arrièregoto
qui est considéré comme mauvais. À l'aide destrchr
permet de mettre en œuvrestrrspn
etstrrcspn
plus simple de la mode: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; }
etsize_t strrcspn(const char *s, const char *reject) { size_t len = strlen(s); while (len > 0 && !strchr(reject, s[len - 1])) { len--; } return len; }
s
. Je suis d'accord un retour serait le mieux. Il serait de remplacer deux instructions pour une. Mais cela ne signifie pas aller dans l'autre fonction devrait aller. Si vous n'aimez pas les gotos, ne les utilisez pas. Épargnez-moi le tout-gotos-sont-mal la rhétorique.Si vous utilisez
getline
est une option à ne Pas négliger ses problèmes de sécurité et si vous souhaitez corset pointeurs - vous pouvez éviter les fonctions de chaîne comme legetline
renvoie le nombre de caractères. Quelque chose comme ci-dessousNote: Le [ les questions de sécurité ] avec
getline
ne devrait pas être négligée si.Mon Newbie façon 😉 s'il vous Plaît laissez-moi savoir si c'est correct. Il semble fonctionner pour tous mes cas:
La fonction ci-dessous est une partie de la chaîne de traitement de la bibliothèque, je suis maintenant sur Github. Il supprime non désirées et les caractères d'une chaîne, exactement ce que vous voulez
Un exemple d'utilisation pourrait être
Vous voudrez peut-être vérifier les autres fonctions disponibles, ou même de contribuer au projet 🙂
https://github.com/fnoyanisi/zString
*
dans*src++;
et fairebad
,token
etd
const char *
. Aussi pourquoi ne pas utiliserstrchr
au lieu dezChrSearch
?*src
ne peut pas être'\0'
dans votrezStrrmv
fonction.strchr
Vous devez lui donner un essai. Ce code de coeur de la boucle à travers la chaîne jusqu'à ce qu'il trouve le '\n'. Quand elle trouve le '\n' sera remplacé par le caractère nul de terminaison '\0'
Noter que vous avez la comparaison des caractères et non des chaînes dans cette ligne, alors il n'y a pas besoin d'utiliser strcmp():
puisque vous allez être en utilisant des guillemets simples et pas de guillemets doubles. Voici un lien unique vs guillemets doubles si vous voulez en savoir plus
for(int i = 0; i < strlen(Name); i++ )
appellerastrlen(Name)
de nombreuses fois (boucle changementsName[]
) avec une longueur deN
, c'est unO(N*N)
solution. Seulement 1 appel àstrlen(Name)
, le cas échéant , est nécessaire pour fournir un O(N) solution. Difficile de comprendre pourquoiint i
est utilisé à la place desize_t i
. Envisagerfor(size_t i = 0; i < Name[i]; i++ )
for (size_t i = 0; Name[i]; i++) { if (Name[i] == '\n') { Name[i] = '\0'; break; } }
break
n'était pas là,i++
et suivantsName[i]
serait de 0, l'arrêt de la boucle. Votre bonne idée a l'avantage dei
étant la longueur de la chaîne après la boucle.i < Name[i]
n'a pas de sens.for(size_t i = 0; i < Name[i]; i++ )
doit avoir étéfor(size_t i = 0; Name[i]; i++ )
Essayez celui-ci:
len = strlen(str)
peut overflow:strlen
retournesize_t
, pasint
. C'est quoi l'étrangeif (len>0) if (...)
conditions? Ne savez-vous pas sur&&
? Si vous voulez supprimer plusieurs cas de fuite de CR/LF, pourquoi vous limiter à 5? Pourquoi ne pas supprimer tous? Pourquoi la fonction ont uneint
type de retour quand elle revient toujours0
? Pourquoi ne pas juste retourvoid
?