2009-09-02 10 views
0

J'essaie de transmettre une chaîne à chdir(). Mais j'ai toujours l'impression que certains éléments traînants font chdir() échouer.analyse de chaîne en C

#define IN_LEN 128 

int main(int argc, char** argv) { 

    int counter; 
    char command[IN_LEN]; 
    char** tokens = (char**) malloc(sizeof(char)*IN_LEN); 
    size_t path_len; char path[IN_LEN]; 

     ... 

    fgets(command, IN_LEN, stdin) 
    counter = 0; 
    tmp = strtok(command, delim); 
    while(tmp != NULL) { 
     *(tokens+counter) = tmp; 
     tmp = strtok(NULL, delim); 
     counter++; 
    } 

    if(strncmp(*tokens, cd_command, strlen(cd_command)) == 0) { 
     path_len = strlen(*(tokens+1)); 
     strncpy(path, *(tokens+1), path_len-1); 
    // this is where I try to remove the trailing junk... 
    // but it doesn't work on a second system 
     if(chdir(path) < 0) { 
      error_string = strerror(errno); 
      fprintf(stderr, "path: %s\n%s\n", path, error_string); 
} 

// just to check if the chdir worked 
char buffer[1000]; 
    printf("%s\n", getcwd(buffer, 1000)); 

    } 

    return 0; 
} 

Il doit y avoir une meilleure façon de procéder. Quelqu'un peut-il aider? J'ai essayé d'utiliser scanf mais quand le programme appelle scanf, il se bloque.

Merci

Répondre

5

Il semble que vous avez oublié d'ajouter un null « \ 0 » à chaîne de chemin après avoir appelé strncpy(). Sans le terminateur nul, chdir() ne sait pas où la chaîne se termine et continue à chercher jusqu'à ce qu'elle en trouve un. Cela donnerait l'impression qu'il y a des caractères supplémentaires à la fin de votre chemin.

+0

ah oui. Quelle erreur stupide. Merci beaucoup aussi. Je devenais très frustré. – devin

+0

Si j'avais un nickel pour chaque fois que j'ai fait une erreur de programmation stupide ... –

3

Vous avez (au moins) 2 problèmes dans votre exemple.

Le premier (qui cause les problèmes immédiatement évidents) est l'utilisation de strncpy() qui ne place pas nécessairement un terminateur '\ 0' à la fin du tampon dans lequel il se copie. Dans votre cas, il n'est pas nécessaire d'utiliser strncpy() (que je considère comme dangereux pour la raison pour laquelle vous vous êtes heurté). Vos jetons seront '\ 0' terminés par strtok(), et ils sont garantis être plus petits que le tampon de chemin (puisque les jetons proviennent d'un tampon de la même taille que le tampon de chemin). Il suffit d'utiliser strcpy(), ou si vous voulez que le code soit résilient de quelqu'un qui viendra plus tard et que vous utilisiez les tailles de tampon, utilisez quelque chose comme le non-standard strlcpy().

En règle générale, n'utilisez pas strncpy().

Un autre problème avec votre code est que l'allocation tokens n'est pas correcte.

char** tokens = (char**) malloc(sizeof(char)*IN_LEN); 

allouera une zone aussi grande que votre tampon de chaîne d'entrée, mais vous stockez des pointeurs vers des chaînes dans cette allocation, et non les caractères. Vous aurez moins de jetons que de caractères (par définition), mais chaque pointeur est probablement 4 fois plus grand qu'un caractère (en fonction de la taille du pointeur de la plateforme). Si votre chaîne contient suffisamment de jetons, vous surchargez ce buffer. Par exemple, supposons que IN_LEN est 14 et la chaîne d'entrée est "a b c d e f g". Si vous utilisez des espaces comme délimiteur, il y aura 7 jetons, ce qui nécessitera un tableau de pointeurs de 28 octets. Un peu plus que les 14 alloués par l'appel malloc().

Un simple changement à:

char** tokens = (char**) malloc((sizeof(char*) * IN_LEN)/2); 

devrait allouer suffisamment d'espace (? Est là une erreur hors par un là-bas peut-être un +1 est nécessaire).

Un troisième problème est que vous accédez potentiellement *tokens et *(tokens+1) même si zéro ou un seul jeton a été ajouté à la baie. Vous devrez ajouter quelques vérifications de la variable counter avant de déréférencer ces pointeurs.