Frage

Siehe auch C Tokenizer


Hier ist ein kurzer substr () für C, die ich geschrieben habe (ja, muss die Variable Initialisierungen bewegt werden von der Funktion etc zu starten, aber Sie erhalten die Idee)

Ich habe viele „intelligente“ Implementierungen von substr () zu sehen, die einfach Motto ruft strncpy ()

Sie sind alle falsch sind (strncpy nicht null Beendigung garantieren und somit könnte der Anruf nicht einen korrekten String erzeugen!)

Hier ist etwas vielleicht besser?

die Wanzen Bringen Sie!

char* substr(const char* text, int nStartingPos, int nRun)
{
    char* emptyString = strdup(""); /* C'mon! This cannot fail */

    if(text == NULL) return emptyString;

    int textLen = strlen(text);

    --nStartingPos;

    if((nStartingPos < 0) || (nRun <= 0) || (textLen == 0) || (textLen < nStartingPos)) return emptyString;

    char* returnString = (char *)calloc((1 + nRun), sizeof(char));

    if(returnString == NULL) return emptyString;

    strncat(returnString, (nStartingPos + text), nRun);

    /* We do not need emptyString anymore from this point onwards */

    free(emptyString);
    emptyString = NULL;

    return returnString;
}


int main()
{
    const char *text = "-2--4--6-7-8-9-10-11-";

    char *p = substr(text, -1, 2);
    printf("[*]'%s' (\")\n",  ((p == NULL) ? "<NULL>" : p));
    free(p);

    p = substr(text, 1, 2);
    printf("[*]'%s' (-2)\n", ((p == NULL) ? "<NULL>" : p));
    free(p);

    p = substr(text, 3, 2);
    printf("[*]'%s' (--)\n", ((p == NULL) ? "<NULL>" : p));
    free(p);

    p = substr(text, 16, 2);
    printf("[*]'%s' (10)\n", ((p == NULL) ? "<NULL>" : p));
    free(p);

    p = substr(text, 16, 20);
    printf("[*]'%s' (10-11-)\n", ((p == NULL) ? "<NULL>" : p));
    free(p);

    p = substr(text, 100, 2);
    printf("[*]'%s' (\")\n", ((p == NULL) ? "<NULL>" : p));
    free(p);

    p = substr(text, 1, 0);
    printf("[*]'%s' (\")\n", ((p == NULL) ? "<NULL>" : p));
    free(p);

    return 0;
}
  

Ausgabe:

