'\ 0' und printf () in C.

21

In einem Einführungskurs in C habe ich gelernt, dass beim Speichern die Zeichenfolgen \0am Ende mit Nullzeichen gespeichert werden . Aber was ist, wenn ich eine Zeichenfolge drucken wollte? Sagen Sie, printf("hello")obwohl ich festgestellt habe, dass dies nicht mit \0der folgenden Anweisung endet

printf("%d", printf("hello"));

Output: 5

Dies scheint jedoch inkonsistent zu sein, da ich weiß, dass Variablen wie Zeichenfolgen im Hauptspeicher gespeichert werden und ich denke, dass beim Drucken etwas möglicherweise auch im Hauptspeicher gespeichert wird. Warum dann der Unterschied?

Ajay Mishra
quelle
1
);Was wollen Sie mit diesem Code zeigen, abgesehen davon , dass Ihr Code zumindest fehlt ? Wie haben Sie bewiesen, dass es nicht mit einem endet \0?
glglgl
Und was hat der darin gespeicherte Speicher damit zu tun?
Tsakiroglou Fotis
In C alle Zeichenketten sind wirklich Arrays von Zeichen, die umfassen die Null-Terminator.
Ein Programmierer
@glglgl Ich denke, printf () gibt die Anzahl der Zeichen zurück, die auf dem Bildschirm gedruckt werden sollen.
Ajay Mishra
4
@ AjayMishra Ja, und es sollte tatsächlich 5 Zeichen gedruckt haben. Das abschließende 0-Byte wird nicht auf dem Bildschirm gedruckt.
glglgl

Antworten:

13

Das Null-Byte markiert das Ende einer Zeichenfolge. Es wird nicht in der Länge der Zeichenfolge gezählt und nicht gedruckt, wenn eine Zeichenfolge mit gedruckt wird printf. Grundsätzlich teilt das Null-Byte Funktionen mit, die die Zeichenfolgenmanipulation ausführen, wann sie gestoppt werden sollen.

Ein Unterschied besteht darin, dass Sie ein charArray erstellen, das mit einer Zeichenfolge initialisiert wurde. Die Verwendung des sizeofOperators spiegelt die Größe des Arrays einschließlich des Nullbytes wider. Zum Beispiel:

char str[] = "hello";
printf("len=%zu\n", strlen(str));     // prints 5
printf("size=%zu\n", sizeof(str));    // prints 6
dbush
quelle
Ich dachte, die Geschichte wäre anders printf(). TBH Ich habe keine Ahnung, wie das printf()funktioniert.
Ajay Mishra
8

printfGibt die Anzahl der gedruckten Zeichen zurück. '\0'wird nicht gedruckt - es signalisiert nur, dass diese Zeichenfolge keine Zeichen mehr enthält. Es wird auch nicht auf die Saitenlänge angerechnet

int main()
{
    char string[] = "hello";

    printf("szieof(string) = %zu, strlen(string) = %zu\n", sizeof(string), strlen(string));
}

https://godbolt.org/z/wYn33e

sizeof(string) = 6, strlen(string) = 5
P__J__
quelle
6

Ihre Annahme ist falsch. Ihre Zeichenfolge endet in der Tat mit einem \0.

Es enthält 5 Zeichen h, e, l, l, ound die 0 - Zeichen.

Was der "innere" print()Aufruf ausgibt, ist die Anzahl der Zeichen, die gedruckt wurden, und das sind 5.

glglgl
quelle
6

In C sind alle Literalzeichenfolgen wirklich Zeichenarrays, die den Nullterminator enthalten.

Der Nullterminator wird jedoch nicht in der Länge einer Zeichenfolge (Literal oder nicht) gezählt und nicht gedruckt. Drucken stoppt , wenn der Nullabschluss gefunden wird.

Ein Programmierer
quelle
Gibt es eine Möglichkeit, dies zu überprüfen, ohne die Zeichenfolge in einem Array zu speichern?
Ajay Mishra
1
@AjayMishra Nun , die Zeichenfolge bereits sind in einem Array (wie erwähnt) ... Aber wenn es dann nicht ein Nullabschluss ist printfwürde außerhalb der Grenzen des Strings, und druckt „random“ oder „Müll“ Zeichen und Rückkehr eines Zahl unterscheidet sich von der Länge der Zeichenfolge. Wenn Sie die Länge der Zeichenfolge bereits kennen, können Sie auch überprüfen, ob das Zeichen an diesem Index '\0'funktioniert. Dies funktioniert, ist jedoch technisch undefiniert, wenn die Größe des Arrays den Terminator nicht enthält (wie in char arr[5] = "hello";, wodurch das nicht hinzugefügt wird Terminator zum Array).
Ein Programmierer
@AjayMishra Ja, z. B. können Sie char * p = "Hello"; int i = 0; while (p[i] != '\0') { printf("%d: %c", i, p[i]); i++; }sehen, wie es ausgeführt wird: Es werden Zeilen mit Indizes und der Inhalt dieser Zeile angezeigt . Nach Index 4 findet es das Zeichen 0 und unterbricht die while-Schleife. Dort sehen Sie, dass es ein 0-Zeichen gibt.
glglgl
6

