Entfernen Sie nachgestellte newline-Zeichen von fgets() input
Ich versuche einige Daten vom Benutzer und senden Sie es an eine andere Funktion im gcc. Der code ist so etwas wie dieses.
printf("Enter your Name: ");
if (!(fgets(Name, sizeof Name, stdin) != NULL)) {
fprintf(stderr, "Error reading Name.\n");
exit(1);
}
Allerdings finde ich, dass es ein newline \n
Charakter. Also, wenn ich geben Sie John
es endet zu senden John\n
. Wie Entferne ich das \n
und senden eine richtige string.
if (!fgets(Name, sizeof Name, stdin))
(zumindest nicht zwei Negationen, ! und !=)Pate "nicht verwenden zwei Negationen" --> hmmm, wenn wir tief Graben "nicht" und "negation" sind die beiden Negationen. ;-). Vielleicht "Verwenden
if (fgets(Name, sizeof Name, stdin)) {
.Ich bin sicher, dass Sie gemeint
if (fgets(Name, sizeof Name, stdin) == NULL ) {
True: lästigen
!
:
InformationsquelleAutor sfactor | 2010-04-22
Du musst angemeldet sein, um einen Kommentar abzugeben.
Die etwas unschöne Art und Weise:
Die etwas seltsame Weise:
Beachten Sie, dass die
strtok
- Funktion funktioniert nicht wie erwartet, wenn der Benutzer einen leeren string (d.h. drückt nur Enter). Es lässt die\n
Charakter intakt.Es gibt andere als gut, natürlich.
Alle C-Laufzeit-Bibliothek, die den thread bewusst (das ist zu sagen, die meisten alle, die das Ziel einer multi-threaded-Plattform)
strtok()
werden thread-sicher (es wird die Verwendung thread-lokaler Speicher für die 'inter-call" - Zustand). Das heißt, es ist zwar generell besser, die nicht-standard - (aber Häufig genug)strtok_r()
Variante.Siehe meine Antwort für vollständig thread-sicher und reentrant-Variante, ähnlich wie Ihre
strtok
Ansatz (und es funktioniert mit leeren Eingänge). In der Tat, ein guter Weg, um zu implementierenstrtok
ist die Verwendungstrcspn
undstrspn
.Es ist wichtig zu behandeln, wird der else-Fall, wenn Sie in einer Umgebung, wo es ein Risiko von zu langen Zeilen. Schweigend abschneiden der Eingang kann sehr schädlichen Käfern.
Wenn Sie mögen one-Liner und verwenden glibc, versuchen
*strchrnul(Name, '\n') = '\0';
.InformationsquelleAutor Jerry Coffin
Vielleicht die einfachste Lösung wird einer meiner Lieblings-wenig bekannte Funktionen,
strcspn()
:Wenn Sie wollen, dass es auch mit
'\r'
(sagen wir, wenn der Strom Binär):Die Funktion zählt die Anzahl von Zeichen, bis es auf eine
'\r'
oder eine'\n'
(in anderen Worten, es findet die erste'\r'
oder'\n'
). Wenn es nicht auf etwas, hält es bei der'\0'
(gibt die Länge der Zeichenfolge).Beachten Sie, dass dies funktioniert sehr gut, auch wenn es keinen Zeilenumbruch, da
strcspn
hält'\0'
. In diesem Fall wird die gesamte Zeile einfach ersetzen'\0'
mit'\0'
.buffer
als beginnt mit'\0'
, etwas, das bewirkt, dass der Kummer über denbuffer[strlen(buffer) - 1] = '\0';
Ansatz.Yup, ich wünschte, mehr Leute gekannt hätten
strcspn()
. Einer der mehr nützliche Funktionen in der Bibliothek, IMO. Ich habe mich entschieden, zu schreiben und zu veröffentlichen eine Reihe von gemeinsamen C-hacks wie dieser heute; einstrtok_r
Umsetzung mitstrcspn
undstrspn
war einer der ersten: codepad.org/2lBkZk0w (Warnung: ich kann nicht garantieren, dass es ohne Fehler; Sie war hastig geschrieben und hat wahrscheinlich ein paar). Ich weiß nicht, wo ich veröffentlichen 'em noch, obwohl, aber ich beabsichtige, es zu machen, in den Geist der berühmten "bit twiddling hacks".Sah aus wie robust trim
fgets()
. Diesestrcspn()
zu sein scheint, der nur richtige one-liner.strlen
ist schneller, allerdings nicht so einfach.Die Frage, die sowohl in der Titel-und der Inhalt, erkundigt sich über die trailing newline von
fgets()
input. Das ist immer auch die erste Zeile.Ich verstehe, wo du herkommst, aber ich kann nicht verantwortlich gemacht werden für die Google-Suche Ergebnisse für spezifische Bedingungen. Vortrag zu Google, nicht mich.
InformationsquelleAutor Tim Čas
der string wird nicht immer leer sein, jedoch.
Morris In ungewöhnlichen Fällen
fgets(buf, size, ....)
-->strlen(buf) == 0
. 1)fgets()
liest sich wie die erstenchar
eine'\0'
. 2)size == 1
3)fgets()
zurückNULL
dannbuf
Inhalt kann alles mögliche sein. (OP-code wird auf NULL zu testen obwohl) Empfehlen:size_t ln = strlen(name); if (ln > 0 && name[ln-1] == '\n') name[--ln] = '\0';
Was ist, wenn der string leer ist?
ln
wäre -1, außer für die Tatsachesize_t
ohne Vorzeichen ist, so zu schreiben, random-Speicher. Ich denke, das Sie verwenden möchtenssize_t
und überprüfenln
ist >0.Die Suche nach einem compile-Zeit-Wert (vor allem einen null-Wert wie in
strlen
) umgesetzt werden können, wesentlich effizienter als eine einfache char-by-char Suche. Deshalb würde ich überlegen, diese Lösung besser als einstrchr
oderstrcspn
basierte.InformationsquelleAutor James Morris
Unten ist ein schnelles Vorgehen zum entfernen eines potenziellen
'\n'
aus einem string gespeichertfgets()
.Es nutzt
strlen()
mit 2 tests.Nun verwenden
buffer
undlen
als nötig.Diese Methode hat den Nebeneffekt einer
len
Wert für den nachfolgenden code. Es kann leicht sein, schneller alsstrchr(Name, '\n')
. Ref YMMV, aber beide Methoden funktionieren.buffer
von der ursprünglichenfgets()
nicht enthalten in"\n"
unter bestimmten Umständen:A) Die Zeile zu lang war für
buffer
also nurchar
vor der'\n'
gespeichert inbuffer
. Die ungelesenen Zeichen verbleibt im stream.B) Die Letzte Zeile in der Datei nicht am Ende mit einem
'\n'
.Wenn der Eingang hat eine eingebettete null-Zeichen
'\0'
im es irgendwo, die Länge berichtet vonstrlen()
beinhalten nicht die'\n'
Lage.Einige andere Antworten " Fragen:
strtok(buffer, "\n");
fehlschlägt, entfernen Sie die'\n'
wennbuffer
ist"\n"
. Aus diesem Antwort - geändert werden, nachdem diese Antwort zu warnen, die von dieser Einschränkung.Folgende scheitert in seltenen Fällen, wenn die ersten
char
Lesenfgets()
ist'\0'
. Dies geschieht, wenn die Eingabe beginnt mit einem eingebetteten'\0'
. Dannbuffer[len -1]
wirdbuffer[SIZE_MAX]
Zugriff auf Speicher, der mit Sicherheit außerhalb des legitimen Bereichs derbuffer
. So etwas kann ein hacker versuchen, in so töricht, das Lesen UTF16-text-Dateien. Dies war der Zustand eines Antwort wenn diese Antwort geschrieben wurde. Später wird ein non-OP bearbeitet, die code enthalten, wie diese Antwort zu überprüfen für""
.sprintf(buffer,"%s",buffer);
ist Undefiniertes Verhalten: Ref. Weiter, es speichert keine führende, Trenn-oder Leerzeichen. Jetzt gelöscht.[Bearbeiten durch gute nachträglich Antwort] Es gibt keine Probleme mit der 1 liner
buffer[strcspn(buffer, "\n")] = 0;
andere als die performance gegenüber derstrlen()
Ansatz. Die Leistung im Trimm ist in der Regel nicht ein Problem gegeben-code, tut-I/O - ein Schwarzes Loch von CPU-Zeit. Sollte folgenden code müssen Sie die string-Länge oder Leistung ist sehr bewusst, nutzen diesestrlen()
Ansatz. Sonst ist derstrcspn()
ist eine gute alternative.strlen(buffer)
wenn die Puffergröße ist dynamisch zugewiesen, mitmalloc
?malloc(allocation_size); length = strlen(buffer); schlecht ist - Daten im Speicher verweist
buffer
ist unbekannt.buffer = malloc(allocation_size_4_or_more); strcpy(buffer, "abc"); length = strlen(buffer);
ist OKInformationsquelleAutor chux
Direkt zu entfernen, die '\n' aus der fgets-Ausgang, wenn jede Zeile mit einem '\n'
Ansonsten:
strnlen
stattstrlen
.Ein Kommentar zu der ersten Antwort in der Frage verlinkten Staaten "Beachten Sie, dass strlen(), strcmp() und strdup() sicher sind. Das 'n' alternativen geben zusätzliche Funktionalität."
Nein, es würde nicht. einfügen eines
n
nicht magisch erhöhen die Sicherheit, in diesem Fall in der Tat, würde der code mehr gefährlich. Ähnlich ist es mitstrncpy
eine schrecklich unsichere Funktion. Der Beitrag, den Sie verlinkt ist schlecht beraten.Dieser taugt nicht für eine leere Zeichenfolge (
""
). Auchstrlen()
zurücksize_t
nichtint
.dies ist zu unsicher für eine leere Zeichenfolge ist, schreibt er auf der index -1. Verwenden Sie nicht dieses.
InformationsquelleAutor Amitabha
Für single '\n' trmming,
für mehrere '\n' trimmen,
if
wenn Sie können, schreiben Sie einfach eine Bedingung mit&&
? Dasswhile
loop hat eine seltsame Struktur; es könnte einfach seinwhile (length > 0 && string[length-1] == '\n') { --length; string[length] = '\0'; }
.danke für die Anregung. Aktualisieren Sie den code.
Ich würde vorschlagen, dass die erste Funktion ist natürlich mehr definiert als:
size_t length = strlen(string); if (length > 0 && string[length-1] == '\n') { string[length-1] = '\0'; }
. Auch dies spiegelt die zweite definition besser (nur mitif
stattwhile
).danke. Es macht Sinn. Ich aktualisierte den code.
InformationsquelleAutor Naveen Kumar
Tim Čas ein liner ist erstaunlich für strings, die durch einen Aufruf von fgets, weil Sie wissen, Sie enthalten einen einzelnen Zeilenumbruch am Ende.
Wenn Sie in einem anderen Kontext und behandeln möchten, Streicher, enthält möglicherweise mehr als eine newline, Sie könnten auf der Suche nach strrspn. Es ist nicht POSIX, das heißt, Sie werden es nicht finden auf allen UNIX-artigen Systemen. Ich schrieb eine für meine eigenen Bedürfnisse.
Für diejenigen, die ein Perl chomp äquivalent in C, ich denke, das ist es (chomp entfernt nur die trailing newline).
Den strrcspn Funktion:
'\n'
(oder, wenn die Zeichenfolge""
).In Antwort auf Ihren ersten Kommentar, chux, meine Antwort bewahrt. Ich hatte zu werfen, resetlen in
strrcspn
wenn es keine\n
.Warum
goto end;
stattreturn len;
?Ich brauchte, um aus dieser unelegant 2-level-Schleife, habe ich an. Der Schaden war getan. Warum nicht ein goto?
Sie haben zwei Arten von
goto
s in deinem code: ein nutzlosesgoto
können ersetzt werden, mit einemreturn
- Anweisung und eine rückwärtsgoto
als böse. Mitstrchr
unterstützt die Umsetzungstrrspn
undstrrcspn
in eine einfachere Art und Weise: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; }
undsize_t strrcspn(const char *s, const char *reject) { size_t len = strlen(s); while (len > 0 && !strchr(reject, s[len - 1])) { len--; } return len; }
InformationsquelleAutor Philippe A.
Wenn mit
getline
ist eine option Nicht zu vernachlässigen, seine security-Probleme und-wenn Sie möchten, Klammer - Zeiger- Sie können vermeiden, string-Funktionen, wie diegetline
gibt die Anzahl der Zeichen. So etwas wie untenHinweis: Die [ Sicherheitsprobleme ] mit
getline
sollte nicht vernachlässigt werden.InformationsquelleAutor sjsam
Meine Newbie Weg 😉 Bitte lassen Sie mich wissen, ob das stimmt. Es scheint zu funktionieren für alle meine Fälle:
InformationsquelleAutor Pawel Flajszer
Die Funktion unten ist ein Teil der string-processing-Bibliothek, die ich bin Pflege auf Github. Es entfernt und unerwünschte Zeichen aus einer Zeichenfolge, die genau das, was Sie wollen
Beispiel könnte
Überprüfen Sie die anderen verfügbaren Funktionen, oder sogar zu dem Projekt beitragen 🙂
https://github.com/fnoyanisi/zString
*
im*src++;
und machenbad
,token
undd
const char *
. Auch warum nicht nutzenstrchr
stattzChrSearch
?*src
nicht'\0'
in IhremzStrrmv
Funktion.Danke @chqrlie! aktualisiert den code entsprechend deinen Anregungen..... zstring begann als ein Spaß-Projekt mit dem Ziel der Schaffung einer string-manipulation-Bibliothek ohne Verwendung von standard-Bibliotheks-Funktionen, damit ich nicht verwenden
strchr
Schreiben Sie "string-manipulation-Bibliothek ohne Verwendung von standard-Bibliotheks-Funktionen" ist eine nette übung, aber warum erzählen Sie anderen Menschen, es zu benutzen? Wenn irgendetwas, es wird langsamer und weniger getestet als jeder standard-Bibliothek.
Dies ist zu tun, einen anderen job aus, was die Frage fragt nach. Es kann wahrscheinlich verwendet werden, um loszuwerden, die nur newline, aber es fühlt sich an wie overkill.
InformationsquelleAutor fnisi
Sollten Sie es versuchen. Dieser code grundsätzlich in einer Schleife durch den string, bis er Sie findet '\n'. Wenn es gefunden wird das '\n' ersetzt wird durch den null-terminator '\0'
Beachten Sie, dass Sie sind Vergleich-Zeichen und keine strings in dieser Linie, dann gibt es keine Notwendigkeit zu verwenden strcmp():
da werden Sie mit single-quotes und nicht doppelte Anführungszeichen. Hier einen link zu single vs. double quotes wenn Sie mehr wissen wollen
In der Regel ist es besser, zu erklären, eine Lösung, anstatt nur Entsendung einige Zeilen des anonymen code. Lesen Sie Wie Schreibe ich eine gute Antwort und auch Erklären völlig code-basierte Antworten.
Tut mir Leid, dies war mein Erster Beitrag hier. Ich werde es beheben. Vielen Dank für das feedback
Ineffizient:
for(int i = 0; i < strlen(Name); i++ )
rufenstrlen(Name)
viele Male (loop-änderungenName[]
) so mit einer LängeN
dies ist einO(N*N)
Lösung. Nur 1 Aufrufstrlen(Name)
, wenn überhaupt , die benötigt wird, um eine O(N)` Lösung. Unklar, warumint i
stattsize_t i
. Betrachtenfor(size_t i = 0; i < Name[i]; i++ )
Der wichtigste Punkt war, dass
i < Name[i]
keinen Sinn macht.InformationsquelleAutor Matheus Martins Jerônimo
Versuchen, diese:
len = strlen(str)
Mai overflow:strlen
zurücksize_t
, nichtint
. Was ist mit dem seltsamenif (len>0) if (...)
Bedingungen? Weißt du nicht über&&
? Wenn du gehst, zu entfernen mehrere nachfolgende Instanzen von CR/LF, warum beschränken Sie sich auf 5? Warum nicht entfernen Sie alle von Ihnen? Warum funktioniert die Funktion haben, eineint
zurück geben, wenn es immer wieder0
? Warum nicht einfach zurückvoid
?InformationsquelleAutor Balazs Kiss