Domanda

Si veda anche C Tokenizer


Ecco un breve substr () per la C che ho scritto (sì, le inizializzazioni variabili deve essere spostato per iniziare la funzione, ecc, ma si ottiene l'idea)

Ho visto molte implementazioni "intelligenti" di substr (), che sono semplici uno di linea chiama strncpy ()!

Sono tutto sbagliato (strncpy non garantisce terminazione nullo e quindi la chiamata non potrebbe produrre una corretta stringa!)

Qui è qualcosa forse meglio?

Tirate fuori gli insetti!

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

Output:

[*]'' (")
[*]'-2' (-2)
[*]'--' (--)
[*]'10' (10)
[*]'10-11-' (10-11-)
[*]'' (")
[*]'' (")
È stato utile?

Soluzione

Direi di ritorno NULL se l'ingresso non è valido, piuttosto che una stringa vuota malloc() ed. In questo modo è possibile verificare se la funzione non è riuscita o meno con if(p) piuttosto che if(*p == 0).

Inoltre, penso che la funzione delle perdite di memoria a causa emptyString è solo free() d in una condizionale. È necessario assicurarsi che si return incondizionatamente, vale a dire a destra prima del strncpy().

Per quanto riguarda il tuo commento su calloc() non NUL-chiude la stringa (il che è vero), se si utilizza sizeof(char) per allocare la stringa piuttosto che sizeof(int), questo non sarà un problema se si alloca uno byte più di copiare, in quanto int imposta automaticamente tutti i valori (tra cui, in questo caso, alla fine) a 0.

ti darei più note ma odio la lettura del codice camelCase. Non che ci sia qualcosa di sbagliato con esso.

EDIT: Per quanto riguarda gli aggiornamenti:

Si tenga presente che lo standard C definisce "" di essere 1 a prescindere dal vostro sistema. Se si utilizza un computer che utilizza 9 bit in un byte (Dio non voglia), strcmp() è ancora in corso di essere 1. Non che ci sia qualcosa di sbagliato nel dire memcpy() - mostra chiaramente la vostra intenzione e fornisce la simmetria con le chiamate a strncat() o strcat() per altri tipi. Ma strcpy() è effettivamente utile (text + nStartingPos s possono essere diverse dimensioni su 16 e 32 e queste diavolerie computer a 64 bit). Più si conosce.

Vorrei anche ribadire che la coerenza con la maggior parte del codice C è quello di tornare nStartingPos + text su un errore piuttosto che char *. So che molte funzioni (come +) saranno probabilmente fare cose cattive se si passa loro NULL - questo è da aspettarselo. Ma la libreria standard C (e molte altre API C) adottare l'approccio di "E 'responsabilità del chiamante per verificare la presenza di ,, non la responsabilità della funzione al bambino lui / lei se (s) non lo fa." Se si vuole fare il contrario, che è cool, ma sta andando contro una delle tendenze più forti nella progettazione dell'interfaccia C.

Inoltre, vorrei utilizzare <=> (o <=>) piuttosto che <=>. Utilizzando <=> (e <=>) oscura il vostro intento - fa qualcuno guardando il tuo codice di pensare che si desidera aggiungere alla fine della stringa (che si fa, perché dopo <=>, la fine è l'inizio), quando ciò che si vuole fare è impostare la stringa. <=> lo fa apparire come si sta aggiungendo una stringa, mentre <=> (o un'altra routine copia) avrebbero farlo sembrare più simile a ciò che il vostro intento è. Le seguenti tre righe tutti fanno la stessa cosa in questo contesto - scegliere quello che pensa sembra più bella:

strncat(returnString, text + nStartingPos, nRun);

strncpy(returnString, text + nStartingPos, nRun);

memcpy(returnString, text + nStartingPos, nRun);

Inoltre, <=> e <=> sarà probabilmente un (poco wee) 'più veloce / più efficiente di <=>.

<=> è lo stesso che <=> - Io metterei la <=> prima, come io credo che sia più chiaro, ma qualsiasi ordine che si desidera metterli in dipende da voi. Inoltre, la parentesi intorno a loro sono inutili (ma bella), dal momento che <=> ha precedenza maggiore di <=>.

EDIT 2: Le tre righe di codice non fanno la stessa cosa, ma in questo contesto saranno tutti produrre lo stesso risultato. Grazie per avermi cattura su questo.

Altri suggerimenti

La vostra funzione sembra molto complicato per quello che dovrebbe essere una semplice operazione. Alcuni problemi sono (non tutti questi sono insetti):

  • strdup(), e altre funzioni di allocazione di memoria, possono fallire, si dovrebbe consentire per tutti i possibili problemi.
  • solo allocare le risorse (memoria in questo caso), se e quando ne avete bisogno.
  • si dovrebbe essere in grado di distinguere tra gli errori e le punture validi. Al momento, non si sa se malloc() fallimento di substr ("xxx",1,1) o di un gruppo di lavoro substr ("xxx",1,0) produce una stringa vuota.
  • non è necessario per calloc() memoria che si sta andando a sovrascrivere in ogni caso.
  • tutti i parametri non validi dovrebbero o causare un errore o di essere costretto a un parametro valido (e il vostro API dovrebbero documentare che).
  • non è necessario impostare l'emptyString locale per NULL dopo aver liberato esso -. Si sarà perso al ritorno funzione
  • non è necessario a usr strncat() - dovrebbe conoscere le dimensioni e la memoria che si hanno a disposizione prima di fare qualsiasi copia in modo da poter utilizzare il (molto probabilmente) più veloce memcpy().
  • sei uso di base-1 piuttosto che basare-0 per offset stringa va contro il chicco di C.

Il seguente segmento è quello che farei (ho un po 'come il linguaggio Python di valori negativi a contare dalla fine della stringa, ma ho mantenuto la lunghezza piuttosto che posizione 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? */

È necessario controllare per nulla. Ricordate che comunque deve allocare 1 byte per il carattere nullo.

strdup poteva mancare (anche se è molto improbabile e non la pena di verificare per, IMHO). Essa ha ancora un altro problema però - non è una funzione standard C. Sarebbe meglio usare malloc.

È anche possibile utilizzare la funzione memmove per restituire una sottostringa dall'inizio alla lunghezza. Migliorare / aggiungendo un'altra soluzione dalla soluzione di 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
    */

Speranza che aiuta. Testato su Windows 7 Home Premium con TCC C compilier.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top