[*]'' (")
[*]'-2' (-2)
[*]'--' (--)
[*]'10' (10)
[*]'10-11-' (10-11-)
[*]'' (")
[*]'' (")
War es hilfreich?

Lösung

Ich würde Rückkehr NULL sagen, wenn die Eingabe nicht gültig ist eher als ein malloc()ed leerer String zurück. Auf diese Weise können Sie testen, ob die Funktion fehlgeschlagen ist oder nicht mit if(p) statt if(*p == 0).

Außerdem glaube ich, Ihre Funktion verliert Speicher, weil emptyString nur in einem bedingten free()d wird. Sie sollten sicherstellen, dass Sie es bedingungslos free(), das heißt unmittelbar vor dem return.

Wie auf deinen Kommentar zu strncpy() nicht NUL-Beendigung der Zeichenfolge (was wahr ist), wenn Sie calloc() verwenden, um die Zeichenfolge zuzuweisen, anstatt malloc(), wird dies kein Problem sein, wenn Sie ein Byte mehr zuweisen, als Sie kopieren, da calloc() automatisch alle Werte setzt (einschließlich, in diesem Fall das Ende) auf 0.

Ich würde Ihnen mehr Noten geben, aber ich hasse Camelcase-Code zu lesen. Nicht, dass es etwas falsch mit ihm.

EDIT: Mit Bezug auf Ihre Updates:

Beachten Sie, dass der C-Standard definiert sizeof(char) 1 zu sein, unabhängig von Ihrem System. Wenn Sie einen Computer verwenden, die 9 Bits in einem Byte verwendet (Gott bewahre), sizeof(char) noch 1. Darf nicht sein wird, dass es zu sagen sizeof(char) etwas falsch ist - es zeigt deutlich, Ihre Absicht und bietet Symmetrie mit Aufrufen an calloc() oder malloc() für andere Arten. Aber sizeof(int) ist wirklich nützlich (ints können unterschiedliche Größen auf 16- und 32- und diese neumodischen 64-Bit-Computer). Je mehr Sie wissen.

Ich würde auch mit den meisten anderen C-Code, der die Konsistenz wiederholen, ist NULL auf einen Fehler zurück, anstatt "". Ich kenne viele Funktionen (wie strcmp()) wird wahrscheinlich schlechte Dinge tun, wenn Sie sie NULL übergeben - dies zu erwarten ist. Aber die C-Standardbibliothek (und viele andere C APIs) nehmen den Ansatz „Es ist die Verantwortung des Anrufers für NULL zu überprüfen, nicht in der Verantwortung der Funktion Baby ihn / sie, wenn er (sie) nicht der Fall.“ Wenn Sie es anders machen wollen, das ist cool, aber es wird gegen eine der stärkeren Trends in der C-Interface-Design.

Außerdem würde ich strncpy() (oder memcpy()) statt strncat() verwenden. Mit strncat() (und strcat()) verschleiert Ihre Absicht - es jemand macht auf den Code suchen denken Sie an das Ende der Zeichenfolge hinzugefügt werden soll (was Sie tun, denn nach calloc(), das Ende ist der Anfang ist), wenn das, was Sie tun möchten, festgelegt wird, um die Zeichenfolge. strncat() macht es so aussehen wie Sie in eine Zeichenfolge sind hinzufügen, während strcpy() (oder eine andere Kopierroutine) wäre es aussehen wie das, was Ihre Absicht ist. Die folgenden drei Zeilen haben alle die gleiche Sache in diesem Zusammenhang - Pick je nachdem, was man denken Sie sieht netteste:

strncat(returnString, text + nStartingPos, nRun);

strncpy(returnString, text + nStartingPos, nRun);

memcpy(returnString, text + nStartingPos, nRun);

Plus, strncpy() und memcpy() wahrscheinlich ein (wee wenig) sein etwas schneller / effizienter als strncat().

text + nStartingPos ist die gleiche wie nStartingPos + text - ich char * die erste Stelle setzen würde, wie ich denke, das ist klarer, aber was auch immer bestellen wollen, um sie setzen in bis zu Ihnen ist. Auch sind die Klammern um sie überflüssig (aber schön), da + höhere Priorität als , hat.

EDIT 2: Die drei Zeilen Code nicht die gleiche Sache nicht, aber in diesem Zusammenhang werden sie alle zum gleichen Ergebnis führen. Vielen Dank für mich auf, dass zu kontrollieren.

Andere Tipps

Ihre Funktion scheint sehr kompliziert, was eine einfache Operation sein sollte. Einige Probleme sind (nicht alle von ihnen sind Bugs):

  • strdup() und andere Speicherzuordnungsfunktionen, können fail, sollten Sie für alle möglichen Fragen ermöglichen.
  • nur Zuweisung von Ressourcen (Speicher in diesem Fall), ob und wann Sie sie brauchen.
  • sollten Sie in der Lage sein, zwischen Fehlern und gültigen Stichen zu unterscheiden. Im Moment, Sie wissen nicht, ob malloc() Ausfall substr ("xxx",1,1) oder eine Arbeits substr ("xxx",1,0) eine leere Zeichenfolge erzeugt.
  • Sie brauchen nicht Gedächtnis zu calloc(), die Sie ohnehin zu überschreiben werden.
  • alle ungültigen Parameter sollten entweder einen Fehler verursachen oder zu einem gültigen Parameter umgewandelt werden (und Ihre API sollten dokumentieren, welche).
  • Sie brauchen nicht auf den lokalen Leerstring auf NULL zu setzen, nachdem sie zu befreien -. Es wird auf der Funktion Rückkehr verloren
  • Sie brauchen nicht zu usr strncat() -. Sie sollte kennen die Größen und die Speicher Sie, bevor Sie das Kopieren zu tun zur Verfügung haben, so dass Sie die (wahrscheinlich) schneller memcpy() verwenden können,
  • Sie haben die Verwendung von Basis-1 eher als Basis-0 für String-Offsets gegen den Strich geht von C.

Das folgende Segment ist das, was ich tun würde (ich eher wie der Python Idiom der negativen Werte aus dem Ende des Strings zu zählen, aber ich habe gehalten Länge eher als Endposition).

char *substr (const char *inpStr, int startPos, int strLen) {
    /* Cannot do anything with NULL. */

    if (inpStr == NULL) return NULL;

    /* All negative positions to go from end, and cannot
       start before start of string, force to start. */

    if (startPos < 0)
        startPos = strlen (inpStr) + startPos;
    if (startPos < 0)
        startPos = 0;

    /* Force negative lengths to zero and cannot
       start after end of string, force to end. */

    if (strLen < 0)
        strLen = 0;
    if (startPos >strlen (inpStr))
        startPos = strlen (inpStr);

    /* Adjust length if source string too short. */

    if (strLen > strlen (&inpStr[startPos]))
        strLen = strlen (&inpStr[startPos]);

    /* Get long enough string from heap, return NULL if no go. */

    if ((buff = malloc (strLen + 1)) == NULL)
        return NULL;

    /* Transfer string section and return it. */

    memcpy (buff, &(inpStr[startPos]), strLen);
    buff[strLen] = '\0';

    return buff;
}
char* emptyString = strdup(""); /* C'mon! This cannot fail? */

Sie müssen für null überprüfen. Denken Sie daran, dass es immer noch 1 Byte für die Nullzeichen zuweisen muss.

strdup scheitern könnte (obwohl es sehr unwahrscheinlich, und nicht einen Besuch wert ist für, IMHO). Es macht jedoch ein anderes Problem - es ist nicht eine Standard-C-Funktion ist. Es wäre besser, malloc zu verwenden.

Sie können auch die memmove Funktion verwenden, um eine Teilkette von Anfang bis Länge zurückzukehren. Die Verbesserung / eine andere Lösung aus paxdiablo Lösung fügt hinzu:

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

    char *splitstr(char *idata, int start, int slen) {
            char ret[150];
            if(slen == NULL) {
                    slen=strlen(idata)-start;
            }
            memmove (ret,idata+start,slen);
            return ret;
    }

    /*
    Usage:
            char ostr[]="Hello World!";
            char *ores=splitstr(ostr, 0, 5);
            Outputs:
                    Hello
    */

Hoffe, es hilft. Getestet auf Windows 7 Home Premium mit TCC C Kompilier.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top