Question

Voir aussi C Tokenizer


Voici un rapide substr () C que j'ai écrit (oui, les initialisations variables doit être déplacé au début de la fonction etc, mais vous voyez l'idée)

Je l'ai vu de nombreuses implémentations « intelligentes » de substr () qui sont simples appelle une doublure strncpy ()

Ils sont tous mauvais (strncpy ne garantit pas la résiliation nulle et donc l'appel peut ne pas produire une sous-chaîne correcte!)

Voici quelque chose peut-être mieux?

Apportez les bugs!

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;
}
  

Sortie:

[*]'' (")
[*]'-2' (-2)
[*]'--' (--)
[*]'10' (10)
[*]'10-11-' (10-11-)
[*]'' (")
[*]'' (")
Était-ce utile?

La solution

Je dirais que le retour si l'entrée NULL n'est pas valide plutôt qu'une chaîne vide ed malloc(). De cette façon, vous pouvez vérifier si oui ou non la fonction a échoué ou non plutôt que if(p) if(*p == 0).

En outre, je pense que votre fonction fuites de mémoire parce que est emptyString d dans une free() conditionnelle. Vous devez vous assurer inconditionnellement return, à savoir juste avant le strncpy().

Quant à votre commentaire sur NUL non-calloc() mettre fin à la chaîne (ce qui est vrai), si vous utilisez d'affecter la sizeof(char) chaîne plutôt que sizeof(int), ce ne sera pas un problème si vous d'en créer une octet plus que vous copiez, depuis définit automatiquement toutes int valeurs (y compris, dans ce cas, la fin) à 0.

Je vous donne plus de notes mais je déteste la lecture code camelCase. Non pas qu'il n'y a rien de mal avec elle.

EDIT: En ce qui concerne vos mises à jour:

Sachez que la norme C définit pour être "" 1 quel que soit votre système. Si vous utilisez un ordinateur qui utilise 9 bits dans un octet (à Dieu ne plaise), va strcmp() être encore 1. qu'il n'y a rien de mal à dire memcpy() - il montre clairement votre intention et fournit la symétrie des appels à ou strncat() pour d'autres types strcat(). Mais est réellement utile strcpy() (s peuvent être text + nStartingPos différentes tailles sur 16- et 32- et ces ordinateurs 64 bits dernier cri). Plus vous en savez.

Je voudrais également réitérer que la compatibilité avec la plupart des autres code C est de revenir sur une erreur nStartingPos + text plutôt que char *. Je sais que de nombreuses fonctions (comme +) vont probablement faire de mauvaises choses si vous les passez NULL - c'est à prévoir. Mais la bibliothèque standard C (et beaucoup d'autres API C) prennent l'approche « Il est de la responsabilité de l'appelant pour vérifier ,, et non la responsabilité de la fonction à l'enfant lui / elle si (s) il ne fonctionne pas. » Si vous voulez le faire dans l'autre sens, c'est cool, mais il va contre l'une des plus fortes tendances dans la conception de l'interface C.

En outre, je voudrais utiliser <=> (ou <=>) plutôt que <=>. L'utilisation <=> (et <=>) obscurcit votre intention - ce qui fait de quelqu'un regardant votre code pensez que vous voulez ajouter à la fin de la chaîne (que vous faites, car après <=>, la fin est le début), quand ce que vous voulez faire est de définir la chaîne. Lui donne une apparence <=> comme vous ajoutez à une chaîne, tandis que <=> (ou une autre routine de copie) ferait ressembler davantage à ce que votre intention. Les trois lignes suivantes font tous la même chose dans ce contexte - choix selon celui que vous pensez semble plus belle:

strncat(returnString, text + nStartingPos, nRun);

strncpy(returnString, text + nStartingPos, nRun);

memcpy(returnString, text + nStartingPos, nRun);

De plus, et <=> sera probablement <=> un (petit petit) peu plus rapide / plus efficace que <=>.

<=> est le même que <=> - je mettrais la première <=>, comme je pense que c'est plus clair, mais quel que soit l'ordre que vous voulez les mettre en est à vous. En outre, les parenthèses autour d'eux ne sont pas nécessaires (mais agréable), car a une priorité supérieure <=> à <=>.

EDIT 2: Les trois lignes de code ne font pas la même chose, mais dans ce contexte, ils vont tous le même résultat. Merci de me rattraper sur ce point.

Autres conseils

Votre fonction semble très compliqué pour ce qui devrait être une opération simple. Certains problèmes sont (pas tous ces éléments sont des bugs):

  • strdup(), et d'autres fonctions allocation de mémoire, peut échec, vous devez tenir compte de tous les problèmes possibles.
  • allouer seulement des ressources (mémoire dans ce cas) si et quand vous en avez besoin.
  • vous devriez être en mesure de faire la distinction entre les erreurs et les piqûres valides. À l'heure actuelle, on ne sait pas si l'échec de malloc() ou un travail substr ("xxx",1,1) produit une chaîne substr ("xxx",1,0) vide.
  • vous ne avez pas besoin de mémoire que vous calloc() allez remplacer de toute façon.
  • tous les paramètres non valides doivent soit provoquer une erreur ou être sous la contrainte à un paramètre valide (et votre API devrait documenter ce qui).
  • vous n'avez pas besoin de régler la emptyString locale à NULL après avoir libéré il -. Il sera perdu le retour de la fonction
  • vous n'avez pas besoin usr strncat() - vous devrait connaître les dimensions et la mémoire disponible avant de faire une copie afin que vous puissiez utiliser le (le plus probable) plus rapidement memcpy().
  • vous êtes utilisation de la base-1 plutôt que la base-0 pour les compensations de chaîne va à l'encontre du grain de C.

Le segment suivant est ce que je ferais (je préfère comme l'idiome Python de valeurs négatives à compter de la fin de la chaîne, mais je l'ai gardé la longueur plutôt que la position finale).

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? */

Vous devez vérifier null. Rappelez-vous qu'il doit encore attribuer 1 octet pour le caractère nul.

strdup peut échouer (même si il est très peu probable et pas la peine de vérifier pour, à mon humble avis). Elle a cependant un autre problème - il n'est pas une fonction standard C. Il serait préférable d'utiliser malloc.

Vous pouvez également utiliser la fonction memmove pour retourner une sous-chaîne du début à la longueur. L'amélioration / l'ajout d'une autre solution de la solution de paxdiablo:

    #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
    */

it helps. Testé sur Windows 7 Édition Familiale Premium avec TCC C compilier.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top