strcmp, strstr, ... - NULL safe?



  • Hallo.
    Kann ich davon ausgehen, dass alle Strinfunktionen NULL safe sind?
    Beispiel:

    char *pszBla = NULL;
    // ...
    if (!strcmp(pszBla, "blubb"))
    {
        // ...
    }
    // ...
    if (strstr(pszBla, "blubb"))
    {
        // ...
    }
    

    In der Dokumentation findet man leider nichts darüber ( http://www.cplusplus.com/reference/clibrary/cstring/strcmp/ ).

    Eine weitere Frage habe ich noch: Kann ich auch davon ausgehen, dass folgendes funktioniert?

    char szBla[32] = "prefix_";
    // ...
    strcat(szBla, "iks");
    

    Gruß



  • theliquidwave schrieb:

    Kann ich davon ausgehen, dass alle Strinfunktionen NULL safe sind?

    Nein.

    In der Dokumentation findet man leider nichts darüber ( http://www.cplusplus.com/reference/clibrary/cstring/strcmp/ ).

    Wenn man genau liest, schon. Da steht nämlich drin, dass er die Strings zeichenweise vergleicht. Dazu muss er den übergebenen Zeiger dereferenzieren, und wenn das ein Nullzeiger ist, kracht es.

    Eine weitere Frage habe ich noch: Kann ich auch davon ausgehen, dass folgendes funktioniert?

    char szBla[32] = "prefix_";
    // ...
    strcat(szBla, "iks");
    

    Ja.



  • Shit. Dann werde ich mir wohl ein paar Makros oder Wrapperfunktionen schreiben. Danke!

    Gruß



  • Mir fällt da gerade noch einmal etwas ein...
    Des öfteren sehe ich in Codes so etwas:

    char szBla[32] = { '\0' };
    

    Dazu habe ich ein paar Fragen:
    1. Ich dachte immer, der Compiler ersetzt auch bei char szBla[32]; alle Zeichen mit \0 - stimmt das nicht?
    2. Setzt der Code oben alle Zeichen auf \0 , oder nur das Erste?

    Nach meinem Verständnis geht beides gleichermaßen (oder ist das falsch)?

    char szBla[32] = { '\0' };
    strcat(szBla, "blubb");
    
    // oder
    
    char szBla[32];
    strcat(szBla, "blubb");
    

    Gruß



  • Wenn das Array dateiglobal ist, wird mit 0 initialisiert, ansonsten steht Schrott drin.

    Bei einer Dekaration innerhalb einer Funktion und anschließender Verwendung als Parameter für strcat wäre also eine Initialisierung mit 0 angebracht:

    char szBla[32] = {0}; // Alle Arrayelemente werden mit 0 initialisiert.
    strcat(szBla, "blubb");
    

    Gruß,
    B.B.



  • theliquidwave schrieb:

    1. Ich dachte immer, der Compiler ersetzt auch bei char szBla[32]; alle Zeichen mit \0 - stimmt das nicht?

    Nein, solange du eine Variable nicht initialisierst (ihr einen Wert zuweist), ist ihr Inhalt unbestimmt.

    theliquidwave schrieb:

    2. Setzt der Code oben alle Zeichen auf \0 , oder nur das Erste?

    Nur das Erste.

    theliquidwave schrieb:

    Nach meinem Verständnis geht beides gleichermaßen (oder ist das falsch)?

    char szBla[32] = { '\0' };
    strcat(szBla, "blubb");
    
    // oder
    
    char szBla[32];
    strcat(szBla, "blubb");
    

    Man siehe sich die C++ Reference Page zu strcat an:

    char * strcat ( char * destination, const char * source );

    Concatenate strings
    Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source, and a new null-character is appended at the end of the new string formed by the concatenation of both in destination.

    Fazit: Die erste Methode liefert dir immer das (hoffentlich) erwartete Ergebnis, dass sich in szBla nun der nullterminierte String "blubb" befindet. Bei der zweiten Methode jedoch aehnelt das Ganze eher einem Gluecksspiel, da fuer ein richtiges Ergebnis an erster Stelle eine 0 stehen muss.

    @Big Brother: Das mit der 0-Initialisierung wusste ich noch nicht, danke. 🙂



  • Danke! 🙂

    Gruß



  • Corsair@01 schrieb:

    theliquidwave schrieb:

    1. Ich dachte immer, der Compiler ersetzt auch bei char szBla[32]; alle Zeichen mit \0 - stimmt das nicht?

    Nein, solange du eine Variable nicht initialisierst (ihr einen Wert zuweist), ist ihr Inhalt unbestimmt.

    Stimmt nicht genau. Fields werden immer initialisiert. Lokale Variablen sind unbestimmt, sie besehen aus altem Stackinhalt.

    Gemallocter Bereich ist meistens auch genullt, da aus Sicherheitsgründen Speicher beim Freigeben vom Betriebssystem genullt wird.

    Unter Windows 95 und ähnliche bekommt man aber wahrscheinlich gern mal alten Speicher von anderen Prozessen zu sehen.



  • Unter Windows 95 und ähnliche bekommt man aber wahrscheinlich gern mal alten Speicher von anderen Prozessen zu sehen.

    Wie soll das denn gehen? Ich dachte, jeder Prozess hat sein eigenen Adressraum... Ach scheiße, Win95 hat ja noch keine NT Technologie ^^

    Gruß



  • Corsair@01 schrieb:

    theliquidwave schrieb:

    2. Setzt der Code oben alle Zeichen auf \0 , oder nur das Erste?

    Nur das Erste.

    Nein, wenn eine Initialisierung stattfindet, werden alle nicht explizit initialisierten Elemente mit 0 initialisiert.

    Das macht man sich oft bei Strukturen zunutze:

    struct Bla x = {0};
    


  • Hi,
    habe noch ein paar Fragen...

    1. Dies _müsste_ doch einen Memoryleak auf das erste char-Objekt erzeugen, oder?

    char *pszText = new char[32];
    strcpy(pszText, "blablub");
    // ...
    pszText++; // ist jetzt "lablub"
    delete[] pszText; // sollte doch jetzt nur noch "lablub" löschen, das erste "b" bleibt also bestehen, oder?
    
    // folgendes wäre die Lösung, richtig?
    pszText--;
    delete[] pszText;
    

    2. Gibt es eine komfortable Möglichkeit, das erste Zeichen eines Stackstrings (ich nenne es mal einfach so) "nicht zu beachten"? Folgendes geht natürlich nicht:

    char szText[32] = { '\0' };
    strcpy(szText, "blablub");
    // ...
    szText++; // <-- "error C2105: '++' muss ein L-Wert sein"
    

    Gruß & Danke



    Memoryleak im eigentlichen Sinne ist das nicht, ein Leak wäre, wenn Du den Speicher gar nicht freigibst. Hier gibst Du ja "einen anderen" Speicher an das System zurück. Was da im Einzelfall passiert hängt von allerlei Dingen ab. Auf jeden Fall wird es nicht gut.

    Du solltest bei C übrigens dann doch eher mit malloc/free arbeiten, oder wenn Du C++ nimmst (delete[]) dann verwende doch gleich eine richtige String-Klasse.

    Du kannst z.B. mit &szText[1] arbeiten... dann beginnt Dein String beim 2. Zeichen und das erste wird überlesen.



  • Marc++us schrieb:

    Du solltest bei C übrigens dann doch eher mit malloc/free arbeiten, oder wenn Du C++ nimmst (delete[]) dann verwende doch gleich eine richtige String-Klasse.

    Stimmt schon. Ich arbeite in C++, da die Fragen aber auf C-Strings bezogen waren, habe ich sie hier gestellt.

    Marc++us schrieb:

    Du kannst z.B. mit &szText[1] arbeiten... dann beginnt Dein String beim 2. Zeichen und das erste wird überlesen.

    Gute Idee 😃

    Gruß



  • Du solltest nicht C und C++ mischen, da wird wohl überhaupt nicht definiert sein, was passiert. (Es gibt übrigens keinen einzigen Compiler, der C++ wirklich vollständig implementiert!)

    Wenn du das mit malloc() gemacht hättest, also etwa so:

    char *s = malloc(10);
    strcpy(s, "hallo!");
    
    // dann wäre bei
    s++;
    free(s);
    // überhaupt nichts passiert, weil die Speicherverwaltung s überhaupt nicht kennt
    
    // und bei
    s--;
    free(s);
    // wäre passiert, was passieren soll: Der Speicher freigegeben, der bei malloc() alloziert wurde.
    


  • earli schrieb:

    char *s = malloc(10);
    strcpy(s, "hallo!");
    
    // dann wäre bei
    s++;
    free(s);
    // überhaupt nichts passiert, weil die Speicherverwaltung s überhaupt nicht kennt
    

    Das wäre schön. Aber in dem Fall passiert irgendwas, denn if the argument does not match a pointer earlier returned by the calloc, malloc, or realloc function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined.
    🙂



  • Du solltest auch strncpy anstatt strcpy verwenden.

    Da strcpy keine längen Prüfung hat und so anfällig für Buffer Overflows wird.



  • strncpy schrieb:

    Du solltest auch strncpy anstatt strcpy verwenden.

    Da strcpy keine längen Prüfung hat und so anfällig für Buffer Overflows wird.

    Das ist nur nötig, wenn du nicht weißt, was kommt.

    Wenn du Stringkonstanten in Arrays kopierst, deren Größe du kennst, ist das egal.



  • earli schrieb:

    strncpy schrieb:

    Du solltest auch strncpy anstatt strcpy verwenden.

    Da strcpy keine längen Prüfung hat und so anfällig für Buffer Overflows wird.

    Das ist nur nötig, wenn du nicht weißt, was kommt.

    Wenn du Stringkonstanten in Arrays kopierst, deren Größe du kennst, ist das egal.

    nicht ganz, es sollte ein geschwindigkeits unterschied sein strncpy() zu verwenden...


Anmelden zum Antworten