2016-04-16 12 views
0

Es sieht aus wie scanf() liest die vorherige '\ n'. Ich versuche, meine verkettete Zeichenfolge in einer Zeile zu erhalten. Wie beseitige ich das '\ n' am Anfang meiner zweiten Saite?Stripping Newline ist sehr schwierig

Dies ist ein c-Programm.

Ich vermute, ich muss den Puffer irgendwie vor der nächsten Zeile gelesen werden. Aber ich weiß nicht, wie dies ohne einen Fehler zu tun.

Btw, ich kann hier nicht cin.get() oder andere Standard Cin/Cout Operationen verwenden. Ich kann auch keine Standard-String-Operationen verwenden, weil ich ausschließlich mit c-Strings und strings.h arbeite, nicht mit Strings.

Eingabe von stdin ist:

12 4.0 Spot run!

int main() { 
    int i = 4; 
    double d = 4.0; 
    char s[] = "See "; 

    int isum; 
    int MAX_SIZE = 256; 
    double dsum; 
    char s2[MAX_SIZE]; 

    scanf("%i",&isum); 
    scanf("%lf",&dsum); // Hope to clear out the newline from reading 
         // in the double value. Or any other newline 
         // before the next scarf(), but haven't figured 
         // how. 
    scanf("%79c", s2); 

    isum += i; 
    printf("%d \n",isum); 

    dsum += d; 
    printf("%.1f \n",dsum); 

    char newchar[MAX_SIZE]; 
    strcpy(newchar,s); 
    newchar[strcspn(newchar,"\n")]='\0'; 
    s2[strcspn(s2,"\n")] = 't'; //To test where newline is in second string. 
    strcat(newchar,s2); 
    printf("%s",newchar); 

    return 0; 

Meine Ausgabe ist:

16 8.0 See tSpot run! // < --Anmerkung das 't' vor Spot !!!

+1

Sind Sie sicher, dass Sie C++ lernen? Das sieht wie ein C-Programm aus. –

+0

Sie haben Recht, ich werde das richtige machen. Ich habe C++ von einem Haufen alter C-Programmierer gelernt, die immer noch C-Style-Gewohnheiten verwenden, also habe ich das nicht sofort verstanden. Ich werde das Tag korrigieren. – NonCreature0714

+0

"* Es sieht aus wie scanf() liest die vorherige '\ n'. *" Hast du das überrascht? Wenn ja, was denkst du würde es lesen? –

Antwort

2

Wie angefordert.

Es gibt eine Menge von Fragen über das Verhalten von scanf() und seine Verwandten, die einige der subtilsten und komplexe Funktionen in der Standard-C-Bibliothek sind. Konvertierungsspezifikationen wie %lf hören auf zu lesen, wenn das nächste Zeichen nicht Teil einer Zahl ist. Dieses Zeichen bleibt bei der nächsten Konvertierungsspezifikation. Beachten Sie, dass %c (zusammen mit %[…] Scan-Sets und %n) führenden Leerraum nicht überspringt; Alle anderen Konvertierungsspezifikationen überspringen führenden Leerraum. Wenn der Zeilenumbruch nicht durch die numerische Eingabe verlassen werden soll, verwenden Sie " %79c", um Leerstellen zu überspringen. Das Leerzeichen in der Formatzeichenfolge überspringt keine oder mehrere Leerzeichen, einschließlich Leerzeichen, Tabulatoren und Zeilenumbrüche.

Wie es aussieht, liest die "%79c" die Newline aus nach dem 4.0, und die Charaktere in ‚Spot run!‘ mit einem Newline, nachdem er und stoppt das Lesen unter der Annahme, dass die Eingabe dann EOF erreicht.

Sie sollten keine neue Zeile nach See erhalten. Die t, die von s2[strcspn(s2,"\n")] = 't'; geschrieben wird, überschreibt das erste Byte von s2, das der Zeilenende nach 4.0 war.

Wussten Sie, dass die Linie erkennen:

newchar[strcspn(newchar, "\n")] = '\0'; 

überschreibt die Null-Byte nach dem Raum nach See mit einem Null-Byte, das ein No-op ist.

Eine Technik, die ich häufig verwende, ist das Eingabedatum in einem geeigneten Satz von Klammern, manchmal <<…>> und manchmal […], je nach Laune oder wahrscheinlichen Inhalt.Zum Beispiel:

#include <stdio.h> 
#include <string.h> 

int main(void) 
{ 
    int i = 4; 
    double d = 4.0; 
    char s[] = "See "; 

    int isum; 
    int MAX_SIZE = 256; 
    double dsum; 
    char s2[MAX_SIZE] = ""; // See comments. 

    scanf("%i", &isum); 
    scanf("%lf", &dsum); 
    scanf("%79c", s2); 

    printf("s2 = [%s]\n", s2); 

    isum += i; 
    printf("%d\n", isum); 

    dsum += d; 
    printf("%.1f\n", dsum); 

    char newchar[MAX_SIZE]; 
    strcpy(newchar, s); 
    newchar[strcspn(newchar, "\n")]='\0'; 
    s2[strcspn(s2, "\n")] = 't'; 
    strcat(newchar, s2); 
    printf("%s", newchar); 

    return 0; 
} 

Wie Cool Guy in seiner comment wies darauf hin, ist es wichtig, sich daran zu erinnern, dass %c nicht ein Null-Byte hinzufügt (es braucht nur ein einzelnes Zeichen von Speicher); In ähnlicher Weise fügt %79c dem Ende kein Null-Byte hinzu. Daher ist die Initialisierung von s2 auf 'alle Bytes Null' erforderlich, um ein undefiniertes Verhalten zu verhindern, wenn es mit newchar verkettet wird. Oder Sie müssen aufwendige Techniken mit %n (möglicherweise zweimal verwendet) verwenden, um herauszufinden, wie viele Bytes in s2 eingelesen wurden, so dass Sie null nach dem Ereignis beenden können.

Die Ausgabe von dieser Variante ist:

s2 = [ 
Spot run! 
] 
16 
8.0 
See tSpot run! 

So zu Beginn ein Newline es gibt und am Ende der s2 nach der Eingabe.

+1

Ist nicht 'printf (" s2 = [% s] \ n ", s2);' UB seit 's2' ist nicht NUL-terminiert? –

+0

@CoolGuy: 's2' ist null-terminiert, es sei denn'% 79c' ist nicht null-terminiert. Ich benutze '% c' selten mit einer Zählung, also würde ich das Handbuch anschauen. _ [... die Zeit vergeht ...] _ POSIX sagt, zum Teil: _Nein Nullbyte ist hinzugefügt._ So hast du recht. Ich hatte einige Kommentare darüber, dass ich nicht null-terminiert wurde, aber es lag auf dem falschen Grund, also entfernte ich es - ohne zu merken, dass "% 79c" auch nicht null sein würde. Der Fix ist einfach genug: 'char s2 [MAX_SIZE] =" ";' um das Array auf alle Nullbytes zu initialisieren. Ich habe den Code geändert - danke. –