Alle Antworten sind wirklich gut, aber ich möchte ein weiteres Beispiel hinzufügen, um all diese zu vervollständigen

#include <stdio.h>

int main()
{
    char a_char_array[12] = "Hello world";

    printf("%s", a_char_array);
    printf("\n");

    a_char_array[4] = 0; //0 is ASCII for null terminator

    printf("%s", a_char_array);
    printf("\n");

    return 0;
}

Für diejenigen, die dies nicht auf Online-GDB ausprobieren möchten, lautet die Ausgabe:

Hallo Welt

Hölle

https://linux.die.net/man/3/printf

Ist dies hilfreich, um zu verstehen, was Escape Terminator tut? Es ist keine Grenze für ein char-Array oder eine Zeichenfolge. Es ist der Charakter, der dem Kerl sagt, der -STOP analysiert, (Druck-) Analyse bis hierher.

PS: Und wenn Sie es als Zeichenarray analysieren und drucken

for(i=0; i<12; i++)
{
    printf("%c", a_char_array[i]);
}
printf("\n");

du erhältst:

Höllenwelt

Dabei ist das Leerzeichen nach double l der Null-Terminator. Wenn Sie jedoch ein char-Array analysieren, wird nur der char-Wert jedes Bytes angezeigt. Wenn Sie eine weitere Analyse durchführen und den int-Wert jedes Bytes ("% d%, char_array [i]) drucken, sehen Sie, dass das Leerzeichen (Sie erhalten die ASCII-Code-int-Darstellung) den Wert 0 hat.

Tsakiroglou Fotis
quelle
4

In Cfunction printf()gibt die Anzahl der gedruckten Zeichen zurück, \0ist ein nullTerminator, der verwendet wird, um das Ende der Zeichenfolge in der Sprache c anzugeben, und es gibt keinen eingebauten stringTyp ab c++, jedoch muss Ihre Array-Größe mindestens größer sein als die chargewünschte Anzahl lagern.

Hier ist die ref: cpp ref printf ()

einige Benutzer
quelle
3

Aber was ist, wenn ich einen String drucken wollte, sagen Sie printf ("Hallo"), obwohl ich festgestellt habe, dass er nicht mit \ 0 endet, indem ich der folgenden Anweisung folge

printf("%d", printf("hello"));

Output: 5

Sie liegen falsch. Diese Anweisung bestätigt nicht, dass das Zeichenfolgenliteral "hello"nicht mit dem abschließenden Nullzeichen endet '\0'. Diese Anweisung bestätigte, dass die Funktion printfElemente einer Zeichenfolge ausgibt, bis das abschließende Nullzeichen gefunden wird.

Wenn Sie ein Zeichenfolgenliteral wie in der obigen Anweisung verwenden, erstellt der Compiler ein Zeichenarray mit der statischen Speicherdauer, das Elemente des Zeichenfolgenliteral enthält.

Also in der Tat dieser Ausdruck

printf("hello")

wird vom Compiler wie folgt verarbeitet

static char string_literal_hello[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
printf( string_literal_hello );

Die Aktion der Funktion printf in diesem können Sie sich folgendermaßen vorstellen

int printf( const char *string_literal )
{
    int result = 0;

    for ( ; *string_literal != '\0'; ++string_literal )
    {    
        putchar( *string_literal );
        ++result;
    }

    return result;
}

Um die Anzahl der im String-Literal "Hallo" gespeicherten Zeichen zu ermitteln, können Sie das folgende Programm ausführen

#include <stdio.h>

int main(void) 
{
    char literal[] = "hello";

    printf( "The size of the literal \"%s\" is %zu\n", literal, sizeof( literal ) );

    return 0;
}

Die Programmausgabe ist

The size of the literal "hello" is 6
Vlad aus Moskau
quelle
0

Sie müssen zuerst Ihr Konzept löschen. Da es gelöscht wird, wenn Sie sich mit dem Array befassen, zählt der von Ihnen verwendete Druckbefehl nur die Zeichen, die in der Klammer stehen. Es ist in der Array-Zeichenfolge erforderlich, dass es mit \ 0 endet

Muhammad Kashif
quelle
0

Eine Zeichenfolge ist ein Vektor von Zeichen. Enthält die Zeichenfolge, aus der die Zeichenfolge besteht, gefolgt von der speziellen Endzeichenfolge: '\ 0'

Beispiel: char str [10] = {'H', 'e', ​​'l', 'l', 'o', '\ 0'};

Beispiel: Der folgende Zeichenvektor ist keine Zeichenfolge, da er nicht mit '\ 0' endet.

char str [2] = {'h', 'e'};

Nicola Brogelli
quelle
Es gibt keine Vektoren in C, denke ich.
Ajay Mishra